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