2 * Copyright (C) 2008, 2009, 2012, 2013, 2014 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 "UnlinkedCodeBlock.h"
50 #include <wtf/PassRefPtr.h>
51 #include <wtf/SegmentedVector.h>
52 #include <wtf/Vector.h>
60 enum ExpectedFunction
{
62 ExpectObjectConstructor
,
63 ExpectArrayConstructor
68 CallArguments(BytecodeGenerator
&, ArgumentsNode
*, unsigned additionalArguments
= 0);
70 RegisterID
* thisRegister() { return m_argv
[0].get(); }
71 RegisterID
* argumentRegister(unsigned i
) { return m_argv
[i
+ 1].get(); }
72 unsigned stackOffset() { return -m_argv
[0]->index() + JSStack::CallFrameHeaderSize
; }
73 unsigned argumentCountIncludingThis() { return m_argv
.size() - m_padding
; }
74 RegisterID
* profileHookRegister() { return m_profileHookRegister
.get(); }
75 ArgumentsNode
* argumentsNode() { return m_argumentsNode
; }
78 RefPtr
<RegisterID
> m_profileHookRegister
;
79 ArgumentsNode
* m_argumentsNode
;
80 Vector
<RefPtr
<RegisterID
>, 8, UnsafeVectorOverflow
> m_argv
;
84 struct FinallyContext
{
85 StatementNode
* finallyBlock
;
86 unsigned scopeContextStackSize
;
87 unsigned switchContextStackSize
;
88 unsigned forInContextStackSize
;
89 unsigned tryContextStackSize
;
90 unsigned labelScopesSize
;
92 int dynamicScopeDepth
;
95 struct ControlFlowContext
{
97 FinallyContext finallyContext
;
100 struct ForInContext
{
101 RefPtr
<RegisterID
> expectedSubscriptRegister
;
102 RefPtr
<RegisterID
> iterRegister
;
103 RefPtr
<RegisterID
> indexRegister
;
104 RefPtr
<RegisterID
> propertyRegister
;
108 RefPtr
<Label
> target
;
109 unsigned targetScopeDepth
;
130 Local(RegisterID
* local
, unsigned attributes
, CaptureMode captureMode
)
132 , m_attributes(attributes
)
133 , m_isCaptured(captureMode
== IsCaptured
)
137 operator bool() { return m_local
; }
139 RegisterID
* get() { return m_local
; }
141 bool isReadOnly() { return m_attributes
& ReadOnly
; }
143 bool isCaptured() { return m_isCaptured
; }
144 CaptureMode
captureMode() { return isCaptured() ? IsCaptured
: NotCaptured
; }
148 unsigned m_attributes
;
158 class BytecodeGenerator
{
159 WTF_MAKE_FAST_ALLOCATED
;
161 typedef DeclarationStacks::VarStack VarStack
;
162 typedef DeclarationStacks::FunctionStack FunctionStack
;
164 BytecodeGenerator(VM
&, ProgramNode
*, UnlinkedProgramCodeBlock
*, DebuggerMode
, ProfilerMode
);
165 BytecodeGenerator(VM
&, FunctionBodyNode
*, UnlinkedFunctionCodeBlock
*, DebuggerMode
, ProfilerMode
);
166 BytecodeGenerator(VM
&, EvalNode
*, UnlinkedEvalCodeBlock
*, DebuggerMode
, ProfilerMode
);
168 ~BytecodeGenerator();
170 VM
* vm() const { return m_vm
; }
171 const CommonIdentifiers
& propertyNames() const { return *m_vm
->propertyNames
; }
173 bool isConstructor() { return m_codeBlock
->isConstructor(); }
175 ParserError
generate();
177 bool isArgumentNumber(const Identifier
&, int);
179 void setIsNumericCompareFunction(bool isNumericCompareFunction
);
181 bool willResolveToArguments(const Identifier
&);
182 RegisterID
* uncheckedRegisterForArguments();
184 bool isCaptured(int operand
);
185 CaptureMode
captureMode(int operand
) { return isCaptured(operand
) ? IsCaptured
: NotCaptured
; }
187 Local
local(const Identifier
&);
188 Local
constLocal(const Identifier
&);
190 // Returns the register storing "this"
191 RegisterID
* thisRegister() { return &m_thisRegister
; }
193 // Returns the next available temporary register. Registers returned by
194 // newTemporary require a modified form of reference counting: any
195 // register with a refcount of 0 is considered "available", meaning that
196 // the next instruction may overwrite it.
197 RegisterID
* newTemporary();
199 // The same as newTemporary(), but this function returns "suggestion" if
200 // "suggestion" is a temporary. This function is helpful in situations
201 // where you've put "suggestion" in a RefPtr, but you'd like to allow
202 // the next instruction to overwrite it anyway.
203 RegisterID
* newTemporaryOr(RegisterID
* suggestion
) { return suggestion
->isTemporary() ? suggestion
: newTemporary(); }
205 // Functions for handling of dst register
207 RegisterID
* ignoredResult() { return &m_ignoredResultRegister
; }
209 // Returns a place to write intermediate values of an operation
210 // which reuses dst if it is safe to do so.
211 RegisterID
* tempDestination(RegisterID
* dst
)
213 return (dst
&& dst
!= ignoredResult() && dst
->isTemporary()) ? dst
: newTemporary();
216 // Returns the place to write the final output of an operation.
217 RegisterID
* finalDestination(RegisterID
* originalDst
, RegisterID
* tempDst
= 0)
219 if (originalDst
&& originalDst
!= ignoredResult())
221 ASSERT(tempDst
!= ignoredResult());
222 if (tempDst
&& tempDst
->isTemporary())
224 return newTemporary();
227 RegisterID
* destinationForAssignResult(RegisterID
* dst
)
229 if (dst
&& dst
!= ignoredResult() && m_codeBlock
->needsFullScopeChain())
230 return dst
->isTemporary() ? dst
: newTemporary();
234 // Moves src to dst if dst is not null and is different from src, otherwise just returns src.
235 RegisterID
* moveToDestinationIfNeeded(RegisterID
* dst
, RegisterID
* src
)
237 return dst
== ignoredResult() ? 0 : (dst
&& dst
!= src
) ? emitMove(dst
, src
) : src
;
240 LabelScopePtr
newLabelScope(LabelScope::Type
, const Identifier
* = 0);
241 PassRefPtr
<Label
> newLabel();
243 void emitNode(RegisterID
* dst
, StatementNode
* n
)
245 // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
246 ASSERT(!dst
|| dst
== ignoredResult() || !dst
->isTemporary() || dst
->refCount());
247 // Should never store directly into a captured variable.
248 ASSERT(!dst
|| dst
== ignoredResult() || !isCaptured(dst
->index()));
249 if (!m_vm
->isSafeToRecurse()) {
250 emitThrowExpressionTooDeepException();
253 n
->emitBytecode(*this, dst
);
256 void emitNode(StatementNode
* n
)
261 RegisterID
* emitNode(RegisterID
* dst
, ExpressionNode
* n
)
263 // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary.
264 ASSERT(!dst
|| dst
== ignoredResult() || !dst
->isTemporary() || dst
->refCount());
265 // Should never store directly into a captured variable.
266 ASSERT(!dst
|| dst
== ignoredResult() || !isCaptured(dst
->index()));
267 if (!m_vm
->isSafeToRecurse())
268 return emitThrowExpressionTooDeepException();
269 return n
->emitBytecode(*this, dst
);
272 RegisterID
* emitNode(ExpressionNode
* n
)
274 return emitNode(0, n
);
277 void emitNodeInConditionContext(ExpressionNode
* n
, Label
* trueTarget
, Label
* falseTarget
, FallThroughMode fallThroughMode
)
279 if (!m_vm
->isSafeToRecurse()) {
280 emitThrowExpressionTooDeepException();
284 n
->emitBytecodeInConditionContext(*this, trueTarget
, falseTarget
, fallThroughMode
);
287 void emitExpressionInfo(const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
)
289 ASSERT(divot
.offset
>= divotStart
.offset
);
290 ASSERT(divotEnd
.offset
>= divot
.offset
);
292 int sourceOffset
= m_scopeNode
->source().startOffset();
293 unsigned firstLine
= m_scopeNode
->source().firstLine();
295 int divotOffset
= divot
.offset
- sourceOffset
;
296 int startOffset
= divot
.offset
- divotStart
.offset
;
297 int endOffset
= divotEnd
.offset
- divot
.offset
;
299 unsigned line
= divot
.line
;
300 ASSERT(line
>= firstLine
);
303 int lineStart
= divot
.lineStartOffset
;
304 if (lineStart
> sourceOffset
)
305 lineStart
-= sourceOffset
;
309 if (divotOffset
< lineStart
)
312 unsigned column
= divotOffset
- lineStart
;
314 unsigned instructionOffset
= instructions().size();
315 if (!m_isBuiltinFunction
)
316 m_codeBlock
->addExpressionInfo(instructionOffset
, divotOffset
, startOffset
, endOffset
, line
, column
);
319 ALWAYS_INLINE
bool leftHandSideNeedsCopy(bool rightHasAssignments
, bool rightIsPure
)
321 return (m_codeType
!= FunctionCode
|| m_codeBlock
->needsFullScopeChain() || rightHasAssignments
) && !rightIsPure
;
324 ALWAYS_INLINE PassRefPtr
<RegisterID
> emitNodeForLeftHandSide(ExpressionNode
* n
, bool rightHasAssignments
, bool rightIsPure
)
326 if (leftHandSideNeedsCopy(rightHasAssignments
, rightIsPure
)) {
327 PassRefPtr
<RegisterID
> dst
= newTemporary();
328 emitNode(dst
.get(), n
);
335 RegisterID
* emitLoad(RegisterID
* dst
, bool);
336 RegisterID
* emitLoad(RegisterID
* dst
, double);
337 RegisterID
* emitLoad(RegisterID
* dst
, const Identifier
&);
338 RegisterID
* emitLoad(RegisterID
* dst
, JSValue
);
339 RegisterID
* emitLoadGlobalObject(RegisterID
* dst
);
341 RegisterID
* emitUnaryOp(OpcodeID
, RegisterID
* dst
, RegisterID
* src
);
342 RegisterID
* emitBinaryOp(OpcodeID
, RegisterID
* dst
, RegisterID
* src1
, RegisterID
* src2
, OperandTypes
);
343 RegisterID
* emitEqualityOp(OpcodeID
, RegisterID
* dst
, RegisterID
* src1
, RegisterID
* src2
);
344 RegisterID
* emitUnaryNoDstOp(OpcodeID
, RegisterID
* src
);
346 RegisterID
* emitCreateThis(RegisterID
* dst
);
347 RegisterID
* emitNewObject(RegisterID
* dst
);
348 RegisterID
* emitNewArray(RegisterID
* dst
, ElementNode
*, unsigned length
); // stops at first elision
350 RegisterID
* emitNewFunction(RegisterID
* dst
, CaptureMode
, FunctionBodyNode
*);
351 RegisterID
* emitLazyNewFunction(RegisterID
* dst
, FunctionBodyNode
* body
);
352 RegisterID
* emitNewFunctionInternal(RegisterID
* dst
, CaptureMode
, unsigned index
, bool shouldNullCheck
);
353 RegisterID
* emitNewFunctionExpression(RegisterID
* dst
, FuncExprNode
* func
);
354 RegisterID
* emitNewRegExp(RegisterID
* dst
, RegExp
*);
356 RegisterID
* emitMove(RegisterID
* dst
, CaptureMode
, RegisterID
* src
);
357 RegisterID
* emitMove(RegisterID
* dst
, RegisterID
* src
);
359 RegisterID
* emitToNumber(RegisterID
* dst
, RegisterID
* src
) { return emitUnaryOp(op_to_number
, dst
, src
); }
360 RegisterID
* emitInc(RegisterID
* srcDst
);
361 RegisterID
* emitDec(RegisterID
* srcDst
);
363 void emitCheckHasInstance(RegisterID
* dst
, RegisterID
* value
, RegisterID
* base
, Label
* target
);
364 RegisterID
* emitInstanceOf(RegisterID
* dst
, RegisterID
* value
, RegisterID
* basePrototype
);
365 RegisterID
* emitTypeOf(RegisterID
* dst
, RegisterID
* src
) { return emitUnaryOp(op_typeof
, dst
, src
); }
366 RegisterID
* emitIn(RegisterID
* dst
, RegisterID
* property
, RegisterID
* base
) { return emitBinaryOp(op_in
, dst
, property
, base
, OperandTypes()); }
368 RegisterID
* emitInitGlobalConst(const Identifier
&, RegisterID
* value
);
370 RegisterID
* emitGetById(RegisterID
* dst
, RegisterID
* base
, const Identifier
& property
);
371 RegisterID
* emitGetArgumentsLength(RegisterID
* dst
, RegisterID
* base
);
372 RegisterID
* emitPutById(RegisterID
* base
, const Identifier
& property
, RegisterID
* value
);
373 RegisterID
* emitDirectPutById(RegisterID
* base
, const Identifier
& property
, RegisterID
* value
);
374 RegisterID
* emitDeleteById(RegisterID
* dst
, RegisterID
* base
, const Identifier
&);
375 RegisterID
* emitGetByVal(RegisterID
* dst
, RegisterID
* base
, RegisterID
* property
);
376 RegisterID
* emitGetArgumentByVal(RegisterID
* dst
, RegisterID
* base
, RegisterID
* property
);
377 RegisterID
* emitPutByVal(RegisterID
* base
, RegisterID
* property
, RegisterID
* value
);
378 RegisterID
* emitDirectPutByVal(RegisterID
* base
, RegisterID
* property
, RegisterID
* value
);
379 RegisterID
* emitDeleteByVal(RegisterID
* dst
, RegisterID
* base
, RegisterID
* property
);
380 RegisterID
* emitPutByIndex(RegisterID
* base
, unsigned index
, RegisterID
* value
);
381 void emitPutGetterSetter(RegisterID
* base
, const Identifier
& property
, RegisterID
* getter
, RegisterID
* setter
);
383 ExpectedFunction
expectedFunctionForIdentifier(const Identifier
&);
384 RegisterID
* emitCall(RegisterID
* dst
, RegisterID
* func
, ExpectedFunction
, CallArguments
&, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
385 RegisterID
* emitCallEval(RegisterID
* dst
, RegisterID
* func
, CallArguments
&, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
386 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
);
388 void emitEnumeration(ThrowableExpressionData
* enumerationNode
, ExpressionNode
* subjectNode
, const std::function
<void(BytecodeGenerator
&, RegisterID
*)>& callBack
);
390 RegisterID
* emitReturn(RegisterID
* src
);
391 RegisterID
* emitEnd(RegisterID
* src
) { return emitUnaryNoDstOp(op_end
, src
); }
393 RegisterID
* emitConstruct(RegisterID
* dst
, RegisterID
* func
, ExpectedFunction
, CallArguments
&, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
394 RegisterID
* emitStrcat(RegisterID
* dst
, RegisterID
* src
, int count
);
395 void emitToPrimitive(RegisterID
* dst
, RegisterID
* src
);
397 ResolveType
resolveType();
398 RegisterID
* emitResolveScope(RegisterID
* dst
, const Identifier
&);
399 RegisterID
* emitGetFromScope(RegisterID
* dst
, RegisterID
* scope
, const Identifier
&, ResolveMode
);
400 RegisterID
* emitPutToScope(RegisterID
* scope
, const Identifier
&, RegisterID
* value
, ResolveMode
);
402 PassRefPtr
<Label
> emitLabel(Label
*);
404 PassRefPtr
<Label
> emitJump(Label
* target
);
405 PassRefPtr
<Label
> emitJumpIfTrue(RegisterID
* cond
, Label
* target
);
406 PassRefPtr
<Label
> emitJumpIfFalse(RegisterID
* cond
, Label
* target
);
407 PassRefPtr
<Label
> emitJumpIfNotFunctionCall(RegisterID
* cond
, Label
* target
);
408 PassRefPtr
<Label
> emitJumpIfNotFunctionApply(RegisterID
* cond
, Label
* target
);
409 void emitPopScopes(int targetScopeDepth
);
411 RegisterID
* emitGetPropertyNames(RegisterID
* dst
, RegisterID
* base
, RegisterID
* i
, RegisterID
* size
, Label
* breakTarget
);
412 RegisterID
* emitNextPropertyName(RegisterID
* dst
, RegisterID
* base
, RegisterID
* i
, RegisterID
* size
, RegisterID
* iter
, Label
* target
);
414 void emitReadOnlyExceptionIfNeeded();
416 // Start a try block. 'start' must have been emitted.
417 TryData
* pushTry(Label
* start
);
418 // End a try block. 'end' must have been emitted.
419 RegisterID
* popTryAndEmitCatch(TryData
*, RegisterID
* targetRegister
, Label
* end
);
421 void emitThrow(RegisterID
* exc
)
423 m_usesExceptions
= true;
424 emitUnaryNoDstOp(op_throw
, exc
);
427 void emitThrowReferenceError(const String
& message
);
429 void emitPushFunctionNameScope(const Identifier
& property
, RegisterID
* value
, unsigned attributes
);
430 void emitPushCatchScope(const Identifier
& property
, RegisterID
* value
, unsigned attributes
);
432 RegisterID
* emitPushWithScope(RegisterID
* scope
);
435 void emitDebugHook(DebugHookID
, unsigned line
, unsigned charOffset
, unsigned lineStart
);
437 int scopeDepth() { return m_localScopeDepth
+ m_finallyDepth
; }
438 bool hasFinaliser() { return m_finallyDepth
!= 0; }
440 void pushFinallyContext(StatementNode
* finallyBlock
);
441 void popFinallyContext();
443 void pushOptimisedForIn(RegisterID
* expectedSubscript
, RegisterID
* iter
, RegisterID
* index
, RegisterID
* propertyRegister
)
445 ForInContext context
= { expectedSubscript
, iter
, index
, propertyRegister
};
446 m_forInContextStack
.append(context
);
449 void popOptimisedForIn()
451 m_forInContextStack
.removeLast();
454 LabelScopePtr
breakTarget(const Identifier
&);
455 LabelScopePtr
continueTarget(const Identifier
&);
457 void beginSwitch(RegisterID
*, SwitchInfo::SwitchType
);
458 void endSwitch(uint32_t clauseCount
, RefPtr
<Label
>*, ExpressionNode
**, Label
* defaultLabel
, int32_t min
, int32_t range
);
460 CodeType
codeType() const { return m_codeType
; }
462 bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks
; }
463 bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks
; }
465 bool isStrictMode() const { return m_codeBlock
->isStrictMode(); }
467 bool isBuiltinFunction() const { return m_isBuiltinFunction
; }
472 void emitOpcode(OpcodeID
);
473 UnlinkedArrayAllocationProfile
newArrayAllocationProfile();
474 UnlinkedObjectAllocationProfile
newObjectAllocationProfile();
475 UnlinkedArrayProfile
newArrayProfile();
476 UnlinkedValueProfile
emitProfiledOpcode(OpcodeID
);
477 int kill(RegisterID
* dst
)
479 int index
= dst
->index();
480 m_staticPropertyAnalyzer
.kill(index
);
484 void retrieveLastBinaryOp(int& dstIndex
, int& src1Index
, int& src2Index
);
485 void retrieveLastUnaryOp(int& dstIndex
, int& srcIndex
);
486 ALWAYS_INLINE
void rewindBinaryOp();
487 ALWAYS_INLINE
void rewindUnaryOp();
489 void emitComplexPopScopes(ControlFlowContext
* topScope
, ControlFlowContext
* bottomScope
);
491 typedef HashMap
<double, JSValue
> NumberMap
;
492 typedef HashMap
<StringImpl
*, JSString
*, IdentifierRepHash
> IdentifierStringMap
;
494 // Helper for emitCall() and emitConstruct(). This works because the set of
495 // expected functions have identical behavior for both call and construct
496 // (i.e. "Object()" is identical to "new Object()").
497 ExpectedFunction
emitExpectedFunctionSnippet(RegisterID
* dst
, RegisterID
* func
, ExpectedFunction
, CallArguments
&, Label
* done
);
499 RegisterID
* emitCall(OpcodeID
, RegisterID
* dst
, RegisterID
* func
, ExpectedFunction
, CallArguments
&, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
501 RegisterID
* newRegister();
503 // Adds a var slot and maps it to the name ident in symbolTable().
504 enum WatchMode
{ IsWatchable
, NotWatchable
};
505 RegisterID
* addVar(const Identifier
& ident
, ConstantMode constantMode
, WatchMode watchMode
)
508 addVar(ident
, constantMode
, watchMode
, local
);
512 // Ditto. Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used.
513 bool addVar(const Identifier
&, ConstantMode
, WatchMode
, RegisterID
*&);
515 // Adds an anonymous var slot. To give this slot a name, add it to symbolTable().
518 ++m_codeBlock
->m_numVars
;
519 return newRegister();
522 // Returns the index of the added var.
523 void addParameter(const Identifier
&, int parameterIndex
);
524 RegisterID
* resolveCallee(FunctionBodyNode
*);
525 void addCallee(FunctionBodyNode
*, RegisterID
*);
527 void preserveLastVar();
529 RegisterID
& registerFor(int index
)
531 if (operandIsLocal(index
))
532 return m_calleeRegisters
[VirtualRegister(index
).toLocal()];
534 if (index
== JSStack::Callee
)
535 return m_calleeRegister
;
537 ASSERT(m_parameters
.size());
538 return m_parameters
[VirtualRegister(index
).toArgument()];
541 unsigned addConstant(const Identifier
&);
542 RegisterID
* addConstantValue(JSValue
);
543 RegisterID
* addConstantEmptyValue();
544 unsigned addRegExp(RegExp
*);
546 unsigned addConstantBuffer(unsigned length
);
548 UnlinkedFunctionExecutable
* makeFunction(FunctionBodyNode
* body
)
550 return UnlinkedFunctionExecutable::create(m_vm
, m_scopeNode
->source(), body
, isBuiltinFunction() ? UnlinkedBuiltinFunction
: UnlinkedNormalFunction
);
553 RegisterID
* emitInitLazyRegister(RegisterID
*);
555 RegisterID
* emitConstructVarargs(RegisterID
* dst
, RegisterID
* func
, RegisterID
* arguments
, RegisterID
* firstFreeRegister
, int32_t firstVarArgOffset
, RegisterID
* profileHookRegister
, const JSTextPosition
& divot
, const JSTextPosition
& divotStart
, const JSTextPosition
& divotEnd
);
556 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
);
559 JSString
* addStringConstant(const Identifier
&);
561 Vector
<UnlinkedInstruction
, 0, UnsafeVectorOverflow
>& instructions() { return m_instructions
; }
563 SymbolTable
& symbolTable() { return *m_symbolTable
; }
565 bool shouldOptimizeLocals()
567 if (m_codeType
!= FunctionCode
)
570 if (m_localScopeDepth
)
576 bool canOptimizeNonLocals()
578 if (m_localScopeDepth
)
581 if (m_codeType
== EvalCode
)
584 if (m_codeType
== FunctionCode
&& m_codeBlock
->usesEval())
590 bool shouldTearOffArgumentsEagerly()
592 return m_codeType
== FunctionCode
&& isStrictMode() && m_scopeNode
->modifiesParameter();
595 RegisterID
* emitThrowExpressionTooDeepException();
597 void createArgumentsIfNecessary();
598 void createActivationIfNecessary();
599 RegisterID
* createLazyRegisterIfNecessary(RegisterID
*);
601 unsigned watchableVariable(int operand
)
603 VirtualRegister
reg(operand
);
606 if (static_cast<size_t>(reg
.toLocal()) >= m_watchableVariables
.size())
608 Identifier
& ident
= m_watchableVariables
[reg
.toLocal()];
611 return addConstant(ident
);
614 bool hasWatchableVariable(int operand
)
616 return watchableVariable(operand
) != UINT_MAX
;
619 Vector
<UnlinkedInstruction
, 0, UnsafeVectorOverflow
> m_instructions
;
621 bool m_shouldEmitDebugHooks
;
622 bool m_shouldEmitProfileHooks
;
624 SymbolTable
* m_symbolTable
;
626 ScopeNode
* m_scopeNode
;
627 Strong
<UnlinkedCodeBlock
> m_codeBlock
;
629 // Some of these objects keep pointers to one another. They are arranged
630 // to ensure a sane destruction order that avoids references to freed memory.
631 HashSet
<RefPtr
<StringImpl
>, IdentifierRepHash
> m_functions
;
632 RegisterID m_ignoredResultRegister
;
633 RegisterID m_thisRegister
;
634 RegisterID m_calleeRegister
;
635 RegisterID
* m_activationRegister
;
636 RegisterID
* m_emptyValueRegister
;
637 RegisterID
* m_globalObjectRegister
;
638 Vector
<Identifier
, 16> m_watchableVariables
;
639 SegmentedVector
<RegisterID
, 32> m_constantPoolRegisters
;
640 SegmentedVector
<RegisterID
, 32> m_calleeRegisters
;
641 SegmentedVector
<RegisterID
, 32> m_parameters
;
642 SegmentedVector
<Label
, 32> m_labels
;
643 LabelScopeStore m_labelScopes
;
644 RefPtr
<RegisterID
> m_lastVar
;
646 int m_localScopeDepth
;
649 Vector
<ControlFlowContext
, 0, UnsafeVectorOverflow
> m_scopeContextStack
;
650 Vector
<SwitchInfo
> m_switchContextStack
;
651 Vector
<ForInContext
> m_forInContextStack
;
652 Vector
<TryContext
> m_tryContextStack
;
653 Vector
<std::pair
<RefPtr
<RegisterID
>, const DeconstructionPatternNode
*>> m_deconstructedParameters
;
655 Vector
<TryRange
> m_tryRanges
;
656 SegmentedVector
<TryData
, 8> m_tryData
;
658 int m_firstConstantIndex
;
659 int m_nextConstantOffset
;
660 unsigned m_globalConstantIndex
;
662 int m_globalVarStorageOffset
;
664 int m_firstLazyFunction
;
665 int m_lastLazyFunction
;
666 HashMap
<unsigned int, FunctionBodyNode
*, WTF::IntHash
<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits
<unsigned int>> m_lazyFunctions
;
667 typedef HashMap
<FunctionBodyNode
*, unsigned> FunctionOffsetMap
;
668 FunctionOffsetMap m_functionOffsets
;
671 IdentifierMap m_identifierMap
;
672 JSValueMap m_jsValueMap
;
673 NumberMap m_numberMap
;
674 IdentifierStringMap m_stringMap
;
676 StaticPropertyAnalyzer m_staticPropertyAnalyzer
;
680 OpcodeID m_lastOpcodeID
;
682 size_t m_lastOpcodePosition
;
685 bool m_usesExceptions
;
686 bool m_expressionTooDeep
;
687 bool m_isBuiltinFunction
;
692 #endif // BytecodeGenerator_h