1 | /* |
2 | * Copyright (C) 2008-2019 Apple Inc. All rights reserved. |
3 | * Copyright (C) 2008 Cameron Zwarich <[email protected]> |
4 | * Copyright (C) 2012 Igalia, S.L. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
16 | * its contributors may be used to endorse or promote products derived |
17 | * from this software without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
22 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
26 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | */ |
30 | |
31 | #pragma once |
32 | |
33 | #include "BytecodeGeneratorBase.h" |
34 | #include "BytecodeStructs.h" |
35 | #include "CodeBlock.h" |
36 | #include "Instruction.h" |
37 | #include "Interpreter.h" |
38 | #include "JSAsyncGenerator.h" |
39 | #include "JSBigInt.h" |
40 | #include "JSGenerator.h" |
41 | #include "JSTemplateObjectDescriptor.h" |
42 | #include "Label.h" |
43 | #include "LabelScope.h" |
44 | #include "Nodes.h" |
45 | #include "ParserError.h" |
46 | #include "ProfileTypeBytecodeFlag.h" |
47 | #include "RegisterID.h" |
48 | #include "StaticPropertyAnalyzer.h" |
49 | #include "SymbolTable.h" |
50 | #include "UnlinkedCodeBlock.h" |
51 | #include <functional> |
52 | #include <wtf/CheckedArithmetic.h> |
53 | #include <wtf/HashFunctions.h> |
54 | #include <wtf/Optional.h> |
55 | #include <wtf/SegmentedVector.h> |
56 | #include <wtf/SetForScope.h> |
57 | #include <wtf/Vector.h> |
58 | |
59 | namespace JSC { |
60 | |
61 | class JSImmutableButterfly; |
62 | class Identifier; |
63 | class IndexedForInContext; |
64 | class StructureForInContext; |
65 | |
66 | enum ExpectedFunction { |
67 | NoExpectedFunction, |
68 | ExpectObjectConstructor, |
69 | ExpectArrayConstructor |
70 | }; |
71 | |
72 | enum class EmitAwait { Yes, No }; |
73 | |
74 | enum class DebuggableCall { Yes, No }; |
75 | enum class ThisResolutionType { Local, Scoped }; |
76 | enum class LinkTimeConstant : int32_t; |
77 | |
78 | class CallArguments { |
79 | public: |
80 | CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0); |
81 | |
82 | RegisterID* thisRegister() { return m_argv[0].get(); } |
83 | RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); } |
84 | unsigned stackOffset() { return -m_argv[0]->index() + CallFrame::headerSizeInRegisters; } |
85 | unsigned argumentCountIncludingThis() { return m_argv.size() - m_padding; } |
86 | ArgumentsNode* argumentsNode() { return m_argumentsNode; } |
87 | |
88 | private: |
89 | ArgumentsNode* m_argumentsNode; |
90 | Vector<RefPtr<RegisterID>, 8, UnsafeVectorOverflow> m_argv; |
91 | unsigned m_padding; |
92 | }; |
93 | |
94 | // https://tc39.github.io/ecma262/#sec-completion-record-specification-type |
95 | // |
96 | // For the Break and Continue cases, instead of using the Break and Continue enum values |
97 | // below, we use the unique jumpID of the break and continue statement as the encoding |
98 | // for the CompletionType value. emitFinallyCompletion() uses this jumpID value later |
99 | // to determine the appropriate jump target to jump to after executing the relevant finally |
100 | // blocks. The jumpID is computed as: |
101 | // jumpID = bytecodeOffset (of the break/continue node) + CompletionType::NumberOfTypes. |
102 | // Hence, there won't be any collision between jumpIDs and CompletionType enums. |
103 | enum class CompletionType : int { |
104 | Normal, |
105 | Throw, |
106 | Return, |
107 | NumberOfTypes |
108 | }; |
109 | |
110 | inline CompletionType bytecodeOffsetToJumpID(unsigned offset) |
111 | { |
112 | int jumpIDAsInt = offset + static_cast<int>(CompletionType::NumberOfTypes); |
113 | ASSERT(jumpIDAsInt >= static_cast<int>(CompletionType::NumberOfTypes)); |
114 | return static_cast<CompletionType>(jumpIDAsInt); |
115 | } |
116 | |
117 | struct FinallyJump { |
118 | FinallyJump(CompletionType jumpID, int targetLexicalScopeIndex, Label& targetLabel) |
119 | : jumpID(jumpID) |
120 | , targetLexicalScopeIndex(targetLexicalScopeIndex) |
121 | , targetLabel(targetLabel) |
122 | { } |
123 | |
124 | CompletionType jumpID; |
125 | int targetLexicalScopeIndex; |
126 | Ref<Label> targetLabel; |
127 | }; |
128 | |
129 | class FinallyContext { |
130 | public: |
131 | FinallyContext() { } |
132 | FinallyContext(BytecodeGenerator&, Label& finallyLabel); |
133 | |
134 | FinallyContext* outerContext() const { return m_outerContext; } |
135 | Label* finallyLabel() const { return m_finallyLabel; } |
136 | |
137 | RegisterID* completionTypeRegister() const { return m_completionRecord.typeRegister.get(); } |
138 | RegisterID* completionValueRegister() const { return m_completionRecord.valueRegister.get(); } |
139 | |
140 | uint32_t numberOfBreaksOrContinues() const { return m_numberOfBreaksOrContinues.unsafeGet(); } |
141 | void incNumberOfBreaksOrContinues() { m_numberOfBreaksOrContinues++; } |
142 | |
143 | bool handlesReturns() const { return m_handlesReturns; } |
144 | void setHandlesReturns() { m_handlesReturns = true; } |
145 | |
146 | void registerJump(CompletionType jumpID, int lexicalScopeIndex, Label& targetLabel) |
147 | { |
148 | m_jumps.append(FinallyJump(jumpID, lexicalScopeIndex, targetLabel)); |
149 | } |
150 | |
151 | size_t numberOfJumps() const { return m_jumps.size(); } |
152 | FinallyJump& jumps(size_t i) { return m_jumps[i]; } |
153 | |
154 | private: |
155 | FinallyContext* m_outerContext { nullptr }; |
156 | Label* m_finallyLabel { nullptr }; |
157 | Checked<uint32_t, WTF::CrashOnOverflow> m_numberOfBreaksOrContinues; |
158 | bool m_handlesReturns { false }; |
159 | Vector<FinallyJump> m_jumps; |
160 | struct { |
161 | RefPtr<RegisterID> typeRegister; |
162 | RefPtr<RegisterID> valueRegister; |
163 | } m_completionRecord; |
164 | }; |
165 | |
166 | struct ControlFlowScope { |
167 | typedef uint8_t Type; |
168 | enum { |
169 | Label, |
170 | Finally |
171 | }; |
172 | ControlFlowScope(Type type, int lexicalScopeIndex, FinallyContext* finallyContext = nullptr) |
173 | : type(type) |
174 | , lexicalScopeIndex(lexicalScopeIndex) |
175 | , finallyContext(finallyContext) |
176 | { } |
177 | |
178 | bool isLabelScope() const { return type == Label; } |
179 | bool isFinallyScope() const { return type == Finally; } |
180 | |
181 | Type type; |
182 | int lexicalScopeIndex; |
183 | FinallyContext* finallyContext; |
184 | }; |
185 | |
186 | class ForInContext : public RefCounted<ForInContext> { |
187 | WTF_MAKE_FAST_ALLOCATED; |
188 | WTF_MAKE_NONCOPYABLE(ForInContext); |
189 | public: |
190 | virtual ~ForInContext() = default; |
191 | |
192 | bool isValid() const { return m_isValid; } |
193 | void invalidate() { m_isValid = false; } |
194 | |
195 | enum class Type : uint8_t { |
196 | IndexedForIn, |
197 | StructureForIn |
198 | }; |
199 | |
200 | Type type() const { return m_type; } |
201 | bool isIndexedForInContext() const { return m_type == Type::IndexedForIn; } |
202 | bool isStructureForInContext() const { return m_type == Type::StructureForIn; } |
203 | |
204 | IndexedForInContext& asIndexedForInContext() |
205 | { |
206 | ASSERT(isIndexedForInContext()); |
207 | return *reinterpret_cast<IndexedForInContext*>(this); |
208 | } |
209 | |
210 | StructureForInContext& asStructureForInContext() |
211 | { |
212 | ASSERT(isStructureForInContext()); |
213 | return *reinterpret_cast<StructureForInContext*>(this); |
214 | } |
215 | |
216 | RegisterID* local() const { return m_localRegister.get(); } |
217 | |
218 | protected: |
219 | ForInContext(RegisterID* localRegister, Type type, unsigned bodyBytecodeStartOffset) |
220 | : m_localRegister(localRegister) |
221 | , m_type(type) |
222 | , m_bodyBytecodeStartOffset(bodyBytecodeStartOffset) |
223 | { } |
224 | |
225 | unsigned bodyBytecodeStartOffset() const { return m_bodyBytecodeStartOffset; } |
226 | |
227 | void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset); |
228 | |
229 | private: |
230 | RefPtr<RegisterID> m_localRegister; |
231 | bool m_isValid { true }; |
232 | Type m_type; |
233 | unsigned m_bodyBytecodeStartOffset; |
234 | }; |
235 | |
236 | class StructureForInContext : public ForInContext { |
237 | using Base = ForInContext; |
238 | public: |
239 | using GetInst = std::tuple<unsigned, int>; |
240 | |
241 | StructureForInContext(RegisterID* localRegister, RegisterID* indexRegister, RegisterID* propertyRegister, RegisterID* enumeratorRegister, unsigned bodyBytecodeStartOffset) |
242 | : ForInContext(localRegister, Type::StructureForIn, bodyBytecodeStartOffset) |
243 | , m_indexRegister(indexRegister) |
244 | , m_propertyRegister(propertyRegister) |
245 | , m_enumeratorRegister(enumeratorRegister) |
246 | { |
247 | } |
248 | |
249 | RegisterID* index() const { return m_indexRegister.get(); } |
250 | RegisterID* property() const { return m_propertyRegister.get(); } |
251 | RegisterID* enumerator() const { return m_enumeratorRegister.get(); } |
252 | |
253 | void addGetInst(unsigned instIndex, int propertyRegIndex) |
254 | { |
255 | m_getInsts.append(GetInst { instIndex, propertyRegIndex }); |
256 | } |
257 | |
258 | void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset); |
259 | |
260 | private: |
261 | RefPtr<RegisterID> m_indexRegister; |
262 | RefPtr<RegisterID> m_propertyRegister; |
263 | RefPtr<RegisterID> m_enumeratorRegister; |
264 | Vector<GetInst> m_getInsts; |
265 | }; |
266 | |
267 | class IndexedForInContext : public ForInContext { |
268 | using Base = ForInContext; |
269 | public: |
270 | IndexedForInContext(RegisterID* localRegister, RegisterID* indexRegister, unsigned bodyBytecodeStartOffset) |
271 | : ForInContext(localRegister, Type::IndexedForIn, bodyBytecodeStartOffset) |
272 | , m_indexRegister(indexRegister) |
273 | { |
274 | } |
275 | |
276 | RegisterID* index() const { return m_indexRegister.get(); } |
277 | |
278 | void finalize(BytecodeGenerator&, UnlinkedCodeBlock*, unsigned bodyBytecodeEndOffset); |
279 | void addGetInst(unsigned instIndex, int propertyIndex) { m_getInsts.append({ instIndex, propertyIndex }); } |
280 | |
281 | private: |
282 | RefPtr<RegisterID> m_indexRegister; |
283 | Vector<std::pair<unsigned, int>> m_getInsts; |
284 | }; |
285 | |
286 | struct TryData { |
287 | Ref<Label> target; |
288 | HandlerType handlerType; |
289 | }; |
290 | |
291 | struct TryContext { |
292 | Ref<Label> start; |
293 | TryData* tryData; |
294 | }; |
295 | |
296 | class Variable { |
297 | public: |
298 | enum VariableKind { NormalVariable, SpecialVariable }; |
299 | |
300 | Variable() |
301 | : m_offset() |
302 | , m_local(nullptr) |
303 | , m_attributes(0) |
304 | , m_kind(NormalVariable) |
305 | , m_symbolTableConstantIndex(0) // This is meaningless here for this kind of Variable. |
306 | , m_isLexicallyScoped(false) |
307 | { |
308 | } |
309 | |
310 | Variable(const Identifier& ident) |
311 | : m_ident(ident) |
312 | , m_local(nullptr) |
313 | , m_attributes(0) |
314 | , m_kind(NormalVariable) // This is somewhat meaningless here for this kind of Variable. |
315 | , m_symbolTableConstantIndex(0) // This is meaningless here for this kind of Variable. |
316 | , m_isLexicallyScoped(false) |
317 | { |
318 | } |
319 | |
320 | Variable(const Identifier& ident, VarOffset offset, RegisterID* local, unsigned attributes, VariableKind kind, int symbolTableConstantIndex, bool isLexicallyScoped) |
321 | : m_ident(ident) |
322 | , m_offset(offset) |
323 | , m_local(local) |
324 | , m_attributes(attributes) |
325 | , m_kind(kind) |
326 | , m_symbolTableConstantIndex(symbolTableConstantIndex) |
327 | , m_isLexicallyScoped(isLexicallyScoped) |
328 | { |
329 | } |
330 | |
331 | // If it's unset, then it is a non-locally-scoped variable. If it is set, then it could be |
332 | // a stack variable, a scoped variable in a local scope, or a variable captured in the |
333 | // direct arguments object. |
334 | bool isResolved() const { return !!m_offset; } |
335 | int symbolTableConstantIndex() const { ASSERT(isResolved() && !isSpecial()); return m_symbolTableConstantIndex; } |
336 | |
337 | const Identifier& ident() const { return m_ident; } |
338 | |
339 | VarOffset offset() const { return m_offset; } |
340 | bool isLocal() const { return m_offset.isStack(); } |
341 | RegisterID* local() const { return m_local; } |
342 | |
343 | bool isReadOnly() const { return m_attributes & PropertyAttribute::ReadOnly; } |
344 | bool isSpecial() const { return m_kind != NormalVariable; } |
345 | bool isConst() const { return isReadOnly() && m_isLexicallyScoped; } |
346 | void setIsReadOnly() { m_attributes |= PropertyAttribute::ReadOnly; } |
347 | |
348 | void dump(PrintStream&) const; |
349 | |
350 | private: |
351 | Identifier m_ident; |
352 | VarOffset m_offset; |
353 | RegisterID* m_local; |
354 | unsigned m_attributes; |
355 | VariableKind m_kind; |
356 | int m_symbolTableConstantIndex; |
357 | bool m_isLexicallyScoped; |
358 | }; |
359 | |
360 | struct TryRange { |
361 | Ref<Label> start; |
362 | Ref<Label> end; |
363 | TryData* tryData; |
364 | }; |
365 | |
366 | |
367 | struct JSGeneratorTraits { |
368 | using OpcodeTraits = JSOpcodeTraits; |
369 | using OpcodeID = ::JSC::OpcodeID; |
370 | using OpNop = ::JSC::OpNop; |
371 | using CodeBlock = Strong<UnlinkedCodeBlock>; |
372 | static constexpr OpcodeID opcodeForDisablingOptimizations = op_end; |
373 | }; |
374 | |
375 | class BytecodeGenerator : public BytecodeGeneratorBase<JSGeneratorTraits> { |
376 | WTF_MAKE_FAST_ALLOCATED; |
377 | WTF_MAKE_NONCOPYABLE(BytecodeGenerator); |
378 | |
379 | friend class FinallyContext; |
380 | friend class IndexedForInContext; |
381 | friend class StructureForInContext; |
382 | public: |
383 | typedef DeclarationStacks::FunctionStack FunctionStack; |
384 | |
385 | BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, OptionSet<CodeGenerationMode>, const VariableEnvironment*); |
386 | BytecodeGenerator(VM&, FunctionNode*, UnlinkedFunctionCodeBlock*, OptionSet<CodeGenerationMode>, const VariableEnvironment*); |
387 | BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, OptionSet<CodeGenerationMode>, const VariableEnvironment*); |
388 | BytecodeGenerator(VM&, ModuleProgramNode*, UnlinkedModuleProgramCodeBlock*, OptionSet<CodeGenerationMode>, const VariableEnvironment*); |
389 | |
390 | ~BytecodeGenerator(); |
391 | |
392 | VM& vm() const { return m_vm; } |
393 | ParserArena& parserArena() const { return m_scopeNode->parserArena(); } |
394 | const CommonIdentifiers& propertyNames() const { return *m_vm.propertyNames; } |
395 | |
396 | bool isConstructor() const { return m_codeBlock->isConstructor(); } |
397 | DerivedContextType derivedContextType() const { return m_derivedContextType; } |
398 | bool usesArrowFunction() const { return m_scopeNode->usesArrowFunction(); } |
399 | bool needsToUpdateArrowFunctionContext() const { return m_needsToUpdateArrowFunctionContext; } |
400 | bool usesEval() const { return m_scopeNode->usesEval(); } |
401 | bool usesThis() const { return m_scopeNode->usesThis(); } |
402 | ConstructorKind constructorKind() const { return m_codeBlock->constructorKind(); } |
403 | SuperBinding superBinding() const { return m_codeBlock->superBinding(); } |
404 | JSParserScriptMode scriptMode() const { return m_codeBlock->scriptMode(); } |
405 | |
406 | template<typename Node, typename UnlinkedCodeBlock> |
407 | static ParserError generate(VM& vm, Node* node, const SourceCode& sourceCode, UnlinkedCodeBlock* unlinkedCodeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* environment) |
408 | { |
409 | MonotonicTime before; |
410 | if (UNLIKELY(Options::reportBytecodeCompileTimes())) |
411 | before = MonotonicTime::now(); |
412 | |
413 | DeferGC deferGC(vm.heap); |
414 | auto bytecodeGenerator = makeUnique<BytecodeGenerator>(vm, node, unlinkedCodeBlock, codeGenerationMode, environment); |
415 | auto result = bytecodeGenerator->generate(); |
416 | |
417 | if (UNLIKELY(Options::reportBytecodeCompileTimes())) { |
418 | MonotonicTime after = MonotonicTime::now(); |
419 | dataLogLn(result.isValid() ? "Failed to compile #" : "Compiled #" , CodeBlockHash(sourceCode, unlinkedCodeBlock->isConstructor() ? CodeForConstruct : CodeForCall), " into bytecode " , bytecodeGenerator->instructions().size(), " instructions in " , (after - before).milliseconds(), " ms." ); |
420 | } |
421 | return result; |
422 | } |
423 | |
424 | bool isArgumentNumber(const Identifier&, int); |
425 | |
426 | Variable variable(const Identifier&, ThisResolutionType = ThisResolutionType::Local); |
427 | |
428 | enum ExistingVariableMode { VerifyExisting, IgnoreExisting }; |
429 | void createVariable(const Identifier&, VarKind, SymbolTable*, ExistingVariableMode = VerifyExisting); // Creates the variable, or asserts that the already-created variable is sufficiently compatible. |
430 | |
431 | // Returns the register storing "this" |
432 | RegisterID* thisRegister() { return &m_thisRegister; } |
433 | RegisterID* argumentsRegister() { return m_argumentsRegister; } |
434 | RegisterID* newTarget() |
435 | { |
436 | ASSERT(m_newTargetRegister); |
437 | return m_newTargetRegister; |
438 | } |
439 | |
440 | RegisterID* scopeRegister() { return m_scopeRegister; } |
441 | |
442 | RegisterID* generatorRegister() { return m_generatorRegister; } |
443 | |
444 | RegisterID* promiseRegister() { return m_promiseRegister; } |
445 | |
446 | // The same as newTemporary(), but this function returns "suggestion" if |
447 | // "suggestion" is a temporary. This function is helpful in situations |
448 | // where you've put "suggestion" in a RefPtr, but you'd like to allow |
449 | // the next instruction to overwrite it anyway. |
450 | RegisterID* newTemporaryOr(RegisterID* suggestion) { return suggestion->isTemporary() ? suggestion : newTemporary(); } |
451 | |
452 | // Functions for handling of dst register |
453 | |
454 | RegisterID* ignoredResult() { return &m_ignoredResultRegister; } |
455 | |
456 | // This will be allocated in the temporary region of registers, but it will |
457 | // not be marked as a temporary. This will ensure that finalDestination() does |
458 | // not overwrite a block scope variable that it mistakes as a temporary. These |
459 | // registers can be (and are) reclaimed when the lexical scope they belong to |
460 | // is no longer on the symbol table stack. |
461 | RegisterID* newBlockScopeVariable(); |
462 | |
463 | // Returns a place to write intermediate values of an operation |
464 | // which reuses dst if it is safe to do so. |
465 | RegisterID* tempDestination(RegisterID* dst) |
466 | { |
467 | return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary(); |
468 | } |
469 | |
470 | // Returns the place to write the final output of an operation. |
471 | RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0) |
472 | { |
473 | if (originalDst && originalDst != ignoredResult()) |
474 | return originalDst; |
475 | ASSERT(tempDst != ignoredResult()); |
476 | if (tempDst && tempDst->isTemporary()) |
477 | return tempDst; |
478 | return newTemporary(); |
479 | } |
480 | |
481 | RegisterID* destinationForAssignResult(RegisterID* dst) |
482 | { |
483 | if (dst && dst != ignoredResult()) |
484 | return dst->isTemporary() ? dst : newTemporary(); |
485 | return 0; |
486 | } |
487 | |
488 | // Moves src to dst if dst is not null and is different from src, otherwise just returns src. |
489 | RegisterID* move(RegisterID* dst, RegisterID* src) |
490 | { |
491 | return dst == ignoredResult() ? nullptr : (dst && dst != src) ? emitMove(dst, src) : src; |
492 | } |
493 | |
494 | Ref<LabelScope> newLabelScope(LabelScope::Type, const Identifier* = 0); |
495 | |
496 | void emitNode(RegisterID* dst, StatementNode* n) |
497 | { |
498 | SetForScope<bool> tailPositionPoisoner(m_inTailPosition, false); |
499 | return emitNodeInTailPosition(dst, n); |
500 | } |
501 | |
502 | void emitNodeInTailPosition(RegisterID* dst, StatementNode* n) |
503 | { |
504 | // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. |
505 | ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); |
506 | if (UNLIKELY(!m_vm.isSafeToRecurse())) { |
507 | emitThrowExpressionTooDeepException(); |
508 | return; |
509 | } |
510 | if (UNLIKELY(n->needsDebugHook())) |
511 | emitDebugHook(n); |
512 | n->emitBytecode(*this, dst); |
513 | } |
514 | |
515 | ALWAYS_INLINE unsigned addMetadataFor(OpcodeID opcodeID) |
516 | { |
517 | return m_codeBlock->metadata().addEntry(opcodeID); |
518 | } |
519 | |
520 | void emitNode(StatementNode* n) |
521 | { |
522 | emitNode(nullptr, n); |
523 | } |
524 | |
525 | void emitNodeInTailPosition(StatementNode* n) |
526 | { |
527 | emitNodeInTailPosition(nullptr, n); |
528 | } |
529 | |
530 | RegisterID* emitNode(RegisterID* dst, ExpressionNode* n) |
531 | { |
532 | SetForScope<bool> tailPositionPoisoner(m_inTailPosition, false); |
533 | return emitNodeInTailPosition(dst, n); |
534 | } |
535 | |
536 | RegisterID* emitNodeInTailPosition(RegisterID* dst, ExpressionNode* n) |
537 | { |
538 | // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. |
539 | ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); |
540 | if (UNLIKELY(!m_vm.isSafeToRecurse())) |
541 | return emitThrowExpressionTooDeepException(); |
542 | if (UNLIKELY(n->needsDebugHook())) |
543 | emitDebugHook(n); |
544 | return n->emitBytecode(*this, dst); |
545 | } |
546 | |
547 | RegisterID* emitNode(ExpressionNode* n) |
548 | { |
549 | return emitNode(nullptr, n); |
550 | } |
551 | |
552 | RegisterID* emitNodeInTailPosition(ExpressionNode* n) |
553 | { |
554 | return emitNodeInTailPosition(nullptr, n); |
555 | } |
556 | |
557 | RegisterID* emitDefineClassElements(PropertyListNode* n, RegisterID* constructor, RegisterID* prototype) |
558 | { |
559 | ASSERT(constructor->refCount() && prototype->refCount()); |
560 | if (UNLIKELY(!m_vm.isSafeToRecurse())) |
561 | return emitThrowExpressionTooDeepException(); |
562 | if (UNLIKELY(n->needsDebugHook())) |
563 | emitDebugHook(n); |
564 | return n->emitBytecode(*this, constructor, prototype); |
565 | } |
566 | |
567 | RegisterID* emitNodeForProperty(RegisterID* dst, ExpressionNode* node) |
568 | { |
569 | if (node->isString()) { |
570 | if (Optional<uint32_t> index = parseIndex(static_cast<StringNode*>(node)->value())) |
571 | return emitLoad(dst, jsNumber(index.value())); |
572 | } |
573 | return emitNode(dst, node); |
574 | } |
575 | |
576 | RegisterID* emitNodeForProperty(ExpressionNode* n) |
577 | { |
578 | return emitNodeForProperty(nullptr, n); |
579 | } |
580 | |
581 | void emitNodeInConditionContext(ExpressionNode* n, Label& trueTarget, Label& falseTarget, FallThroughMode fallThroughMode) |
582 | { |
583 | if (UNLIKELY(!m_vm.isSafeToRecurse())) { |
584 | emitThrowExpressionTooDeepException(); |
585 | return; |
586 | } |
587 | n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMode); |
588 | } |
589 | |
590 | void emitExpressionInfo(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) |
591 | { |
592 | ASSERT(divot.offset >= divotStart.offset); |
593 | ASSERT(divotEnd.offset >= divot.offset); |
594 | |
595 | int sourceOffset = m_scopeNode->source().startOffset(); |
596 | unsigned firstLine = m_scopeNode->source().firstLine().oneBasedInt(); |
597 | |
598 | int divotOffset = divot.offset - sourceOffset; |
599 | int startOffset = divot.offset - divotStart.offset; |
600 | int endOffset = divotEnd.offset - divot.offset; |
601 | |
602 | unsigned line = divot.line; |
603 | ASSERT(line >= firstLine); |
604 | line -= firstLine; |
605 | |
606 | int lineStart = divot.lineStartOffset; |
607 | if (lineStart > sourceOffset) |
608 | lineStart -= sourceOffset; |
609 | else |
610 | lineStart = 0; |
611 | |
612 | if (divotOffset < lineStart) |
613 | return; |
614 | |
615 | unsigned column = divotOffset - lineStart; |
616 | |
617 | unsigned instructionOffset = instructions().size(); |
618 | if (!m_isBuiltinFunction) |
619 | m_codeBlock->addExpressionInfo(instructionOffset, divotOffset, startOffset, endOffset, line, column); |
620 | } |
621 | |
622 | |
623 | ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) |
624 | { |
625 | return (m_codeType != FunctionCode || rightHasAssignments) && !rightIsPure; |
626 | } |
627 | |
628 | ALWAYS_INLINE RefPtr<RegisterID> emitNodeForLeftHandSide(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure) |
629 | { |
630 | if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) { |
631 | RefPtr<RegisterID> dst = newTemporary(); |
632 | emitNode(dst.get(), n); |
633 | return dst; |
634 | } |
635 | |
636 | return emitNode(n); |
637 | } |
638 | |
639 | ALWAYS_INLINE RefPtr<RegisterID> emitNodeForLeftHandSideForProperty(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure) |
640 | { |
641 | if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) { |
642 | RefPtr<RegisterID> dst = newTemporary(); |
643 | emitNodeForProperty(dst.get(), n); |
644 | return dst; |
645 | } |
646 | |
647 | return emitNodeForProperty(n); |
648 | } |
649 | |
650 | void hoistSloppyModeFunctionIfNecessary(const Identifier& functionName); |
651 | |
652 | private: |
653 | void emitTypeProfilerExpressionInfo(const JSTextPosition& startDivot, const JSTextPosition& endDivot); |
654 | public: |
655 | |
656 | // This doesn't emit expression info. If using this, make sure you shouldn't be emitting text offset. |
657 | void emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag); |
658 | // These variables are associated with variables in a program. They could be Locals, LocalClosureVar, or ClosureVar. |
659 | void emitProfileType(RegisterID* registerToProfile, const Variable&, const JSTextPosition& startDivot, const JSTextPosition& endDivot); |
660 | |
661 | void emitProfileType(RegisterID* registerToProfile, ProfileTypeBytecodeFlag, const JSTextPosition& startDivot, const JSTextPosition& endDivot); |
662 | // These are not associated with variables and don't have a global id. |
663 | void emitProfileType(RegisterID* registerToProfile, const JSTextPosition& startDivot, const JSTextPosition& endDivot); |
664 | |
665 | void emitProfileControlFlow(int); |
666 | |
667 | RegisterID* emitLoadArrowFunctionLexicalEnvironment(const Identifier&); |
668 | RegisterID* ensureThis(); |
669 | void emitLoadThisFromArrowFunctionLexicalEnvironment(); |
670 | RegisterID* emitLoadNewTargetFromArrowFunctionLexicalEnvironment(); |
671 | |
672 | unsigned addConstantIndex(); |
673 | RegisterID* emitLoad(RegisterID* dst, bool); |
674 | RegisterID* emitLoad(RegisterID* dst, const Identifier&); |
675 | RegisterID* emitLoad(RegisterID* dst, JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other); |
676 | RegisterID* emitLoad(RegisterID* dst, IdentifierSet& excludedList); |
677 | |
678 | template<typename UnaryOp, typename = std::enable_if_t<UnaryOp::opcodeID != op_negate>> |
679 | RegisterID* emitUnaryOp(RegisterID* dst, RegisterID* src) |
680 | { |
681 | UnaryOp::emit(this, dst, src); |
682 | return dst; |
683 | } |
684 | |
685 | RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src, ResultType); |
686 | |
687 | template<typename BinaryOp> |
688 | std::enable_if_t< |
689 | BinaryOp::opcodeID != op_add |
690 | && BinaryOp::opcodeID != op_mul |
691 | && BinaryOp::opcodeID != op_sub |
692 | && BinaryOp::opcodeID != op_div, |
693 | RegisterID*> |
694 | emitBinaryOp(RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes) |
695 | { |
696 | BinaryOp::emit(this, dst, src1, src2); |
697 | return dst; |
698 | } |
699 | |
700 | template<typename BinaryOp> |
701 | std::enable_if_t< |
702 | BinaryOp::opcodeID == op_add |
703 | || BinaryOp::opcodeID == op_mul |
704 | || BinaryOp::opcodeID == op_sub |
705 | || BinaryOp::opcodeID == op_div, |
706 | RegisterID*> |
707 | emitBinaryOp(RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types) |
708 | { |
709 | BinaryOp::emit(this, dst, src1, src2, types); |
710 | return dst; |
711 | } |
712 | |
713 | RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes); |
714 | |
715 | template<typename EqOp> |
716 | RegisterID* emitEqualityOp(RegisterID* dst, RegisterID* src1, RegisterID* src2) |
717 | { |
718 | if (!emitEqualityOpImpl(dst, src1, src2)) |
719 | EqOp::emit(this, dst, src1, src2); |
720 | return dst; |
721 | } |
722 | |
723 | bool emitEqualityOpImpl(RegisterID* dst, RegisterID* src1, RegisterID* src2); |
724 | |
725 | RegisterID* emitCreateThis(RegisterID* dst); |
726 | RegisterID* emitCreatePromise(RegisterID* dst, RegisterID* newTarget, bool isInternalPromise); |
727 | RegisterID* emitCreateGenerator(RegisterID* dst, RegisterID* newTarget); |
728 | RegisterID* emitCreateAsyncGenerator(RegisterID* dst, RegisterID* newTarget); |
729 | void emitTDZCheck(RegisterID* target); |
730 | bool needsTDZCheck(const Variable&); |
731 | void emitTDZCheckIfNecessary(const Variable&, RegisterID* target, RegisterID* scope); |
732 | void liftTDZCheckIfPossible(const Variable&); |
733 | RegisterID* emitNewObject(RegisterID* dst); |
734 | RegisterID* emitNewPromise(RegisterID* dst, bool isInternalPromise); |
735 | RegisterID* emitNewGenerator(RegisterID* dst); |
736 | RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length, IndexingType recommendedIndexingType); // stops at first elision |
737 | RegisterID* emitNewArrayBuffer(RegisterID* dst, JSImmutableButterfly*, IndexingType recommendedIndexingType); |
738 | // FIXME: new_array_with_spread should use an array allocation profile and take a recommendedIndexingType |
739 | RegisterID* emitNewArrayWithSpread(RegisterID* dst, ElementNode*); |
740 | RegisterID* emitNewArrayWithSize(RegisterID* dst, RegisterID* length); |
741 | |
742 | RegisterID* emitNewFunction(RegisterID* dst, FunctionMetadataNode*); |
743 | RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode*); |
744 | RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name, const Identifier& ecmaName, const SourceCode& classSource); |
745 | RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*); |
746 | RegisterID* emitNewMethodDefinition(RegisterID* dst, MethodDefinitionNode*); |
747 | RegisterID* emitNewRegExp(RegisterID* dst, RegExp*); |
748 | |
749 | void emitSetFunctionNameIfNeeded(ExpressionNode* valueNode, RegisterID* value, RegisterID* name); |
750 | |
751 | RegisterID* moveLinkTimeConstant(RegisterID* dst, LinkTimeConstant); |
752 | RegisterID* moveEmptyValue(RegisterID* dst); |
753 | |
754 | RegisterID* emitToNumber(RegisterID* dst, RegisterID* src); |
755 | RegisterID* emitToNumeric(RegisterID* dst, RegisterID* src); |
756 | RegisterID* emitToString(RegisterID* dst, RegisterID* src); |
757 | RegisterID* emitToObject(RegisterID* dst, RegisterID* src, const Identifier& message); |
758 | RegisterID* emitInc(RegisterID* srcDst); |
759 | RegisterID* emitDec(RegisterID* srcDst); |
760 | |
761 | RegisterID* emitOverridesHasInstance(RegisterID* dst, RegisterID* constructor, RegisterID* hasInstanceValue); |
762 | RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype); |
763 | RegisterID* emitInstanceOfCustom(RegisterID* dst, RegisterID* value, RegisterID* constructor, RegisterID* hasInstanceValue); |
764 | RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src); |
765 | RegisterID* emitInByVal(RegisterID* dst, RegisterID* property, RegisterID* base); |
766 | RegisterID* emitInById(RegisterID* dst, RegisterID* base, const Identifier& property); |
767 | |
768 | RegisterID* emitTryGetById(RegisterID* dst, RegisterID* base, const Identifier& property); |
769 | RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property); |
770 | RegisterID* emitGetById(RegisterID* dst, RegisterID* base, RegisterID* thisVal, const Identifier& property); |
771 | RegisterID* emitDirectGetById(RegisterID* dst, RegisterID* base, const Identifier& property); |
772 | RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value); |
773 | RegisterID* emitPutById(RegisterID* base, RegisterID* thisValue, const Identifier& property, RegisterID* value); |
774 | RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType); |
775 | RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&); |
776 | RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property); |
777 | RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property); |
778 | RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); |
779 | RegisterID* emitPutByVal(RegisterID* base, RegisterID* thisValue, RegisterID* property, RegisterID* value); |
780 | RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); |
781 | RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); |
782 | |
783 | RegisterID* emitGetInternalField(RegisterID* dst, RegisterID* base, unsigned index); |
784 | RegisterID* emitPutInternalField(RegisterID* base, unsigned index, RegisterID* value); |
785 | |
786 | void emitSuperSamplerBegin(); |
787 | void emitSuperSamplerEnd(); |
788 | |
789 | RegisterID* emitIdWithProfile(RegisterID* src, SpeculatedType profile); |
790 | void emitUnreachable(); |
791 | |
792 | void emitPutGetterById(RegisterID* base, const Identifier& property, unsigned propertyDescriptorOptions, RegisterID* getter); |
793 | void emitPutSetterById(RegisterID* base, const Identifier& property, unsigned propertyDescriptorOptions, RegisterID* setter); |
794 | void emitPutGetterSetter(RegisterID* base, const Identifier& property, unsigned attributes, RegisterID* getter, RegisterID* setter); |
795 | void emitPutGetterByVal(RegisterID* base, RegisterID* property, unsigned propertyDescriptorOptions, RegisterID* getter); |
796 | void emitPutSetterByVal(RegisterID* base, RegisterID* property, unsigned propertyDescriptorOptions, RegisterID* setter); |
797 | |
798 | RegisterID* emitGetArgument(RegisterID* dst, int32_t index); |
799 | |
800 | // Initialize object with generator fields (@generatorThis, @generatorNext, @generatorState, @generatorFrame) |
801 | void emitPutGeneratorFields(RegisterID* nextFunction); |
802 | |
803 | void emitPutAsyncGeneratorFields(RegisterID* nextFunction); |
804 | |
805 | ExpectedFunction expectedFunctionForIdentifier(const Identifier&); |
806 | RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); |
807 | RegisterID* emitCallInTailPosition(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); |
808 | RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); |
809 | RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); |
810 | RegisterID* emitCallVarargsInTailPosition(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); |
811 | RegisterID* emitCallForwardArgumentsInTailPosition(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); |
812 | |
813 | enum PropertyDescriptorOption { |
814 | PropertyConfigurable = 1, |
815 | PropertyWritable = 1 << 1, |
816 | PropertyEnumerable = 1 << 2, |
817 | }; |
818 | void emitCallDefineProperty(RegisterID* newObj, RegisterID* propertyNameRegister, |
819 | RegisterID* valueRegister, RegisterID* getterRegister, RegisterID* setterRegister, unsigned options, const JSTextPosition&); |
820 | |
821 | void emitEnumeration(ThrowableExpressionData* enumerationNode, ExpressionNode* subjectNode, const ScopedLambda<void(BytecodeGenerator&, RegisterID*)>& callBack, ForOfNode* = nullptr, RegisterID* forLoopSymbolTable = nullptr); |
822 | |
823 | RegisterID* emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode*); |
824 | RegisterID* emitGetGlobalPrivate(RegisterID* dst, const Identifier& property); |
825 | |
826 | enum class ReturnFrom { Normal, Finally }; |
827 | RegisterID* emitReturn(RegisterID* src, ReturnFrom = ReturnFrom::Normal); |
828 | RegisterID* emitEnd(RegisterID* src); |
829 | |
830 | RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, RegisterID* lazyThis, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); |
831 | RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count); |
832 | void emitToPrimitive(RegisterID* dst, RegisterID* src); |
833 | |
834 | ResolveType resolveType(); |
835 | RegisterID* emitResolveConstantLocal(RegisterID* dst, const Variable&); |
836 | RegisterID* emitResolveScope(RegisterID* dst, const Variable&); |
837 | RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Variable&, ResolveMode); |
838 | RegisterID* emitPutToScope(RegisterID* scope, const Variable&, RegisterID* value, ResolveMode, InitializationMode); |
839 | |
840 | RegisterID* emitResolveScopeForHoistingFuncDeclInEval(RegisterID* dst, const Identifier&); |
841 | |
842 | RegisterID* initializeVariable(const Variable&, RegisterID* value); |
843 | |
844 | void emitLoopHint(); |
845 | void emitJump(Label& target); |
846 | void emitJumpIfTrue(RegisterID* cond, Label& target); |
847 | void emitJumpIfFalse(RegisterID* cond, Label& target); |
848 | void emitJumpIfNotFunctionCall(RegisterID* cond, Label& target); |
849 | void emitJumpIfNotFunctionApply(RegisterID* cond, Label& target); |
850 | |
851 | template<typename BinOp, typename JmpOp> |
852 | bool fuseCompareAndJump(RegisterID* cond, Label& target, bool swapOperands = false); |
853 | |
854 | template<typename UnaryOp, typename JmpOp> |
855 | bool fuseTestAndJmp(RegisterID* cond, Label& target); |
856 | |
857 | void emitEnter(); |
858 | void emitCheckTraps(); |
859 | |
860 | RegisterID* emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName); |
861 | RegisterID* emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator); |
862 | RegisterID* emitHasGenericProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName); |
863 | RegisterID* emitGetPropertyEnumerator(RegisterID* dst, RegisterID* base); |
864 | RegisterID* emitGetEnumerableLength(RegisterID* dst, RegisterID* base); |
865 | RegisterID* emitGetStructurePropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length); |
866 | RegisterID* emitGetGenericPropertyEnumerator(RegisterID* dst, RegisterID* base, RegisterID* length, RegisterID* structureEnumerator); |
867 | RegisterID* emitEnumeratorStructurePropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index); |
868 | RegisterID* emitEnumeratorGenericPropertyName(RegisterID* dst, RegisterID* enumerator, RegisterID* index); |
869 | RegisterID* emitToIndexString(RegisterID* dst, RegisterID* index); |
870 | |
871 | RegisterID* emitIsCellWithType(RegisterID* dst, RegisterID* src, JSType); |
872 | RegisterID* emitIsGenerator(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSGeneratorType); } |
873 | RegisterID* emitIsAsyncGenerator(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSAsyncGeneratorType); } |
874 | RegisterID* emitIsJSArray(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, ArrayType); } |
875 | RegisterID* emitIsPromise(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSPromiseType); } |
876 | RegisterID* emitIsProxyObject(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, ProxyObjectType); } |
877 | RegisterID* emitIsRegExpObject(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, RegExpObjectType); } |
878 | RegisterID* emitIsMap(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSMapType); } |
879 | RegisterID* emitIsSet(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, JSSetType); } |
880 | RegisterID* emitIsObject(RegisterID* dst, RegisterID* src); |
881 | RegisterID* emitIsNumber(RegisterID* dst, RegisterID* src); |
882 | RegisterID* emitIsUndefined(RegisterID* dst, RegisterID* src); |
883 | RegisterID* emitIsUndefinedOrNull(RegisterID* dst, RegisterID* src); |
884 | RegisterID* emitIsEmpty(RegisterID* dst, RegisterID* src); |
885 | RegisterID* emitIsDerivedArray(RegisterID* dst, RegisterID* src) { return emitIsCellWithType(dst, src, DerivedArrayType); } |
886 | void emitRequireObjectCoercible(RegisterID* value, const String& error); |
887 | |
888 | RegisterID* emitIteratorNext(RegisterID* dst, RegisterID* nextMethod, RegisterID* iterator, const ThrowableExpressionData* node, JSC::EmitAwait = JSC::EmitAwait::No); |
889 | RegisterID* emitIteratorNextWithValue(RegisterID* dst, RegisterID* nextMethod, RegisterID* iterator, RegisterID* value, const ThrowableExpressionData* node); |
890 | void emitIteratorClose(RegisterID* iterator, const ThrowableExpressionData* node, EmitAwait = EmitAwait::No); |
891 | |
892 | RegisterID* emitRestParameter(RegisterID* result, unsigned numParametersToSkip); |
893 | |
894 | bool emitReadOnlyExceptionIfNeeded(const Variable&); |
895 | |
896 | // Start a try block. 'start' must have been emitted. |
897 | TryData* pushTry(Label& start, Label& handlerLabel, HandlerType); |
898 | // End a try block. 'end' must have been emitted. |
899 | void popTry(TryData*, Label& end); |
900 | |
901 | void emitOutOfLineCatchHandler(RegisterID* thrownValueRegister, RegisterID* completionTypeRegister, TryData*); |
902 | void emitOutOfLineFinallyHandler(RegisterID* exceptionRegister, RegisterID* completionTypeRegister, TryData*); |
903 | |
904 | private: |
905 | static constexpr int CurrentLexicalScopeIndex = -2; |
906 | static constexpr int OutermostLexicalScopeIndex = -1; |
907 | |
908 | int currentLexicalScopeIndex() const |
909 | { |
910 | int size = static_cast<int>(m_lexicalScopeStack.size()); |
911 | ASSERT(static_cast<size_t>(size) == m_lexicalScopeStack.size()); |
912 | ASSERT(size >= 0); |
913 | if (!size) |
914 | return OutermostLexicalScopeIndex; |
915 | return size - 1; |
916 | } |
917 | |
918 | void emitOutOfLineExceptionHandler(RegisterID* exceptionRegister, RegisterID* thrownValueRegister, RegisterID* completionTypeRegister, TryData*); |
919 | |
920 | public: |
921 | void restoreScopeRegister(); |
922 | void restoreScopeRegister(int lexicalScopeIndex); |
923 | |
924 | int labelScopeDepthToLexicalScopeIndex(int labelScopeDepth); |
925 | |
926 | void emitThrow(RegisterID*); |
927 | RegisterID* emitArgumentCount(RegisterID*); |
928 | |
929 | void emitThrowStaticError(ErrorType, RegisterID*); |
930 | void emitThrowStaticError(ErrorType, const Identifier& message); |
931 | void emitThrowReferenceError(const String& message); |
932 | void emitThrowTypeError(const String& message); |
933 | void emitThrowTypeError(const Identifier& message); |
934 | void emitThrowRangeError(const Identifier& message); |
935 | void emitThrowOutOfMemoryError(); |
936 | |
937 | void emitPushCatchScope(VariableEnvironment&); |
938 | void emitPopCatchScope(VariableEnvironment&); |
939 | |
940 | RegisterID* emitGetIterator(RegisterID*, ThrowableExpressionData*); |
941 | RegisterID* emitGetAsyncIterator(RegisterID*, ThrowableExpressionData*); |
942 | |
943 | void emitAwait(RegisterID*); |
944 | void emitGetScope(); |
945 | RegisterID* emitPushWithScope(RegisterID* objectScope); |
946 | void emitPopWithScope(); |
947 | void emitPutThisToArrowFunctionContextScope(); |
948 | void emitPutNewTargetToArrowFunctionContextScope(); |
949 | void emitPutDerivedConstructorToArrowFunctionContextScope(); |
950 | RegisterID* emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(); |
951 | |
952 | void emitDebugHook(DebugHookType, const JSTextPosition&); |
953 | void emitDebugHook(DebugHookType, unsigned line, unsigned charOffset, unsigned lineStart); |
954 | void emitDebugHook(StatementNode*); |
955 | void emitDebugHook(ExpressionNode*); |
956 | void emitWillLeaveCallFrameDebugHook(); |
957 | |
958 | void emitLoad(RegisterID* completionTypeRegister, CompletionType type) |
959 | { |
960 | emitLoad(completionTypeRegister, JSValue(static_cast<int>(type))); |
961 | } |
962 | |
963 | template<typename CompareOp> |
964 | void emitJumpIf(RegisterID* completionTypeRegister, CompletionType, Label& jumpTarget); |
965 | |
966 | bool emitJumpViaFinallyIfNeeded(int targetLabelScopeDepth, Label& jumpTarget); |
967 | bool emitReturnViaFinallyIfNeeded(RegisterID* returnRegister); |
968 | void emitFinallyCompletion(FinallyContext&, Label& normalCompletionLabel); |
969 | |
970 | public: |
971 | void pushFinallyControlFlowScope(FinallyContext&); |
972 | void popFinallyControlFlowScope(); |
973 | |
974 | void pushOptionalChainTarget(); |
975 | void popOptionalChainTarget(); |
976 | void popOptionalChainTarget(RegisterID* dst, bool isDelete); |
977 | void emitOptionalCheck(RegisterID* src); |
978 | |
979 | void pushIndexedForInScope(RegisterID* local, RegisterID* index); |
980 | void popIndexedForInScope(RegisterID* local); |
981 | void pushStructureForInScope(RegisterID* local, RegisterID* index, RegisterID* property, RegisterID* enumerator); |
982 | void popStructureForInScope(RegisterID* local); |
983 | |
984 | LabelScope* breakTarget(const Identifier&); |
985 | LabelScope* continueTarget(const Identifier&); |
986 | |
987 | void beginSwitch(RegisterID*, SwitchInfo::SwitchType); |
988 | void endSwitch(uint32_t clauseCount, const Vector<Ref<Label>, 8>&, ExpressionNode**, Label& defaultLabel, int32_t min, int32_t range); |
989 | |
990 | void emitYieldPoint(RegisterID*, JSAsyncGenerator::AsyncGeneratorSuspendReason); |
991 | |
992 | void emitGeneratorStateLabel(); |
993 | void emitGeneratorStateChange(int32_t state); |
994 | RegisterID* emitYield(RegisterID* argument, JSAsyncGenerator::AsyncGeneratorSuspendReason = JSAsyncGenerator::AsyncGeneratorSuspendReason::Yield); |
995 | RegisterID* emitDelegateYield(RegisterID* argument, ThrowableExpressionData*); |
996 | RegisterID* generatorStateRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::State)]; } |
997 | RegisterID* generatorValueRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::Value)]; } |
998 | RegisterID* generatorResumeModeRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::ResumeMode)]; } |
999 | RegisterID* generatorFrameRegister() { return &m_parameters[static_cast<int32_t>(JSGenerator::GeneratorArgument::Frame)]; } |
1000 | |
1001 | CodeType codeType() const { return m_codeType; } |
1002 | |
1003 | bool shouldBeConcernedWithCompletionValue() const { return m_codeType != FunctionCode; } |
1004 | |
1005 | bool shouldEmitDebugHooks() const { return m_codeGenerationMode.contains(CodeGenerationMode::Debugger) && !m_isBuiltinFunction; } |
1006 | bool shouldEmitTypeProfilerHooks() const { return m_codeGenerationMode.contains(CodeGenerationMode::TypeProfiler); } |
1007 | bool shouldEmitControlFlowProfilerHooks() const { return m_codeGenerationMode.contains(CodeGenerationMode::ControlFlowProfiler); } |
1008 | |
1009 | bool isStrictMode() const { return m_codeBlock->isStrictMode(); } |
1010 | |
1011 | SourceParseMode parseMode() const { return m_codeBlock->parseMode(); } |
1012 | |
1013 | bool isBuiltinFunction() const { return m_isBuiltinFunction; } |
1014 | |
1015 | OpcodeID lastOpcodeID() const { return m_lastOpcodeID; } |
1016 | |
1017 | bool isDerivedConstructorContext() { return m_derivedContextType == DerivedContextType::DerivedConstructorContext; } |
1018 | bool isDerivedClassContext() { return m_derivedContextType == DerivedContextType::DerivedMethodContext; } |
1019 | bool isArrowFunction() { return m_codeBlock->isArrowFunction(); } |
1020 | |
1021 | enum class TDZCheckOptimization { Optimize, DoNotOptimize }; |
1022 | enum class NestedScopeType { IsNested, IsNotNested }; |
1023 | private: |
1024 | enum class TDZRequirement { UnderTDZ, NotUnderTDZ }; |
1025 | enum class ScopeType { CatchScope, LetConstScope, FunctionNameScope }; |
1026 | enum class ScopeRegisterType { Var, Block }; |
1027 | void pushLexicalScopeInternal(VariableEnvironment&, TDZCheckOptimization, NestedScopeType, RegisterID** constantSymbolTableResult, TDZRequirement, ScopeType, ScopeRegisterType); |
1028 | void initializeBlockScopedFunctions(VariableEnvironment&, FunctionStack&, RegisterID* constantSymbolTable); |
1029 | void popLexicalScopeInternal(VariableEnvironment&); |
1030 | template<typename LookUpVarKindFunctor> |
1031 | bool instantiateLexicalVariables(const VariableEnvironment&, SymbolTable*, ScopeRegisterType, LookUpVarKindFunctor); |
1032 | void emitPrefillStackTDZVariables(const VariableEnvironment&, SymbolTable*); |
1033 | RegisterID* emitGetParentScope(RegisterID* dst, RegisterID* scope); |
1034 | void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, bool isCaptured); |
1035 | void emitNewFunctionExpressionCommon(RegisterID*, FunctionMetadataNode*); |
1036 | |
1037 | bool isNewTargetUsedInInnerArrowFunction(); |
1038 | bool isArgumentsUsedInInnerArrowFunction(); |
1039 | |
1040 | void emitToThis(); |
1041 | |
1042 | RegisterID* emitMove(RegisterID* dst, RegisterID* src); |
1043 | |
1044 | bool canDoPeepholeOptimization() const { return m_lastOpcodeID != op_end; } |
1045 | |
1046 | public: |
1047 | bool isSuperUsedInInnerArrowFunction(); |
1048 | bool isSuperCallUsedInInnerArrowFunction(); |
1049 | bool isThisUsedInInnerArrowFunction(); |
1050 | void pushLexicalScope(VariableEnvironmentNode*, TDZCheckOptimization, NestedScopeType = NestedScopeType::IsNotNested, RegisterID** constantSymbolTableResult = nullptr, bool shouldInitializeBlockScopedFunctions = true); |
1051 | void popLexicalScope(VariableEnvironmentNode*); |
1052 | void prepareLexicalScopeForNextForLoopIteration(VariableEnvironmentNode*, RegisterID* loopSymbolTable); |
1053 | int labelScopeDepth() const; |
1054 | UnlinkedArrayProfile newArrayProfile(); |
1055 | |
1056 | private: |
1057 | ParserError generate(); |
1058 | Variable variableForLocalEntry(const Identifier&, const SymbolTableEntry&, int symbolTableConstantIndex, bool isLexicallyScoped); |
1059 | |
1060 | RegisterID* kill(RegisterID* dst) |
1061 | { |
1062 | m_staticPropertyAnalyzer.kill(dst); |
1063 | return dst; |
1064 | } |
1065 | |
1066 | void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); |
1067 | ALWAYS_INLINE void rewind(); |
1068 | |
1069 | void allocateAndEmitScope(); |
1070 | |
1071 | template<typename JumpOp> |
1072 | void setTargetForJumpInstruction(InstructionStream::MutableRef&, int target); |
1073 | |
1074 | using BigIntMapEntry = std::tuple<UniquedStringImpl*, uint8_t, bool>; |
1075 | |
1076 | using NumberMap = HashMap<double, JSValue>; |
1077 | using IdentifierStringMap = HashMap<UniquedStringImpl*, JSString*, IdentifierRepHash>; |
1078 | using IdentifierBigIntMap = HashMap<BigIntMapEntry, JSBigInt*>; |
1079 | using TemplateObjectDescriptorSet = HashSet<Ref<TemplateObjectDescriptor>>; |
1080 | using TemplateDescriptorMap = HashMap<uint64_t, JSTemplateObjectDescriptor*, WTF::IntHash<uint64_t>, WTF::UnsignedWithZeroKeyHashTraits<uint64_t>>; |
1081 | |
1082 | // Helper for emitCall() and emitConstruct(). This works because the set of |
1083 | // expected functions have identical behavior for both call and construct |
1084 | // (i.e. "Object()" is identical to "new Object()"). |
1085 | ExpectedFunction emitExpectedFunctionSnippet(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, Label& done); |
1086 | |
1087 | template<typename CallOp> |
1088 | RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); |
1089 | |
1090 | RegisterID* emitCallIterator(RegisterID* iterator, RegisterID* argument, ThrowableExpressionData*); |
1091 | |
1092 | // Initializes the stack form the parameter; does nothing for the symbol table. |
1093 | RegisterID* initializeNextParameter(); |
1094 | UniquedStringImpl* visibleNameForParameter(DestructuringPatternNode*); |
1095 | |
1096 | RegisterID& registerFor(VirtualRegister reg) |
1097 | { |
1098 | if (reg.isLocal()) |
1099 | return m_calleeLocals[reg.toLocal()]; |
1100 | |
1101 | if (reg.offset() == CallFrameSlot::callee) |
1102 | return m_calleeRegister; |
1103 | |
1104 | ASSERT(m_parameters.size()); |
1105 | return m_parameters[reg.toArgument()]; |
1106 | } |
1107 | |
1108 | bool hasConstant(const Identifier&) const; |
1109 | unsigned addConstant(const Identifier&); |
1110 | RegisterID* addConstantValue(JSValue, SourceCodeRepresentation = SourceCodeRepresentation::Other); |
1111 | RegisterID* addConstantEmptyValue(); |
1112 | |
1113 | UnlinkedFunctionExecutable* makeFunction(FunctionMetadataNode* metadata) |
1114 | { |
1115 | DerivedContextType newDerivedContextType = DerivedContextType::None; |
1116 | |
1117 | if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode, SourceParseMode::AsyncArrowFunctionBodyMode).contains(metadata->parseMode())) { |
1118 | if (constructorKind() == ConstructorKind::Extends || isDerivedConstructorContext()) |
1119 | newDerivedContextType = DerivedContextType::DerivedConstructorContext; |
1120 | else if (m_codeBlock->isClassContext() || isDerivedClassContext()) |
1121 | newDerivedContextType = DerivedContextType::DerivedMethodContext; |
1122 | } |
1123 | |
1124 | Optional<CompactVariableMap::Handle> optionalVariablesUnderTDZ = getVariablesUnderTDZ(); |
1125 | |
1126 | // FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized. |
1127 | // https://bugs.webkit.org/show_bug.cgi?id=151547 |
1128 | SourceParseMode parseMode = metadata->parseMode(); |
1129 | ConstructAbility constructAbility = constructAbilityForParseMode(parseMode); |
1130 | if (parseMode == SourceParseMode::MethodMode && metadata->constructorKind() != ConstructorKind::None) |
1131 | constructAbility = ConstructAbility::CanConstruct; |
1132 | |
1133 | return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType); |
1134 | } |
1135 | |
1136 | Optional<CompactVariableMap::Handle> getVariablesUnderTDZ(); |
1137 | |
1138 | RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); |
1139 | template<typename CallOp> |
1140 | RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); |
1141 | |
1142 | void emitLogShadowChickenPrologueIfNecessary(); |
1143 | void emitLogShadowChickenTailIfNecessary(); |
1144 | |
1145 | void initializeParameters(FunctionParameters&); |
1146 | void initializeVarLexicalEnvironment(int symbolTableConstantIndex, SymbolTable* functionSymbolTable, bool hasCapturedVariables); |
1147 | void initializeDefaultParameterValuesAndSetupFunctionScopeStack(FunctionParameters&, bool isSimpleParameterList, FunctionNode*, SymbolTable*, int symbolTableConstantIndex, const ScopedLambda<bool (UniquedStringImpl*)>& captures, bool shouldCreateArgumentsVariableInParameterScope); |
1148 | void initializeArrowFunctionContextScopeIfNeeded(SymbolTable* functionSymbolTable = nullptr, bool canReuseLexicalEnvironment = false); |
1149 | bool needsDerivedConstructorInArrowFunctionLexicalEnvironment(); |
1150 | |
1151 | enum class TDZNecessityLevel { |
1152 | NotNeeded, |
1153 | Optimize, |
1154 | DoNotOptimize |
1155 | }; |
1156 | typedef HashMap<RefPtr<UniquedStringImpl>, TDZNecessityLevel, IdentifierRepHash> TDZMap; |
1157 | |
1158 | public: |
1159 | JSString* addStringConstant(const Identifier&); |
1160 | JSValue addBigIntConstant(const Identifier&, uint8_t radix, bool sign); |
1161 | RegisterID* addTemplateObjectConstant(Ref<TemplateObjectDescriptor>&&, int); |
1162 | |
1163 | const InstructionStream& instructions() const { return m_writer; } |
1164 | |
1165 | RegisterID* emitThrowExpressionTooDeepException(); |
1166 | |
1167 | class PreservedTDZStack { |
1168 | private: |
1169 | Vector<TDZMap> m_preservedTDZStack; |
1170 | friend class BytecodeGenerator; |
1171 | }; |
1172 | |
1173 | void preserveTDZStack(PreservedTDZStack&); |
1174 | void restoreTDZStack(const PreservedTDZStack&); |
1175 | |
1176 | template<typename Func> |
1177 | void withWriter(InstructionStreamWriter& writer, const Func& fn) |
1178 | { |
1179 | auto prevLastOpcodeID = m_lastOpcodeID; |
1180 | auto prevLastInstruction = m_lastInstruction; |
1181 | m_writer.swap(writer); |
1182 | m_lastOpcodeID = op_end; |
1183 | m_lastInstruction = m_writer.ref(); |
1184 | fn(); |
1185 | m_writer.swap(writer); |
1186 | m_lastOpcodeID = prevLastOpcodeID; |
1187 | m_lastInstruction = prevLastInstruction; |
1188 | } |
1189 | |
1190 | private: |
1191 | OptionSet<CodeGenerationMode> m_codeGenerationMode; |
1192 | |
1193 | struct LexicalScopeStackEntry { |
1194 | SymbolTable* m_symbolTable; |
1195 | RegisterID* m_scope; |
1196 | bool m_isWithScope; |
1197 | int m_symbolTableConstantIndex; |
1198 | }; |
1199 | Vector<LexicalScopeStackEntry> m_lexicalScopeStack; |
1200 | |
1201 | Vector<TDZMap> m_TDZStack; |
1202 | Optional<size_t> m_varScopeLexicalScopeStackIndex; |
1203 | void pushTDZVariables(const VariableEnvironment&, TDZCheckOptimization, TDZRequirement); |
1204 | |
1205 | ScopeNode* const m_scopeNode; |
1206 | |
1207 | // Some of these objects keep pointers to one another. They are arranged |
1208 | // to ensure a sane destruction order that avoids references to freed memory. |
1209 | HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> m_functions; |
1210 | RegisterID m_ignoredResultRegister; |
1211 | RegisterID m_thisRegister; |
1212 | RegisterID m_calleeRegister; |
1213 | RegisterID* m_scopeRegister { nullptr }; |
1214 | RegisterID* m_topMostScope { nullptr }; |
1215 | RegisterID* m_argumentsRegister { nullptr }; |
1216 | RegisterID* m_lexicalEnvironmentRegister { nullptr }; |
1217 | RegisterID* m_generatorRegister { nullptr }; |
1218 | RegisterID* m_emptyValueRegister { nullptr }; |
1219 | RegisterID* m_newTargetRegister { nullptr }; |
1220 | RegisterID* m_isDerivedConstuctor { nullptr }; |
1221 | HashMap<LinkTimeConstant, RegisterID*, WTF::IntHash<LinkTimeConstant>, WTF::StrongEnumHashTraits<LinkTimeConstant>> m_linkTimeConstantRegisters; |
1222 | RegisterID* m_arrowFunctionContextLexicalEnvironmentRegister { nullptr }; |
1223 | RegisterID* m_promiseRegister { nullptr }; |
1224 | |
1225 | FinallyContext* m_currentFinallyContext { nullptr }; |
1226 | |
1227 | SegmentedVector<RegisterID, 32> m_parameters; |
1228 | SegmentedVector<LabelScope, 32> m_labelScopes; |
1229 | SegmentedVector<RegisterID, 32> m_constantPoolRegisters; |
1230 | unsigned m_finallyDepth { 0 }; |
1231 | unsigned m_localScopeDepth { 0 }; |
1232 | const CodeType m_codeType; |
1233 | |
1234 | unsigned localScopeDepth() const; |
1235 | void pushLocalControlFlowScope(); |
1236 | void popLocalControlFlowScope(); |
1237 | |
1238 | // FIXME: Restore overflow checking with UnsafeVectorOverflow once SegmentVector supports it. |
1239 | // https://bugs.webkit.org/show_bug.cgi?id=165980 |
1240 | SegmentedVector<ControlFlowScope, 16> m_controlFlowScopeStack; |
1241 | Vector<SwitchInfo> m_switchContextStack; |
1242 | Vector<Ref<ForInContext>> m_forInContextStack; |
1243 | Vector<TryContext> m_tryContextStack; |
1244 | unsigned m_yieldPoints { 0 }; |
1245 | |
1246 | Strong<SymbolTable> m_generatorFrameSymbolTable; |
1247 | int m_generatorFrameSymbolTableIndex { 0 }; |
1248 | |
1249 | enum FunctionVariableType : uint8_t { NormalFunctionVariable, TopLevelFunctionVariable }; |
1250 | Vector<std::pair<FunctionMetadataNode*, FunctionVariableType>> m_functionsToInitialize; |
1251 | bool m_needToInitializeArguments { false }; |
1252 | RestParameterNode* m_restParameter { nullptr }; |
1253 | |
1254 | Vector<TryRange> m_tryRanges; |
1255 | SegmentedVector<TryData, 8> m_tryData; |
1256 | |
1257 | Vector<Ref<Label>> m_optionalChainTargetStack; |
1258 | |
1259 | int m_nextConstantOffset { 0 }; |
1260 | |
1261 | typedef HashMap<FunctionMetadataNode*, unsigned> FunctionOffsetMap; |
1262 | FunctionOffsetMap m_functionOffsets; |
1263 | |
1264 | // Constant pool |
1265 | IdentifierMap m_identifierMap; |
1266 | |
1267 | typedef HashMap<EncodedJSValueWithRepresentation, unsigned, EncodedJSValueWithRepresentationHash, EncodedJSValueWithRepresentationHashTraits> JSValueMap; |
1268 | JSValueMap m_jsValueMap; |
1269 | IdentifierStringMap m_stringMap; |
1270 | IdentifierBigIntMap m_bigIntMap; |
1271 | TemplateObjectDescriptorSet m_templateObjectDescriptorSet; |
1272 | TemplateDescriptorMap m_templateDescriptorMap; |
1273 | |
1274 | StaticPropertyAnalyzer m_staticPropertyAnalyzer; |
1275 | |
1276 | VM& m_vm; |
1277 | |
1278 | bool m_usesExceptions { false }; |
1279 | bool m_expressionTooDeep { false }; |
1280 | bool m_isBuiltinFunction { false }; |
1281 | bool m_usesNonStrictEval { false }; |
1282 | bool m_inTailPosition { false }; |
1283 | bool m_needsToUpdateArrowFunctionContext; |
1284 | bool m_hasCachedVariablesUnderTDZ { false }; |
1285 | DerivedContextType m_derivedContextType { DerivedContextType::None }; |
1286 | |
1287 | CompactVariableMap::Handle m_cachedVariablesUnderTDZ; |
1288 | |
1289 | struct CatchEntry { |
1290 | TryData* tryData; |
1291 | VirtualRegister exceptionRegister; |
1292 | VirtualRegister thrownValueRegister; |
1293 | VirtualRegister completionTypeRegister; |
1294 | }; |
1295 | Vector<CatchEntry> m_exceptionHandlersToEmit; |
1296 | }; |
1297 | |
1298 | } // namespace JSC |
1299 | |
1300 | namespace WTF { |
1301 | |
1302 | void printInternal(PrintStream&, JSC::Variable::VariableKind); |
1303 | |
1304 | } // namespace WTF |
1305 | |