2 * Copyright (C) 2008, 2009, 2012-2015 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4 * Copyright (C) 2012 Igalia, S.L.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
31 #ifndef BytecodeGenerator_h
32 #define BytecodeGenerator_h
34 #include "CodeBlock.h"
35 #include <wtf/HashTraits.h>
36 #include "Instruction.h"
38 #include "LabelScope.h"
39 #include "Interpreter.h"
40 #include "ParserError.h"
41 #include "RegisterID.h"
42 #include "SymbolTable.h"
45 #include "StaticPropertyAnalyzer.h"
46 #include "TemplateRegistryKey.h"
47 #include "UnlinkedCodeBlock.h"
51 #include <wtf/PassRefPtr.h>
52 #include <wtf/SegmentedVector.h>
53 #include <wtf/Vector.h>
59 class JSTemplateRegistryKey
;
61 enum ExpectedFunction
{
63 ExpectObjectConstructor
,
64 ExpectArrayConstructor
69 CallArguments(BytecodeGenerator
&, ArgumentsNode
*, unsigned additionalArguments
= 0);
71 RegisterID
* thisRegister() { return m_argv
[0].get(); }
72 RegisterID
* argumentRegister(unsigned i
) { return m_argv
[i
+ 1].get(); }
73 unsigned stackOffset() { return -m_argv
[0]->index() + JSStack::CallFrameHeaderSize
; }
74 unsigned argumentCountIncludingThis() { return m_argv
.size() - m_padding
; }
75 RegisterID
* profileHookRegister() { return m_profileHookRegister
.get(); }
76 ArgumentsNode
* argumentsNode() { return m_argumentsNode
; }
79 RefPtr
<RegisterID
> m_profileHookRegister
;
80 ArgumentsNode
* m_argumentsNode
;
81 Vector
<RefPtr
<RegisterID
>, 8, UnsafeVectorOverflow
> m_argv
;
85 struct FinallyContext
{
86 StatementNode
* finallyBlock
;
88 ThrowableExpressionData
* enumerationNode
;
89 unsigned scopeContextStackSize
;
90 unsigned switchContextStackSize
;
91 unsigned forInContextStackSize
;
92 unsigned tryContextStackSize
;
93 unsigned labelScopesSize
;
95 int dynamicScopeDepth
;
98 struct ControlFlowContext
{
100 FinallyContext finallyContext
;
105 ForInContext(RegisterID
* localRegister
)
106 : m_localRegister(localRegister
)
111 virtual ~ForInContext()
115 bool isValid() const { return m_isValid
; }
116 void invalidate() { m_isValid
= false; }
118 enum ForInContextType
{
119 StructureForInContextType
,
120 IndexedForInContextType
122 virtual ForInContextType
type() const = 0;
124 RegisterID
* local() const { return m_localRegister
.get(); }
127 RefPtr
<RegisterID
> m_localRegister
;
131 class StructureForInContext
: public ForInContext
{
133 StructureForInContext(RegisterID
* localRegister
, RegisterID
* indexRegister
, RegisterID
* propertyRegister
, RegisterID
* enumeratorRegister
)
134 : ForInContext(localRegister
)
135 , m_indexRegister(indexRegister
)
136 , m_propertyRegister(propertyRegister
)
137 , m_enumeratorRegister(enumeratorRegister
)
141 virtual ForInContextType
type() const
143 return StructureForInContextType
;
146 RegisterID
* index() const { return m_indexRegister
.get(); }
147 RegisterID
* property() const { return m_propertyRegister
.get(); }
148 RegisterID
* enumerator() const { return m_enumeratorRegister
.get(); }
151 RefPtr
<RegisterID
> m_indexRegister
;
152 RefPtr
<RegisterID
> m_propertyRegister
;
153 RefPtr
<RegisterID
> m_enumeratorRegister
;
156 class IndexedForInContext
: public ForInContext
{
158 IndexedForInContext(RegisterID
* localRegister
, RegisterID
* indexRegister
)
159 : ForInContext(localRegister
)
160 , m_indexRegister(indexRegister
)
164 virtual ForInContextType
type() const
166 return IndexedForInContextType
;
169 RegisterID
* index() const { return m_indexRegister
.get(); }
172 RefPtr
<RegisterID
> m_indexRegister
;
176 RefPtr
<Label
> target
;
177 unsigned targetScopeDepth
;
178 HandlerType handlerType
;
188 enum VariableKind
{ NormalVariable
, SpecialVariable
};
194 , m_kind(NormalVariable
)
198 Variable(const Identifier
& ident
)
202 , m_kind(NormalVariable
) // This is somewhat meaningless here for this kind of Variable.
206 Variable(const Identifier
& ident
, VarOffset offset
, RegisterID
* local
, unsigned attributes
, VariableKind kind
)
210 , m_attributes(attributes
)
215 // If it's unset, then it is a non-locally-scoped variable. If it is set, then it could be
216 // a stack variable, a scoped variable in the local scope, or a variable captured in the
217 // direct arguments object.
218 bool isResolved() const { return !!m_offset
; }
220 const Identifier
& ident() const { return m_ident
; }
222 VarOffset
offset() const { return m_offset
; }
223 bool isLocal() const { return m_offset
.isStack(); }
224 RegisterID
* local() const { return m_local
; }
226 bool isReadOnly() const { return m_attributes
& ReadOnly
; }
227 bool isSpecial() const { return m_kind
!= NormalVariable
; }
233 unsigned m_attributes
;
243 enum ProfileTypeBytecodeFlag
{
244 ProfileTypeBytecodePutToScope
,
245 ProfileTypeBytecodeGetFromScope
,
246 ProfileTypeBytecodePutToLocalScope
,
247 ProfileTypeBytecodeGetFromLocalScope
,
248 ProfileTypeBytecodeHasGlobalID
,
249 ProfileTypeBytecodeDoesNotHaveGlobalID
,
250 ProfileTypeBytecodeFunctionArgument
,
251 ProfileTypeBytecodeFunctionReturnStatement
254 class BytecodeGenerator
{
255 WTF_MAKE_FAST_ALLOCATED
;
256 WTF_MAKE_NONCOPYABLE(BytecodeGenerator
);
258 typedef DeclarationStacks::VarStack VarStack
;
259 typedef DeclarationStacks::FunctionStack FunctionStack
;
261 BytecodeGenerator(VM
&, ProgramNode
*, UnlinkedProgramCodeBlock
*, DebuggerMode
, ProfilerMode
);
262 BytecodeGenerator(VM
&, FunctionNode
*, UnlinkedFunctionCodeBlock
*, DebuggerMode
, ProfilerMode
);
263 BytecodeGenerator(VM
&, EvalNode
*, UnlinkedEvalCodeBlock
*, DebuggerMode
, ProfilerMode
);
265 ~BytecodeGenerator();
267 VM
* vm() const { return m_vm
; }
268 ParserArena
& parserArena() const { return m_scopeNode
->parserArena(); }
269 const CommonIdentifiers
& propertyNames() const { return *m_vm
->propertyNames
; }
271 bool isConstructor() const { return m_codeBlock
->isConstructor(); }
272 #if ENABLE(ES6_CLASS_SYNTAX)
273 ConstructorKind
constructorKind() const { return m_codeBlock
->constructorKind(); }
275 ConstructorKind
constructorKind() const { return ConstructorKind::None
; }
278 ParserError
generate();
280 bool isArgumentNumber(const Identifier
&, int);
282 Variable
variable(const Identifier
&);
284 // Ignores the possibility of intervening scopes.
285 Variable
variablePerSymbolTable(const Identifier
&);
287 enum ExistingVariableMode
{ VerifyExisting
, IgnoreExisting
};
288 void createVariable(const Identifier
&, VarKind
, ConstantMode
, ExistingVariableMode
= VerifyExisting
); // Creates the variable, or asserts that the already-created variable is sufficiently compatible.
290 // Returns the register storing "this"
291 RegisterID
* thisRegister() { return &m_thisRegister
; }
292 RegisterID
* argumentsRegister() { return m_argumentsRegister
; }
293 RegisterID
* newTarget() { return m_newTargetRegister
; }
295 RegisterID
* scopeRegister() { return m_scopeRegister
; }
297 // Returns the next available temporary register. Registers returned by
298 // newTemporary require a modified form of reference counting: any
299 // register with a refcount of 0 is considered "available", meaning that
300 // the next instruction may overwrite it.
301 RegisterID
* newTemporary();
303 // The same as newTemporary(), but this function returns "suggestion" if
304 // "suggestion" is a temporary. This function is helpful in situations
305 // where you've put "suggestion" in a RefPtr, but you'd like to allow
306 // the next instruction to overwrite it anyway.
307 RegisterID
* newTemporaryOr(RegisterID
* suggestion
) { return suggestion
->isTemporary() ? suggestion
: newTemporary(); }
309 // Functions for handling of dst register
311 RegisterID
* ignoredResult() { return &m_ignoredResultRegister
; }
313 // Returns a place to write intermediate values of an operation
314 // which reuses dst if it is safe to do so.
315 RegisterID
* tempDestination(RegisterID
* dst
)
317 return (dst
&& dst
!= ignoredResult() && dst
->isTemporary()) ? dst
: newTemporary();
320 // Returns the place to write the final output of an operation.
321 RegisterID
* finalDestination(RegisterID
* originalDst
, RegisterID
* tempDst
= 0)
323 if (originalDst
&& originalDst
!= ignoredResult())
325 ASSERT(tempDst
!= ignoredResult());
326 if (tempDst
&& tempDst
->isTemporary())
328 return newTemporary();
331 RegisterID
* destinationForAssignResult(RegisterID
* dst
)
333 if (dst
&& dst
!= ignoredResult() && m_codeBlock
->needsFullScopeChain())
334 return dst
->isTemporary() ? dst
: newTemporary();
338 // Moves src to dst if dst is not null and is different from src, otherwise just returns src.
339 RegisterID
* moveToDestinationIfNeeded(RegisterID
* dst
, RegisterID
* src
)
341 return dst
== ignoredResult() ? 0 : (dst
&& dst
!= src
) ? emitMove(dst
, src
) : src
;
344 LabelScopePtr
newLabelScope(LabelScope::Type
, const Identifier
* = 0);
345 PassRefPtr
<Label
> newLabel();
347 void emitNode(RegisterID
* dst
, StatementNode
* n
)
349 // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
350 ASSERT(!dst
|| dst
== ignoredResult() || !dst
->isTemporary() || dst
->refCount());
351 if (!m_vm
->isSafeToRecurse()) {
352 emitThrowExpressionTooDeepException();
355 n
->emitBytecode(*this, dst
);
358 void emitNode(StatementNode
* n
)
363 RegisterID
* emitNode(RegisterID
* dst
, ExpressionNode
* n
)
365 // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
366 ASSERT(!dst
|| dst
== ignoredResult() || !dst
->isTemporary() || dst
->refCount());
367 if (!m_vm
->isSafeToRecurse())
368 return emitThrowExpressionTooDeepException();
369 return n
->emitBytecode(*this, dst
);
372 RegisterID
* emitNode(ExpressionNode
* n
)
374 return emitNode(0, n
);
377 void emitNodeInConditionContext(ExpressionNode
* n
, Label
* trueTarget
, Label
* falseTarget
, FallThroughMode fallThroughMode
)
379 if (!m_vm
->isSafeToRecurse()) {
380 emitThrowExpressionTooDeepException();
384 n
->emitBytecodeInConditionContext(*this, trueTarget
, falseTarget
, fallThroughMode
);
387 void emitExpressionInfo(const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
)
389 ASSERT(divot
.offset
>= divotStart
.offset
);
390 ASSERT(divotEnd
.offset
>= divot
.offset
);
392 int sourceOffset
= m_scopeNode
->source().startOffset();
393 unsigned firstLine
= m_scopeNode
->source().firstLine();
395 int divotOffset
= divot
.offset
- sourceOffset
;
396 int startOffset
= divot
.offset
- divotStart
.offset
;
397 int endOffset
= divotEnd
.offset
- divot
.offset
;
399 unsigned line
= divot
.line
;
400 ASSERT(line
>= firstLine
);
403 int lineStart
= divot
.lineStartOffset
;
404 if (lineStart
> sourceOffset
)
405 lineStart
-= sourceOffset
;
409 if (divotOffset
< lineStart
)
412 unsigned column
= divotOffset
- lineStart
;
414 unsigned instructionOffset
= instructions().size();
415 if (!m_isBuiltinFunction
)
416 m_codeBlock
->addExpressionInfo(instructionOffset
, divotOffset
, startOffset
, endOffset
, line
, column
);
420 ALWAYS_INLINE
bool leftHandSideNeedsCopy(bool rightHasAssignments
, bool rightIsPure
)
422 return (m_codeType
!= FunctionCode
|| m_codeBlock
->needsFullScopeChain() || rightHasAssignments
) && !rightIsPure
;
425 ALWAYS_INLINE PassRefPtr
<RegisterID
> emitNodeForLeftHandSide(ExpressionNode
* n
, bool rightHasAssignments
, bool rightIsPure
)
427 if (leftHandSideNeedsCopy(rightHasAssignments
, rightIsPure
)) {
428 PassRefPtr
<RegisterID
> dst
= newTemporary();
429 emitNode(dst
.get(), n
);
436 void emitTypeProfilerExpressionInfo(const JSTextPosition
& startDivot
, const JSTextPosition
& endDivot
);
437 void emitProfileType(RegisterID
* registerToProfile
, ProfileTypeBytecodeFlag
, const Identifier
*);
439 void emitProfileControlFlow(int);
441 RegisterID
* emitLoad(RegisterID
* dst
, bool);
442 RegisterID
* emitLoad(RegisterID
* dst
, const Identifier
&);
443 RegisterID
* emitLoad(RegisterID
* dst
, JSValue
, SourceCodeRepresentation
= SourceCodeRepresentation::Other
);
444 RegisterID
* emitLoadGlobalObject(RegisterID
* dst
);
446 RegisterID
* emitUnaryOp(OpcodeID
, RegisterID
* dst
, RegisterID
* src
);
447 RegisterID
* emitBinaryOp(OpcodeID
, RegisterID
* dst
, RegisterID
* src1
, RegisterID
* src2
, OperandTypes
);
448 RegisterID
* emitEqualityOp(OpcodeID
, RegisterID
* dst
, RegisterID
* src1
, RegisterID
* src2
);
449 RegisterID
* emitUnaryNoDstOp(OpcodeID
, RegisterID
* src
);
451 RegisterID
* emitCreateThis(RegisterID
* dst
);
452 void emitTDZCheck(RegisterID
* target
);
453 RegisterID
* emitNewObject(RegisterID
* dst
);
454 RegisterID
* emitNewArray(RegisterID
* dst
, ElementNode
*, unsigned length
); // stops at first elision
456 RegisterID
* emitNewFunction(RegisterID
* dst
, FunctionBodyNode
*);
457 RegisterID
* emitNewFunctionInternal(RegisterID
* dst
, unsigned index
);
458 RegisterID
* emitNewFunctionExpression(RegisterID
* dst
, FuncExprNode
* func
);
459 RegisterID
* emitNewDefaultConstructor(RegisterID
* dst
, ConstructorKind
, const Identifier
& name
);
460 RegisterID
* emitNewRegExp(RegisterID
* dst
, RegExp
*);
462 RegisterID
* emitMoveLinkTimeConstant(RegisterID
* dst
, LinkTimeConstant
);
463 RegisterID
* emitMoveEmptyValue(RegisterID
* dst
);
464 RegisterID
* emitMove(RegisterID
* dst
, RegisterID
* src
);
466 RegisterID
* emitToNumber(RegisterID
* dst
, RegisterID
* src
) { return emitUnaryOp(op_to_number
, dst
, src
); }
467 RegisterID
* emitToString(RegisterID
* dst
, RegisterID
* src
) { return emitUnaryOp(op_to_string
, dst
, src
); }
468 RegisterID
* emitInc(RegisterID
* srcDst
);
469 RegisterID
* emitDec(RegisterID
* srcDst
);
471 void emitCheckHasInstance(RegisterID
* dst
, RegisterID
* value
, RegisterID
* base
, Label
* target
);
472 RegisterID
* emitInstanceOf(RegisterID
* dst
, RegisterID
* value
, RegisterID
* basePrototype
);
473 RegisterID
* emitTypeOf(RegisterID
* dst
, RegisterID
* src
) { return emitUnaryOp(op_typeof
, dst
, src
); }
474 RegisterID
* emitIn(RegisterID
* dst
, RegisterID
* property
, RegisterID
* base
) { return emitBinaryOp(op_in
, dst
, property
, base
, OperandTypes()); }
476 RegisterID
* emitInitGlobalConst(const Identifier
&, RegisterID
* value
);
478 RegisterID
* emitGetById(RegisterID
* dst
, RegisterID
* base
, const Identifier
& property
);
479 RegisterID
* emitPutById(RegisterID
* base
, const Identifier
& property
, RegisterID
* value
);
480 RegisterID
* emitDirectPutById(RegisterID
* base
, const Identifier
& property
, RegisterID
* value
, PropertyNode::PutType
);
481 RegisterID
* emitDeleteById(RegisterID
* dst
, RegisterID
* base
, const Identifier
&);
482 RegisterID
* emitGetByVal(RegisterID
* dst
, RegisterID
* base
, RegisterID
* property
);
483 RegisterID
* emitGetArgumentByVal(RegisterID
* dst
, RegisterID
* base
, RegisterID
* property
);
484 RegisterID
* emitPutByVal(RegisterID
* base
, RegisterID
* property
, RegisterID
* value
);
485 RegisterID
* emitDirectPutByVal(RegisterID
* base
, RegisterID
* property
, RegisterID
* value
);
486 RegisterID
* emitDeleteByVal(RegisterID
* dst
, RegisterID
* base
, RegisterID
* property
);
487 RegisterID
* emitPutByIndex(RegisterID
* base
, unsigned index
, RegisterID
* value
);
489 void emitPutGetterById(RegisterID
* base
, const Identifier
& property
, RegisterID
* getter
);
490 void emitPutSetterById(RegisterID
* base
, const Identifier
& property
, RegisterID
* setter
);
491 void emitPutGetterSetter(RegisterID
* base
, const Identifier
& property
, RegisterID
* getter
, RegisterID
* setter
);
493 ExpectedFunction
expectedFunctionForIdentifier(const Identifier
&);
494 RegisterID
* emitCall(RegisterID
* dst
, RegisterID
* func
, ExpectedFunction
, CallArguments
&, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
495 RegisterID
* emitCallEval(RegisterID
* dst
, RegisterID
* func
, CallArguments
&, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
496 RegisterID
* emitCallVarargs(RegisterID
* dst
, RegisterID
* func
, RegisterID
* thisRegister
, RegisterID
* arguments
, RegisterID
* firstFreeRegister
, int32_t firstVarArgOffset
, RegisterID
* profileHookRegister
, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
498 enum PropertyDescriptorOption
{
499 PropertyConfigurable
= 1,
500 PropertyWritable
= 1 << 1,
501 PropertyEnumerable
= 1 << 2,
503 void emitCallDefineProperty(RegisterID
* newObj
, RegisterID
* propertyNameRegister
,
504 RegisterID
* valueRegister
, RegisterID
* getterRegister
, RegisterID
* setterRegister
, unsigned options
, const JSTextPosition
&);
506 void emitEnumeration(ThrowableExpressionData
* enumerationNode
, ExpressionNode
* subjectNode
, const std::function
<void(BytecodeGenerator
&, RegisterID
*)>& callBack
);
508 #if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
509 RegisterID
* emitGetTemplateObject(RegisterID
* dst
, TaggedTemplateNode
*);
512 RegisterID
* emitReturn(RegisterID
* src
);
513 RegisterID
* emitEnd(RegisterID
* src
) { return emitUnaryNoDstOp(op_end
, src
); }
515 RegisterID
* emitConstruct(RegisterID
* dst
, RegisterID
* func
, ExpectedFunction
, CallArguments
&, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
516 RegisterID
* emitStrcat(RegisterID
* dst
, RegisterID
* src
, int count
);
517 void emitToPrimitive(RegisterID
* dst
, RegisterID
* src
);
519 ResolveType
resolveType();
520 RegisterID
* emitResolveConstantLocal(RegisterID
* dst
, const Variable
&);
521 RegisterID
* emitResolveScope(RegisterID
* dst
, const Variable
&);
522 RegisterID
* emitGetFromScope(RegisterID
* dst
, RegisterID
* scope
, const Variable
&, ResolveMode
);
523 RegisterID
* emitPutToScope(RegisterID
* scope
, const Variable
&, RegisterID
* value
, ResolveMode
);
524 RegisterID
* initializeVariable(const Variable
&, RegisterID
* value
);
526 PassRefPtr
<Label
> emitLabel(Label
*);
528 PassRefPtr
<Label
> emitJump(Label
* target
);
529 PassRefPtr
<Label
> emitJumpIfTrue(RegisterID
* cond
, Label
* target
);
530 PassRefPtr
<Label
> emitJumpIfFalse(RegisterID
* cond
, Label
* target
);
531 PassRefPtr
<Label
> emitJumpIfNotFunctionCall(RegisterID
* cond
, Label
* target
);
532 PassRefPtr
<Label
> emitJumpIfNotFunctionApply(RegisterID
* cond
, Label
* target
);
533 void emitPopScopes(RegisterID
* srcDst
, int targetScopeDepth
);
535 RegisterID
* emitHasIndexedProperty(RegisterID
* dst
, RegisterID
* base
, RegisterID
* propertyName
);
536 RegisterID
* emitHasStructureProperty(RegisterID
* dst
, RegisterID
* base
, RegisterID
* propertyName
, RegisterID
* enumerator
);
537 RegisterID
* emitHasGenericProperty(RegisterID
* dst
, RegisterID
* base
, RegisterID
* propertyName
);
538 RegisterID
* emitGetPropertyEnumerator(RegisterID
* dst
, RegisterID
* base
);
539 RegisterID
* emitGetEnumerableLength(RegisterID
* dst
, RegisterID
* base
);
540 RegisterID
* emitGetStructurePropertyEnumerator(RegisterID
* dst
, RegisterID
* base
, RegisterID
* length
);
541 RegisterID
* emitGetGenericPropertyEnumerator(RegisterID
* dst
, RegisterID
* base
, RegisterID
* length
, RegisterID
* structureEnumerator
);
542 RegisterID
* emitEnumeratorStructurePropertyName(RegisterID
* dst
, RegisterID
* enumerator
, RegisterID
* index
);
543 RegisterID
* emitEnumeratorGenericPropertyName(RegisterID
* dst
, RegisterID
* enumerator
, RegisterID
* index
);
544 RegisterID
* emitToIndexString(RegisterID
* dst
, RegisterID
* index
);
546 RegisterID
* emitIsObject(RegisterID
* dst
, RegisterID
* src
);
547 RegisterID
* emitIsUndefined(RegisterID
* dst
, RegisterID
* src
);
549 RegisterID
* emitIteratorNext(RegisterID
* dst
, RegisterID
* iterator
, const ThrowableExpressionData
* node
);
550 void emitIteratorClose(RegisterID
* iterator
, const ThrowableExpressionData
* node
);
552 void emitReadOnlyExceptionIfNeeded();
554 // Start a try block. 'start' must have been emitted.
555 TryData
* pushTry(Label
* start
);
556 // End a try block. 'end' must have been emitted.
557 void popTryAndEmitCatch(TryData
*, RegisterID
* exceptionRegister
, RegisterID
* thrownValueRegister
, Label
* end
, HandlerType
);
559 void emitThrow(RegisterID
* exc
)
561 m_usesExceptions
= true;
562 emitUnaryNoDstOp(op_throw
, exc
);
565 void emitThrowReferenceError(const String
& message
);
566 void emitThrowTypeError(const String
& message
);
568 void emitPushFunctionNameScope(RegisterID
* dst
, const Identifier
& property
, RegisterID
* value
, unsigned attributes
);
569 void emitPushCatchScope(RegisterID
* dst
, const Identifier
& property
, RegisterID
* value
, unsigned attributes
);
572 RegisterID
* emitPushWithScope(RegisterID
* dst
, RegisterID
* scope
);
573 void emitPopScope(RegisterID
* srcDst
);
575 void emitDebugHook(DebugHookID
, unsigned line
, unsigned charOffset
, unsigned lineStart
);
577 int scopeDepth() { return m_localScopeDepth
+ m_finallyDepth
; }
578 bool hasFinaliser() { return m_finallyDepth
!= 0; }
580 void pushFinallyContext(StatementNode
* finallyBlock
);
581 void popFinallyContext();
582 void pushIteratorCloseContext(RegisterID
* iterator
, ThrowableExpressionData
* enumerationNode
);
583 void popIteratorCloseContext();
585 void pushIndexedForInScope(RegisterID
* local
, RegisterID
* index
);
586 void popIndexedForInScope(RegisterID
* local
);
587 void pushStructureForInScope(RegisterID
* local
, RegisterID
* index
, RegisterID
* property
, RegisterID
* enumerator
);
588 void popStructureForInScope(RegisterID
* local
);
589 void invalidateForInContextForLocal(RegisterID
* local
);
591 LabelScopePtr
breakTarget(const Identifier
&);
592 LabelScopePtr
continueTarget(const Identifier
&);
594 void beginSwitch(RegisterID
*, SwitchInfo::SwitchType
);
595 void endSwitch(uint32_t clauseCount
, RefPtr
<Label
>*, ExpressionNode
**, Label
* defaultLabel
, int32_t min
, int32_t range
);
597 CodeType
codeType() const { return m_codeType
; }
599 bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks
; }
600 bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks
; }
602 bool isStrictMode() const { return m_codeBlock
->isStrictMode(); }
604 bool isBuiltinFunction() const { return m_isBuiltinFunction
; }
606 OpcodeID
lastOpcodeID() const { return m_lastOpcodeID
; }
609 Variable
variableForLocalEntry(const Identifier
&, const SymbolTableEntry
&);
611 void emitOpcode(OpcodeID
);
612 UnlinkedArrayAllocationProfile
newArrayAllocationProfile();
613 UnlinkedObjectAllocationProfile
newObjectAllocationProfile();
614 UnlinkedArrayProfile
newArrayProfile();
615 UnlinkedValueProfile
emitProfiledOpcode(OpcodeID
);
616 int kill(RegisterID
* dst
)
618 int index
= dst
->index();
619 m_staticPropertyAnalyzer
.kill(index
);
623 void retrieveLastBinaryOp(int& dstIndex
, int& src1Index
, int& src2Index
);
624 void retrieveLastUnaryOp(int& dstIndex
, int& srcIndex
);
625 ALWAYS_INLINE
void rewindBinaryOp();
626 ALWAYS_INLINE
void rewindUnaryOp();
628 void allocateAndEmitScope();
629 void emitComplexPopScopes(RegisterID
*, ControlFlowContext
* topScope
, ControlFlowContext
* bottomScope
);
631 typedef HashMap
<double, JSValue
> NumberMap
;
632 typedef HashMap
<UniquedStringImpl
*, JSString
*, IdentifierRepHash
> IdentifierStringMap
;
633 typedef HashMap
<TemplateRegistryKey
, JSTemplateRegistryKey
*> TemplateRegistryKeyMap
;
635 // Helper for emitCall() and emitConstruct(). This works because the set of
636 // expected functions have identical behavior for both call and construct
637 // (i.e. "Object()" is identical to "new Object()").
638 ExpectedFunction
emitExpectedFunctionSnippet(RegisterID
* dst
, RegisterID
* func
, ExpectedFunction
, CallArguments
&, Label
* done
);
640 RegisterID
* emitCall(OpcodeID
, RegisterID
* dst
, RegisterID
* func
, ExpectedFunction
, CallArguments
&, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
642 RegisterID
* newRegister();
644 // Adds an anonymous local var slot. To give this slot a name, add it to symbolTable().
647 ++m_codeBlock
->m_numVars
;
648 RegisterID
* result
= newRegister();
649 ASSERT(VirtualRegister(result
->index()).toLocal() == m_codeBlock
->m_numVars
- 1);
650 result
->ref(); // We should never free this slot.
654 // Initializes the stack form the parameter; does nothing for the symbol table.
655 RegisterID
* initializeNextParameter();
656 UniquedStringImpl
* visibleNameForParameter(DestructuringPatternNode
*);
658 RegisterID
& registerFor(VirtualRegister reg
)
661 return m_calleeRegisters
[reg
.toLocal()];
663 if (reg
.offset() == JSStack::Callee
)
664 return m_calleeRegister
;
666 ASSERT(m_parameters
.size());
667 return m_parameters
[reg
.toArgument()];
670 bool hasConstant(const Identifier
&) const;
671 unsigned addConstant(const Identifier
&);
672 RegisterID
* addConstantValue(JSValue
, SourceCodeRepresentation
= SourceCodeRepresentation::Other
);
673 RegisterID
* addConstantEmptyValue();
674 unsigned addRegExp(RegExp
*);
676 unsigned addConstantBuffer(unsigned length
);
678 UnlinkedFunctionExecutable
* makeFunction(FunctionBodyNode
* body
)
680 return UnlinkedFunctionExecutable::create(m_vm
, m_scopeNode
->source(), body
, isBuiltinFunction() ? UnlinkedBuiltinFunction
: UnlinkedNormalFunction
);
683 RegisterID
* emitConstructVarargs(RegisterID
* dst
, RegisterID
* func
, RegisterID
* thisRegister
, RegisterID
* arguments
, RegisterID
* firstFreeRegister
, int32_t firstVarArgOffset
, RegisterID
* profileHookRegister
, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
684 RegisterID
* emitCallVarargs(OpcodeID
, RegisterID
* dst
, RegisterID
* func
, RegisterID
* thisRegister
, RegisterID
* arguments
, RegisterID
* firstFreeRegister
, int32_t firstVarArgOffset
, RegisterID
* profileHookRegister
, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
687 JSString
* addStringConstant(const Identifier
&);
688 JSTemplateRegistryKey
* addTemplateRegistryKeyConstant(const TemplateRegistryKey
&);
690 Vector
<UnlinkedInstruction
, 0, UnsafeVectorOverflow
>& instructions() { return m_instructions
; }
692 SymbolTable
& symbolTable() { return *m_symbolTable
; }
694 bool shouldOptimizeLocals()
696 if (m_codeType
!= FunctionCode
)
699 if (m_localScopeDepth
)
705 bool canOptimizeNonLocals()
707 if (m_localScopeDepth
)
710 if (m_codeType
== EvalCode
)
713 if (m_codeType
== FunctionCode
&& m_codeBlock
->usesEval())
719 RegisterID
* emitThrowExpressionTooDeepException();
722 Vector
<UnlinkedInstruction
, 0, UnsafeVectorOverflow
> m_instructions
;
724 bool m_shouldEmitDebugHooks
;
725 bool m_shouldEmitProfileHooks
;
727 SymbolTable
* m_symbolTable
{ nullptr };
729 ScopeNode
* const m_scopeNode
;
730 Strong
<UnlinkedCodeBlock
> m_codeBlock
;
732 // Some of these objects keep pointers to one another. They are arranged
733 // to ensure a sane destruction order that avoids references to freed memory.
734 HashSet
<RefPtr
<UniquedStringImpl
>, IdentifierRepHash
> m_functions
;
735 RegisterID m_ignoredResultRegister
;
736 RegisterID m_thisRegister
;
737 RegisterID m_calleeRegister
;
738 RegisterID
* m_scopeRegister
{ nullptr };
739 RegisterID
* m_argumentsRegister
{ nullptr };
740 RegisterID
* m_lexicalEnvironmentRegister
{ nullptr };
741 RegisterID
* m_emptyValueRegister
{ nullptr };
742 RegisterID
* m_globalObjectRegister
{ nullptr };
743 RegisterID
* m_newTargetRegister
{ nullptr };
744 RegisterID
* m_linkTimeConstantRegisters
[LinkTimeConstantCount
];
746 SegmentedVector
<RegisterID
, 32> m_constantPoolRegisters
;
747 SegmentedVector
<RegisterID
, 32> m_calleeRegisters
;
748 SegmentedVector
<RegisterID
, 32> m_parameters
;
749 SegmentedVector
<Label
, 32> m_labels
;
750 LabelScopeStore m_labelScopes
;
751 int m_finallyDepth
{ 0 };
752 int m_localScopeDepth
{ 0 };
753 const CodeType m_codeType
;
755 Vector
<ControlFlowContext
, 0, UnsafeVectorOverflow
> m_scopeContextStack
;
756 Vector
<SwitchInfo
> m_switchContextStack
;
757 Vector
<std::unique_ptr
<ForInContext
>> m_forInContextStack
;
758 Vector
<TryContext
> m_tryContextStack
;
759 Vector
<std::pair
<RefPtr
<RegisterID
>, const DestructuringPatternNode
*>> m_destructuringParameters
;
760 enum FunctionVariableType
: uint8_t { NormalFunctionVariable
, GlobalFunctionVariable
};
761 Vector
<std::pair
<FunctionBodyNode
*, FunctionVariableType
>> m_functionsToInitialize
;
762 bool m_needToInitializeArguments
{ false };
764 Vector
<TryRange
> m_tryRanges
;
765 SegmentedVector
<TryData
, 8> m_tryData
;
767 int m_nextConstantOffset
{ 0 };
769 typedef HashMap
<FunctionBodyNode
*, unsigned> FunctionOffsetMap
;
770 FunctionOffsetMap m_functionOffsets
;
773 IdentifierMap m_identifierMap
;
775 typedef HashMap
<EncodedJSValueWithRepresentation
, unsigned, EncodedJSValueWithRepresentationHash
, EncodedJSValueWithRepresentationHashTraits
> JSValueMap
;
776 JSValueMap m_jsValueMap
;
777 IdentifierStringMap m_stringMap
;
778 TemplateRegistryKeyMap m_templateRegistryKeyMap
;
780 StaticPropertyAnalyzer m_staticPropertyAnalyzer
{ &m_instructions
};
784 OpcodeID m_lastOpcodeID
= op_end
;
786 size_t m_lastOpcodePosition
{ 0 };
789 bool m_usesExceptions
{ false };
790 bool m_expressionTooDeep
{ false };
791 bool m_isBuiltinFunction
{ false };
796 #endif // BytecodeGenerator_h