2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "BytecodeGenerator.h"
33 #include "BatchedTransitionOptimizer.h"
34 #include "JSFunction.h"
35 #include "Interpreter.h"
36 #include "ScopeChain.h"
44 The layout of a register frame looks like this:
55 assuming (x) and (y) generated temporaries t1 and t2, you would have
57 ------------------------------------
58 | x | y | g | v2 | v1 | t1 | t2 | <-- value held
59 ------------------------------------
60 | -5 | -4 | -3 | -2 | -1 | +0 | +1 | <-- register index
61 ------------------------------------
62 | params->|<-locals | temps->
64 Because temporary registers are allocated in a stack-like fashion, we
65 can reclaim them with a simple popping algorithm. The same goes for labels.
66 (We never reclaim parameter or local registers, because parameters and
67 locals are DontDelete.)
69 The register layout before a function call looks like this:
79 > <------------------------------
80 < > reserved: call frame | 1 | <-- value held
81 > >snip< <------------------------------
82 < > +0 | +1 | +2 | +3 | +4 | +5 | <-- register index
83 > <------------------------------
84 | params->|<-locals | temps->
86 The call instruction fills in the "call frame" registers. It also pads
87 missing arguments at the end of the call:
89 > <-----------------------------------
90 < > reserved: call frame | 1 | ? | <-- value held ("?" stands for "undefined")
91 > >snip< <-----------------------------------
92 < > +0 | +1 | +2 | +3 | +4 | +5 | +6 | <-- register index
93 > <-----------------------------------
94 | params->|<-locals | temps->
96 After filling in missing arguments, the call instruction sets up the new
97 stack frame to overlap the end of the old stack frame:
99 |----------------------------------> <
100 | reserved: call frame | 1 | ? < > <-- value held ("?" stands for "undefined")
101 |----------------------------------> >snip< <
102 | -7 | -6 | -5 | -4 | -3 | -2 | -1 < > <-- register index
103 |----------------------------------> <
104 | | params->|<-locals | temps->
106 That way, arguments are "copied" into the callee's stack frame for free.
108 If the caller supplies too many arguments, this trick doesn't work. The
109 extra arguments protrude into space reserved for locals and temporaries.
110 In that case, the call instruction makes a real copy of the call frame header,
111 along with just the arguments expected by the callee, leaving the original
112 call frame header and arguments behind. (The call instruction can't just discard
113 extra arguments, because the "arguments" object may access them later.)
114 This copying strategy ensures that all named values will be at the indices
115 expected by the callee.
119 static bool s_dumpsGeneratedCode = false;
122 void BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode)
125 s_dumpsGeneratedCode = dumpsGeneratedCode;
127 UNUSED_PARAM(dumpsGeneratedCode);
131 bool BytecodeGenerator::dumpsGeneratedCode()
134 return s_dumpsGeneratedCode;
140 JSObject* BytecodeGenerator::generate()
142 m_codeBlock->setThisRegister(m_thisRegister.index());
144 m_scopeNode->emitBytecode(*this);
147 m_codeBlock->setInstructionCount(m_codeBlock->instructions().size());
149 if (s_dumpsGeneratedCode)
150 m_codeBlock->dump(m_scopeChain->globalObject->globalExec());
153 if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode)
154 symbolTable().clear();
156 m_codeBlock->shrinkToFit();
158 if (m_expressionTooDeep)
159 return createOutOfMemoryError(m_scopeChain->globalObject.get());
163 bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
165 int index = m_calleeRegisters.size();
166 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
167 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry);
169 if (!result.second) {
170 r0 = ®isterFor(result.first->second.getIndex());
178 int BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant)
180 int index = symbolTable().size();
181 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
182 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry);
184 index = result.first->second.getIndex();
188 void BytecodeGenerator::preserveLastVar()
190 if ((m_firstConstantIndex = m_calleeRegisters.size()) != 0)
191 m_lastVar = &m_calleeRegisters.last();
194 BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock, CompilationKind compilationKind)
195 : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
196 , m_shouldEmitProfileHooks(scopeChain->globalObject->supportsProfiling())
197 , m_shouldEmitRichSourceInfo(scopeChain->globalObject->supportsRichSourceInfo())
198 , m_scopeChain(*scopeChain->globalData, scopeChain)
199 , m_symbolTable(symbolTable)
200 , m_scopeNode(programNode)
201 , m_codeBlock(codeBlock)
202 , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
204 , m_dynamicScopeDepth(0)
205 , m_baseScopeDepth(0)
206 , m_codeType(GlobalCode)
207 , m_nextConstantOffset(0)
208 , m_globalConstantIndex(0)
209 , m_hasCreatedActivation(true)
210 , m_firstLazyFunction(0)
211 , m_lastLazyFunction(0)
212 , m_globalData(scopeChain->globalData)
213 , m_lastOpcodeID(op_end)
215 , m_lastOpcodePosition(0)
217 , m_stack(m_globalData->stack())
218 , m_usesExceptions(false)
219 , m_expressionTooDeep(false)
221 if (m_shouldEmitDebugHooks)
222 m_codeBlock->setNeedsFullScopeChain(true);
224 emitOpcode(op_enter);
225 codeBlock->setGlobalData(m_globalData);
227 // FIXME: Move code that modifies the global object to Interpreter::execute.
229 m_codeBlock->m_numParameters = 1; // Allocate space for "this"
230 codeBlock->m_numCapturedVars = codeBlock->m_numVars;
232 if (compilationKind == OptimizingCompilation)
235 JSGlobalObject* globalObject = scopeChain->globalObject.get();
236 ExecState* exec = globalObject->globalExec();
238 BatchedTransitionOptimizer optimizer(*m_globalData, globalObject);
240 const VarStack& varStack = programNode->varStack();
241 const FunctionStack& functionStack = programNode->functionStack();
243 size_t newGlobals = varStack.size() + functionStack.size();
246 globalObject->resizeRegisters(symbolTable->size() + newGlobals);
248 for (size_t i = 0; i < functionStack.size(); ++i) {
249 FunctionBodyNode* function = functionStack[i];
250 globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties.
252 JSValue value = JSFunction::create(exec, makeFunction(exec, function), scopeChain);
253 int index = addGlobalVar(function->ident(), false);
254 globalObject->registerAt(index).set(*m_globalData, globalObject, value);
257 for (size_t i = 0; i < varStack.size(); ++i) {
258 if (globalObject->hasProperty(exec, *varStack[i].first))
260 addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
264 BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainNode* scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, CompilationKind)
265 : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
266 , m_shouldEmitProfileHooks(scopeChain->globalObject->supportsProfiling())
267 , m_shouldEmitRichSourceInfo(scopeChain->globalObject->supportsRichSourceInfo())
268 , m_scopeChain(*scopeChain->globalData, scopeChain)
269 , m_symbolTable(symbolTable)
270 , m_scopeNode(functionBody)
271 , m_codeBlock(codeBlock)
272 , m_activationRegister(0)
274 , m_dynamicScopeDepth(0)
275 , m_baseScopeDepth(0)
276 , m_codeType(FunctionCode)
277 , m_nextConstantOffset(0)
278 , m_globalConstantIndex(0)
279 , m_hasCreatedActivation(false)
280 , m_firstLazyFunction(0)
281 , m_lastLazyFunction(0)
282 , m_globalData(scopeChain->globalData)
283 , m_lastOpcodeID(op_end)
285 , m_lastOpcodePosition(0)
287 , m_stack(m_globalData->stack())
288 , m_usesExceptions(false)
289 , m_expressionTooDeep(false)
291 if (m_shouldEmitDebugHooks)
292 m_codeBlock->setNeedsFullScopeChain(true);
294 codeBlock->setGlobalData(m_globalData);
296 emitOpcode(op_enter);
297 if (m_codeBlock->needsFullScopeChain()) {
298 m_activationRegister = addVar();
299 emitInitLazyRegister(m_activationRegister);
300 m_codeBlock->setActivationRegister(m_activationRegister->index());
303 // Both op_tear_off_activation and op_tear_off_arguments tear off the 'arguments'
304 // object, if created.
305 if (m_codeBlock->needsFullScopeChain() || functionBody->usesArguments()) {
306 RegisterID* unmodifiedArgumentsRegister = addVar(); // Anonymous, so it can't be modified by user code.
307 RegisterID* argumentsRegister = addVar(propertyNames().arguments, false); // Can be changed by assigning to 'arguments'.
309 // We can save a little space by hard-coding the knowledge that the two
310 // 'arguments' values are stored in consecutive registers, and storing
311 // only the index of the assignable one.
312 codeBlock->setArgumentsRegister(argumentsRegister->index());
313 ASSERT_UNUSED(unmodifiedArgumentsRegister, unmodifiedArgumentsRegister->index() == JSC::unmodifiedArgumentsRegister(codeBlock->argumentsRegister()));
315 emitInitLazyRegister(argumentsRegister);
316 emitInitLazyRegister(unmodifiedArgumentsRegister);
318 if (m_codeBlock->isStrictMode()) {
319 emitOpcode(op_create_arguments);
320 instructions().append(argumentsRegister->index());
323 // The debugger currently retrieves the arguments object from an activation rather than pulling
324 // it from a call frame. In the long-term it should stop doing that (<rdar://problem/6911886>),
325 // but for now we force eager creation of the arguments object when debugging.
326 if (m_shouldEmitDebugHooks) {
327 emitOpcode(op_create_arguments);
328 instructions().append(argumentsRegister->index());
332 const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack();
333 const DeclarationStacks::VarStack& varStack = functionBody->varStack();
335 // Captured variables and functions go first so that activations don't have
336 // to step over the non-captured locals to mark them.
337 m_hasCreatedActivation = false;
338 if (functionBody->hasCapturedVariables()) {
339 for (size_t i = 0; i < functionStack.size(); ++i) {
340 FunctionBodyNode* function = functionStack[i];
341 const Identifier& ident = function->ident();
342 if (functionBody->captures(ident)) {
343 if (!m_hasCreatedActivation) {
344 m_hasCreatedActivation = true;
345 emitOpcode(op_create_activation);
346 instructions().append(m_activationRegister->index());
348 m_functions.add(ident.impl());
349 emitNewFunction(addVar(ident, false), function);
352 for (size_t i = 0; i < varStack.size(); ++i) {
353 const Identifier& ident = *varStack[i].first;
354 if (functionBody->captures(ident))
355 addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
358 bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks;
359 if (!canLazilyCreateFunctions && !m_hasCreatedActivation) {
360 m_hasCreatedActivation = true;
361 emitOpcode(op_create_activation);
362 instructions().append(m_activationRegister->index());
365 codeBlock->m_numCapturedVars = codeBlock->m_numVars;
366 m_firstLazyFunction = codeBlock->m_numVars;
367 for (size_t i = 0; i < functionStack.size(); ++i) {
368 FunctionBodyNode* function = functionStack[i];
369 const Identifier& ident = function->ident();
370 if (!functionBody->captures(ident)) {
371 m_functions.add(ident.impl());
372 RefPtr<RegisterID> reg = addVar(ident, false);
373 // Don't lazily create functions that override the name 'arguments'
374 // as this would complicate lazy instantiation of actual arguments.
375 if (!canLazilyCreateFunctions || ident == propertyNames().arguments)
376 emitNewFunction(reg.get(), function);
378 emitInitLazyRegister(reg.get());
379 m_lazyFunctions.set(reg->index(), function);
383 m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction;
384 for (size_t i = 0; i < varStack.size(); ++i) {
385 const Identifier& ident = *varStack[i].first;
386 if (!functionBody->captures(ident))
387 addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
390 if (m_shouldEmitDebugHooks)
391 codeBlock->m_numCapturedVars = codeBlock->m_numVars;
393 FunctionParameters& parameters = *functionBody->parameters();
394 size_t parameterCount = parameters.size();
395 int nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1;
396 m_parameters.grow(1 + parameterCount); // reserve space for "this"
398 // Add "this" as a parameter
399 m_thisRegister.setIndex(nextParameterIndex);
400 ++m_codeBlock->m_numParameters;
402 for (size_t i = 0; i < parameterCount; ++i)
403 addParameter(parameters[i], ++nextParameterIndex);
407 if (isConstructor()) {
408 RefPtr<RegisterID> func = newTemporary();
409 RefPtr<RegisterID> funcProto = newTemporary();
411 emitOpcode(op_get_callee);
412 instructions().append(func->index());
414 emitGetById(funcProto.get(), func.get(), globalData()->propertyNames->prototype);
416 emitOpcode(op_create_this);
417 instructions().append(m_thisRegister.index());
418 instructions().append(funcProto->index());
419 } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) {
420 emitOpcode(op_convert_this);
421 instructions().append(m_thisRegister.index());
425 BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock, CompilationKind)
426 : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
427 , m_shouldEmitProfileHooks(scopeChain->globalObject->supportsProfiling())
428 , m_shouldEmitRichSourceInfo(scopeChain->globalObject->supportsRichSourceInfo())
429 , m_scopeChain(*scopeChain->globalData, scopeChain)
430 , m_symbolTable(symbolTable)
431 , m_scopeNode(evalNode)
432 , m_codeBlock(codeBlock)
433 , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
435 , m_dynamicScopeDepth(0)
436 , m_baseScopeDepth(codeBlock->baseScopeDepth())
437 , m_codeType(EvalCode)
438 , m_nextConstantOffset(0)
439 , m_globalConstantIndex(0)
440 , m_hasCreatedActivation(true)
441 , m_firstLazyFunction(0)
442 , m_lastLazyFunction(0)
443 , m_globalData(scopeChain->globalData)
444 , m_lastOpcodeID(op_end)
446 , m_lastOpcodePosition(0)
448 , m_stack(m_globalData->stack())
449 , m_usesExceptions(false)
450 , m_expressionTooDeep(false)
452 if (m_shouldEmitDebugHooks || m_baseScopeDepth)
453 m_codeBlock->setNeedsFullScopeChain(true);
455 emitOpcode(op_enter);
456 codeBlock->setGlobalData(m_globalData);
457 m_codeBlock->m_numParameters = 1; // Allocate space for "this"
459 const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack();
460 for (size_t i = 0; i < functionStack.size(); ++i)
461 m_codeBlock->addFunctionDecl(makeFunction(m_globalData, functionStack[i]));
463 const DeclarationStacks::VarStack& varStack = evalNode->varStack();
464 unsigned numVariables = varStack.size();
465 Vector<Identifier> variables;
466 variables.reserveCapacity(numVariables);
467 for (size_t i = 0; i < numVariables; ++i)
468 variables.append(*varStack[i].first);
469 codeBlock->adoptVariables(variables);
470 codeBlock->m_numCapturedVars = codeBlock->m_numVars;
474 RegisterID* BytecodeGenerator::emitInitLazyRegister(RegisterID* reg)
476 emitOpcode(op_init_lazy_reg);
477 instructions().append(reg->index());
481 void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex)
483 // Parameters overwrite var declarations, but not function declarations.
484 StringImpl* rep = ident.impl();
485 if (!m_functions.contains(rep)) {
486 symbolTable().set(rep, parameterIndex);
487 RegisterID& parameter = registerFor(parameterIndex);
488 parameter.setIndex(parameterIndex);
491 // To maintain the calling convention, we have to allocate unique space for
492 // each parameter, even if the parameter doesn't make it into the symbol table.
493 ++m_codeBlock->m_numParameters;
496 RegisterID* BytecodeGenerator::registerFor(const Identifier& ident)
498 if (ident == propertyNames().thisIdentifier)
499 return &m_thisRegister;
501 if (m_codeType == GlobalCode)
504 if (!shouldOptimizeLocals())
507 SymbolTableEntry entry = symbolTable().get(ident.impl());
511 if (ident == propertyNames().arguments)
512 createArgumentsIfNecessary();
514 return createLazyRegisterIfNecessary(®isterFor(entry.getIndex()));
517 RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident)
519 if (m_codeType == EvalCode)
522 if (m_codeType == GlobalCode)
525 SymbolTableEntry entry = symbolTable().get(ident.impl());
529 return createLazyRegisterIfNecessary(®isterFor(entry.getIndex()));
532 bool BytecodeGenerator::willResolveToArguments(const Identifier& ident)
534 if (ident != propertyNames().arguments)
537 if (!shouldOptimizeLocals())
540 SymbolTableEntry entry = symbolTable().get(ident.impl());
544 if (m_codeBlock->usesArguments() && m_codeType == FunctionCode)
550 RegisterID* BytecodeGenerator::uncheckedRegisterForArguments()
552 ASSERT(willResolveToArguments(propertyNames().arguments));
554 SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.impl());
555 ASSERT(!entry.isNull());
556 return ®isterFor(entry.getIndex());
559 RegisterID* BytecodeGenerator::createLazyRegisterIfNecessary(RegisterID* reg)
561 if (m_lastLazyFunction <= reg->index() || reg->index() < m_firstLazyFunction)
563 emitLazyNewFunction(reg, m_lazyFunctions.get(reg->index()));
567 bool BytecodeGenerator::isLocal(const Identifier& ident)
569 if (ident == propertyNames().thisIdentifier)
572 return shouldOptimizeLocals() && symbolTable().contains(ident.impl());
575 bool BytecodeGenerator::isLocalConstant(const Identifier& ident)
577 return symbolTable().get(ident.impl()).isReadOnly();
580 RegisterID* BytecodeGenerator::newRegister()
582 m_calleeRegisters.append(m_calleeRegisters.size());
583 m_codeBlock->m_numCalleeRegisters = max<int>(m_codeBlock->m_numCalleeRegisters, m_calleeRegisters.size());
584 return &m_calleeRegisters.last();
587 RegisterID* BytecodeGenerator::newTemporary()
589 // Reclaim free register IDs.
590 while (m_calleeRegisters.size() && !m_calleeRegisters.last().refCount())
591 m_calleeRegisters.removeLast();
593 RegisterID* result = newRegister();
594 result->setTemporary();
598 RegisterID* BytecodeGenerator::highestUsedRegister()
600 size_t count = m_codeBlock->m_numCalleeRegisters;
601 while (m_calleeRegisters.size() < count)
603 return &m_calleeRegisters.last();
606 PassRefPtr<LabelScope> BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name)
608 // Reclaim free label scopes.
609 while (m_labelScopes.size() && !m_labelScopes.last().refCount())
610 m_labelScopes.removeLast();
612 // Allocate new label scope.
613 LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : PassRefPtr<Label>()); // Only loops have continue targets.
614 m_labelScopes.append(scope);
615 return &m_labelScopes.last();
618 PassRefPtr<Label> BytecodeGenerator::newLabel()
620 // Reclaim free label IDs.
621 while (m_labels.size() && !m_labels.last().refCount())
622 m_labels.removeLast();
624 // Allocate new label ID.
625 m_labels.append(m_codeBlock);
626 return &m_labels.last();
629 PassRefPtr<Label> BytecodeGenerator::emitLabel(Label* l0)
631 unsigned newLabelIndex = instructions().size();
632 l0->setLocation(newLabelIndex);
634 if (m_codeBlock->numberOfJumpTargets()) {
635 unsigned lastLabelIndex = m_codeBlock->lastJumpTarget();
636 ASSERT(lastLabelIndex <= newLabelIndex);
637 if (newLabelIndex == lastLabelIndex) {
638 // Peephole optimizations have already been disabled by emitting the last label
643 m_codeBlock->addJumpTarget(newLabelIndex);
645 // This disables peephole optimizations when an instruction is a jump target
646 m_lastOpcodeID = op_end;
650 void BytecodeGenerator::emitOpcode(OpcodeID opcodeID)
653 size_t opcodePosition = instructions().size();
654 ASSERT(opcodePosition - m_lastOpcodePosition == opcodeLength(m_lastOpcodeID) || m_lastOpcodeID == op_end);
655 m_lastOpcodePosition = opcodePosition;
657 instructions().append(globalData()->interpreter->getOpcode(opcodeID));
658 m_lastOpcodeID = opcodeID;
661 void BytecodeGenerator::emitLoopHint()
663 #if ENABLE(TIERED_COMPILATION)
664 emitOpcode(op_loop_hint);
668 void BytecodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
670 ASSERT(instructions().size() >= 4);
671 size_t size = instructions().size();
672 dstIndex = instructions().at(size - 3).u.operand;
673 src1Index = instructions().at(size - 2).u.operand;
674 src2Index = instructions().at(size - 1).u.operand;
677 void BytecodeGenerator::retrieveLastUnaryOp(int& dstIndex, int& srcIndex)
679 ASSERT(instructions().size() >= 3);
680 size_t size = instructions().size();
681 dstIndex = instructions().at(size - 2).u.operand;
682 srcIndex = instructions().at(size - 1).u.operand;
685 void ALWAYS_INLINE BytecodeGenerator::rewindBinaryOp()
687 ASSERT(instructions().size() >= 4);
688 instructions().shrink(instructions().size() - 4);
689 m_lastOpcodeID = op_end;
692 void ALWAYS_INLINE BytecodeGenerator::rewindUnaryOp()
694 ASSERT(instructions().size() >= 3);
695 instructions().shrink(instructions().size() - 3);
696 m_lastOpcodeID = op_end;
699 PassRefPtr<Label> BytecodeGenerator::emitJump(Label* target)
701 size_t begin = instructions().size();
702 emitOpcode(target->isForward() ? op_jmp : op_loop);
703 instructions().append(target->bind(begin, instructions().size()));
707 PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* target)
709 if (m_lastOpcodeID == op_less) {
714 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
716 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
719 size_t begin = instructions().size();
720 emitOpcode(target->isForward() ? op_jless : op_loop_if_less);
721 instructions().append(src1Index);
722 instructions().append(src2Index);
723 instructions().append(target->bind(begin, instructions().size()));
726 } else if (m_lastOpcodeID == op_lesseq) {
731 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
733 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
736 size_t begin = instructions().size();
737 emitOpcode(target->isForward() ? op_jlesseq : op_loop_if_lesseq);
738 instructions().append(src1Index);
739 instructions().append(src2Index);
740 instructions().append(target->bind(begin, instructions().size()));
743 } else if (m_lastOpcodeID == op_greater) {
748 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
750 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
753 size_t begin = instructions().size();
754 emitOpcode(target->isForward() ? op_jgreater : op_loop_if_greater);
755 instructions().append(src1Index);
756 instructions().append(src2Index);
757 instructions().append(target->bind(begin, instructions().size()));
760 } else if (m_lastOpcodeID == op_greatereq) {
765 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
767 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
770 size_t begin = instructions().size();
771 emitOpcode(target->isForward() ? op_jgreatereq : op_loop_if_greatereq);
772 instructions().append(src1Index);
773 instructions().append(src2Index);
774 instructions().append(target->bind(begin, instructions().size()));
777 } else if (m_lastOpcodeID == op_eq_null && target->isForward()) {
781 retrieveLastUnaryOp(dstIndex, srcIndex);
783 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
786 size_t begin = instructions().size();
787 emitOpcode(op_jeq_null);
788 instructions().append(srcIndex);
789 instructions().append(target->bind(begin, instructions().size()));
792 } else if (m_lastOpcodeID == op_neq_null && target->isForward()) {
796 retrieveLastUnaryOp(dstIndex, srcIndex);
798 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
801 size_t begin = instructions().size();
802 emitOpcode(op_jneq_null);
803 instructions().append(srcIndex);
804 instructions().append(target->bind(begin, instructions().size()));
809 size_t begin = instructions().size();
811 emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true);
812 instructions().append(cond->index());
813 instructions().append(target->bind(begin, instructions().size()));
817 PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* target)
819 if (m_lastOpcodeID == op_less && target->isForward()) {
824 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
826 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
829 size_t begin = instructions().size();
830 emitOpcode(op_jnless);
831 instructions().append(src1Index);
832 instructions().append(src2Index);
833 instructions().append(target->bind(begin, instructions().size()));
836 } else if (m_lastOpcodeID == op_lesseq && target->isForward()) {
841 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
843 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
846 size_t begin = instructions().size();
847 emitOpcode(op_jnlesseq);
848 instructions().append(src1Index);
849 instructions().append(src2Index);
850 instructions().append(target->bind(begin, instructions().size()));
853 } else if (m_lastOpcodeID == op_greater && target->isForward()) {
858 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
860 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
863 size_t begin = instructions().size();
864 emitOpcode(op_jngreater);
865 instructions().append(src1Index);
866 instructions().append(src2Index);
867 instructions().append(target->bind(begin, instructions().size()));
870 } else if (m_lastOpcodeID == op_greatereq && target->isForward()) {
875 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
877 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
880 size_t begin = instructions().size();
881 emitOpcode(op_jngreatereq);
882 instructions().append(src1Index);
883 instructions().append(src2Index);
884 instructions().append(target->bind(begin, instructions().size()));
887 } else if (m_lastOpcodeID == op_not) {
891 retrieveLastUnaryOp(dstIndex, srcIndex);
893 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
896 size_t begin = instructions().size();
897 emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true);
898 instructions().append(srcIndex);
899 instructions().append(target->bind(begin, instructions().size()));
902 } else if (m_lastOpcodeID == op_eq_null && target->isForward()) {
906 retrieveLastUnaryOp(dstIndex, srcIndex);
908 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
911 size_t begin = instructions().size();
912 emitOpcode(op_jneq_null);
913 instructions().append(srcIndex);
914 instructions().append(target->bind(begin, instructions().size()));
917 } else if (m_lastOpcodeID == op_neq_null && target->isForward()) {
921 retrieveLastUnaryOp(dstIndex, srcIndex);
923 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
926 size_t begin = instructions().size();
927 emitOpcode(op_jeq_null);
928 instructions().append(srcIndex);
929 instructions().append(target->bind(begin, instructions().size()));
934 size_t begin = instructions().size();
935 emitOpcode(target->isForward() ? op_jfalse : op_loop_if_false);
936 instructions().append(cond->index());
937 instructions().append(target->bind(begin, instructions().size()));
941 PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(RegisterID* cond, Label* target)
943 size_t begin = instructions().size();
945 emitOpcode(op_jneq_ptr);
946 instructions().append(cond->index());
947 instructions().append(Instruction(*m_globalData, m_codeBlock->ownerExecutable(), m_scopeChain->globalObject->callFunction()));
948 instructions().append(target->bind(begin, instructions().size()));
952 PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond, Label* target)
954 size_t begin = instructions().size();
956 emitOpcode(op_jneq_ptr);
957 instructions().append(cond->index());
958 instructions().append(Instruction(*m_globalData, m_codeBlock->ownerExecutable(), m_scopeChain->globalObject->applyFunction()));
959 instructions().append(target->bind(begin, instructions().size()));
963 unsigned BytecodeGenerator::addConstant(const Identifier& ident)
965 StringImpl* rep = ident.impl();
966 pair<IdentifierMap::iterator, bool> result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers());
967 if (result.second) // new entry
968 m_codeBlock->addIdentifier(Identifier(m_globalData, rep));
970 return result.first->second;
973 RegisterID* BytecodeGenerator::addConstantValue(JSValue v)
975 int index = m_nextConstantOffset;
977 pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(JSValue::encode(v), m_nextConstantOffset);
979 m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset);
980 ++m_nextConstantOffset;
981 m_codeBlock->addConstant(JSValue(v));
983 index = result.first->second;
985 return &m_constantPoolRegisters[index];
988 unsigned BytecodeGenerator::addRegExp(RegExp* r)
990 return m_codeBlock->addRegExp(r);
993 RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
996 instructions().append(dst->index());
997 instructions().append(src->index());
1001 RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src)
1003 emitOpcode(opcodeID);
1004 instructions().append(dst->index());
1005 instructions().append(src->index());
1009 RegisterID* BytecodeGenerator::emitPreInc(RegisterID* srcDst)
1011 emitOpcode(op_pre_inc);
1012 instructions().append(srcDst->index());
1016 RegisterID* BytecodeGenerator::emitPreDec(RegisterID* srcDst)
1018 emitOpcode(op_pre_dec);
1019 instructions().append(srcDst->index());
1023 RegisterID* BytecodeGenerator::emitPostInc(RegisterID* dst, RegisterID* srcDst)
1025 emitOpcode(op_post_inc);
1026 instructions().append(dst->index());
1027 instructions().append(srcDst->index());
1031 RegisterID* BytecodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst)
1033 emitOpcode(op_post_dec);
1034 instructions().append(dst->index());
1035 instructions().append(srcDst->index());
1039 RegisterID* BytecodeGenerator::emitBinaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types)
1041 emitOpcode(opcodeID);
1042 instructions().append(dst->index());
1043 instructions().append(src1->index());
1044 instructions().append(src2->index());
1046 if (opcodeID == op_bitor || opcodeID == op_bitand || opcodeID == op_bitxor ||
1047 opcodeID == op_add || opcodeID == op_mul || opcodeID == op_sub || opcodeID == op_div)
1048 instructions().append(types.toInt());
1053 RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2)
1055 if (m_lastOpcodeID == op_typeof) {
1059 retrieveLastUnaryOp(dstIndex, srcIndex);
1061 if (src1->index() == dstIndex
1062 && src1->isTemporary()
1063 && m_codeBlock->isConstantRegisterIndex(src2->index())
1064 && m_codeBlock->constantRegister(src2->index()).get().isString()) {
1065 const UString& value = asString(m_codeBlock->constantRegister(src2->index()).get())->tryGetValue();
1066 if (value == "undefined") {
1068 emitOpcode(op_is_undefined);
1069 instructions().append(dst->index());
1070 instructions().append(srcIndex);
1073 if (value == "boolean") {
1075 emitOpcode(op_is_boolean);
1076 instructions().append(dst->index());
1077 instructions().append(srcIndex);
1080 if (value == "number") {
1082 emitOpcode(op_is_number);
1083 instructions().append(dst->index());
1084 instructions().append(srcIndex);
1087 if (value == "string") {
1089 emitOpcode(op_is_string);
1090 instructions().append(dst->index());
1091 instructions().append(srcIndex);
1094 if (value == "object") {
1096 emitOpcode(op_is_object);
1097 instructions().append(dst->index());
1098 instructions().append(srcIndex);
1101 if (value == "function") {
1103 emitOpcode(op_is_function);
1104 instructions().append(dst->index());
1105 instructions().append(srcIndex);
1111 emitOpcode(opcodeID);
1112 instructions().append(dst->index());
1113 instructions().append(src1->index());
1114 instructions().append(src2->index());
1118 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, bool b)
1120 return emitLoad(dst, jsBoolean(b));
1123 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, double number)
1125 // FIXME: Our hash tables won't hold infinity, so we make a new JSValue each time.
1126 // Later we can do the extra work to handle that like the other cases. They also don't
1127 // work correctly with NaN as a key.
1128 if (isnan(number) || number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number))
1129 return emitLoad(dst, jsNumber(number));
1130 JSValue& valueInMap = m_numberMap.add(number, JSValue()).first->second;
1132 valueInMap = jsNumber(number);
1133 return emitLoad(dst, valueInMap);
1136 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier)
1138 JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).first->second;
1140 stringInMap = jsOwnedString(globalData(), identifier.ustring());
1141 return emitLoad(dst, JSValue(stringInMap));
1144 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v)
1146 RegisterID* constantID = addConstantValue(v);
1148 return emitMove(dst, constantID);
1152 bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, bool& requiresDynamicChecks, JSObject*& globalObject)
1154 // Cases where we cannot statically optimize the lookup.
1155 if (property == propertyNames().arguments || !canOptimizeNonLocals()) {
1157 index = missingSymbolMarker();
1159 if (shouldOptimizeLocals() && m_codeType == GlobalCode) {
1160 ScopeChainIterator iter = m_scopeChain->begin();
1161 globalObject = iter->get();
1162 ASSERT((++iter) == m_scopeChain->end());
1168 requiresDynamicChecks = false;
1169 ScopeChainIterator iter = m_scopeChain->begin();
1170 ScopeChainIterator end = m_scopeChain->end();
1171 for (; iter != end; ++iter, ++depth) {
1172 JSObject* currentScope = iter->get();
1173 if (!currentScope->isVariableObject())
1175 JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
1176 SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl());
1178 // Found the property
1179 if (!entry.isNull()) {
1180 if (entry.isReadOnly() && forWriting) {
1182 index = missingSymbolMarker();
1184 globalObject = currentVariableObject;
1187 stackDepth = depth + m_codeBlock->needsFullScopeChain();
1188 index = entry.getIndex();
1190 globalObject = currentVariableObject;
1193 bool scopeRequiresDynamicChecks = false;
1194 if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks))
1196 requiresDynamicChecks |= scopeRequiresDynamicChecks;
1198 // Can't locate the property but we're able to avoid a few lookups.
1199 stackDepth = depth + m_codeBlock->needsFullScopeChain();
1200 index = missingSymbolMarker();
1201 JSObject* scope = iter->get();
1203 globalObject = scope;
1207 void BytecodeGenerator::emitCheckHasInstance(RegisterID* base)
1209 emitOpcode(op_check_has_instance);
1210 instructions().append(base->index());
1213 RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype)
1215 emitOpcode(op_instanceof);
1216 instructions().append(dst->index());
1217 instructions().append(value->index());
1218 instructions().append(base->index());
1219 instructions().append(basePrototype->index());
1223 static const unsigned maxGlobalResolves = 128;
1225 bool BytecodeGenerator::shouldAvoidResolveGlobal()
1227 return m_codeBlock->globalResolveInfoCount() > maxGlobalResolves && !m_labelScopes.size();
1230 RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
1234 JSObject* globalObject = 0;
1235 bool requiresDynamicChecks = false;
1236 if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) && !globalObject) {
1237 // We can't optimise at all :-(
1238 emitOpcode(op_resolve);
1239 instructions().append(dst->index());
1240 instructions().append(addConstant(property));
1243 if (shouldAvoidResolveGlobal()) {
1245 requiresDynamicChecks = true;
1249 if (index != missingSymbolMarker() && !requiresDynamicChecks) {
1250 // Directly index the property lookup across multiple scopes.
1251 return emitGetScopedVar(dst, depth, index, globalObject);
1255 m_codeBlock->addGlobalResolveInfo(instructions().size());
1257 #if ENABLE(INTERPRETER)
1258 m_codeBlock->addGlobalResolveInstruction(instructions().size());
1260 emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
1261 instructions().append(dst->index());
1262 instructions().append(addConstant(property));
1263 instructions().append(0);
1264 instructions().append(0);
1265 if (requiresDynamicChecks)
1266 instructions().append(depth);
1270 if (requiresDynamicChecks) {
1271 // If we get here we have eval nested inside a |with| just give up
1272 emitOpcode(op_resolve);
1273 instructions().append(dst->index());
1274 instructions().append(addConstant(property));
1278 if (index != missingSymbolMarker()) {
1279 // Directly index the property lookup across multiple scopes.
1280 return emitGetScopedVar(dst, depth, index, globalObject);
1283 // In this case we are at least able to drop a few scope chains from the
1284 // lookup chain, although we still need to hash from then on.
1285 emitOpcode(op_resolve_skip);
1286 instructions().append(dst->index());
1287 instructions().append(addConstant(property));
1288 instructions().append(depth);
1292 RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValue globalObject)
1295 if (m_lastOpcodeID == op_put_global_var) {
1298 retrieveLastUnaryOp(dstIndex, srcIndex);
1300 if (dstIndex == index && srcIndex == dst->index())
1304 emitOpcode(op_get_global_var);
1305 instructions().append(dst->index());
1306 instructions().append(index);
1310 emitOpcode(op_get_scoped_var);
1311 instructions().append(dst->index());
1312 instructions().append(index);
1313 instructions().append(depth);
1317 RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValue globalObject)
1320 emitOpcode(op_put_global_var);
1321 instructions().append(index);
1322 instructions().append(value->index());
1325 emitOpcode(op_put_scoped_var);
1326 instructions().append(index);
1327 instructions().append(depth);
1328 instructions().append(value->index());
1332 RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property)
1336 JSObject* globalObject = 0;
1337 bool requiresDynamicChecks = false;
1338 findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject);
1339 if (!globalObject || requiresDynamicChecks) {
1340 // We can't optimise at all :-(
1341 emitOpcode(op_resolve_base);
1342 instructions().append(dst->index());
1343 instructions().append(addConstant(property));
1344 instructions().append(false);
1348 // Global object is the base
1349 return emitLoad(dst, JSValue(globalObject));
1352 RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Identifier& property)
1354 if (!m_codeBlock->isStrictMode())
1355 return emitResolveBase(dst, property);
1358 JSObject* globalObject = 0;
1359 bool requiresDynamicChecks = false;
1360 findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject);
1361 if (!globalObject || requiresDynamicChecks) {
1362 // We can't optimise at all :-(
1363 emitOpcode(op_resolve_base);
1364 instructions().append(dst->index());
1365 instructions().append(addConstant(property));
1366 instructions().append(true);
1370 // Global object is the base
1371 RefPtr<RegisterID> result = emitLoad(dst, JSValue(globalObject));
1372 emitOpcode(op_ensure_property_exists);
1373 instructions().append(dst->index());
1374 instructions().append(addConstant(property));
1375 return result.get();
1378 RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
1382 JSObject* globalObject = 0;
1383 bool requiresDynamicChecks = false;
1384 if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) {
1385 // We can't optimise at all :-(
1386 emitOpcode(op_resolve_with_base);
1387 instructions().append(baseDst->index());
1388 instructions().append(propDst->index());
1389 instructions().append(addConstant(property));
1393 bool forceGlobalResolve = false;
1395 // Global object is the base
1396 emitLoad(baseDst, JSValue(globalObject));
1398 if (index != missingSymbolMarker() && !forceGlobalResolve) {
1399 // Directly index the property lookup across multiple scopes.
1400 emitGetScopedVar(propDst, depth, index, globalObject);
1403 if (shouldAvoidResolveGlobal()) {
1404 emitOpcode(op_resolve);
1405 instructions().append(propDst->index());
1406 instructions().append(addConstant(property));
1410 m_codeBlock->addGlobalResolveInfo(instructions().size());
1412 #if ENABLE(INTERPRETER)
1413 m_codeBlock->addGlobalResolveInstruction(instructions().size());
1415 emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
1416 instructions().append(propDst->index());
1417 instructions().append(addConstant(property));
1418 instructions().append(0);
1419 instructions().append(0);
1420 if (requiresDynamicChecks)
1421 instructions().append(depth);
1425 RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
1429 JSObject* globalObject = 0;
1430 bool requiresDynamicChecks = false;
1431 if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) {
1432 // We can't optimise at all :-(
1433 emitOpcode(op_resolve_with_this);
1434 instructions().append(baseDst->index());
1435 instructions().append(propDst->index());
1436 instructions().append(addConstant(property));
1440 bool forceGlobalResolve = false;
1442 // Global object is the base
1443 emitLoad(baseDst, jsUndefined());
1445 if (index != missingSymbolMarker() && !forceGlobalResolve) {
1446 // Directly index the property lookup across multiple scopes.
1447 emitGetScopedVar(propDst, depth, index, globalObject);
1450 if (shouldAvoidResolveGlobal()) {
1451 emitOpcode(op_resolve);
1452 instructions().append(propDst->index());
1453 instructions().append(addConstant(property));
1457 m_codeBlock->addGlobalResolveInfo(instructions().size());
1459 #if ENABLE(INTERPRETER)
1460 m_codeBlock->addGlobalResolveInstruction(instructions().size());
1462 emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
1463 instructions().append(propDst->index());
1464 instructions().append(addConstant(property));
1465 instructions().append(0);
1466 instructions().append(0);
1467 if (requiresDynamicChecks)
1468 instructions().append(depth);
1472 void BytecodeGenerator::emitMethodCheck()
1474 emitOpcode(op_method_check);
1477 RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
1479 #if ENABLE(INTERPRETER)
1480 m_codeBlock->addPropertyAccessInstruction(instructions().size());
1483 emitOpcode(op_get_by_id);
1484 instructions().append(dst->index());
1485 instructions().append(base->index());
1486 instructions().append(addConstant(property));
1487 instructions().append(0);
1488 instructions().append(0);
1489 instructions().append(0);
1490 instructions().append(0);
1494 RegisterID* BytecodeGenerator::emitGetArgumentsLength(RegisterID* dst, RegisterID* base)
1496 emitOpcode(op_get_arguments_length);
1497 instructions().append(dst->index());
1498 ASSERT(base->index() == m_codeBlock->argumentsRegister());
1499 instructions().append(base->index());
1500 instructions().append(addConstant(propertyNames().length));
1504 RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
1506 #if ENABLE(INTERPRETER)
1507 m_codeBlock->addPropertyAccessInstruction(instructions().size());
1510 emitOpcode(op_put_by_id);
1511 instructions().append(base->index());
1512 instructions().append(addConstant(property));
1513 instructions().append(value->index());
1514 instructions().append(0);
1515 instructions().append(0);
1516 instructions().append(0);
1517 instructions().append(0);
1518 instructions().append(0);
1522 RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value)
1524 #if ENABLE(INTERPRETER)
1525 m_codeBlock->addPropertyAccessInstruction(instructions().size());
1528 emitOpcode(op_put_by_id);
1529 instructions().append(base->index());
1530 instructions().append(addConstant(property));
1531 instructions().append(value->index());
1532 instructions().append(0);
1533 instructions().append(0);
1534 instructions().append(0);
1535 instructions().append(0);
1536 instructions().append(property != m_globalData->propertyNames->underscoreProto);
1540 RegisterID* BytecodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
1542 emitOpcode(op_put_getter);
1543 instructions().append(base->index());
1544 instructions().append(addConstant(property));
1545 instructions().append(value->index());
1549 RegisterID* BytecodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
1551 emitOpcode(op_put_setter);
1552 instructions().append(base->index());
1553 instructions().append(addConstant(property));
1554 instructions().append(value->index());
1558 RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
1560 emitOpcode(op_del_by_id);
1561 instructions().append(dst->index());
1562 instructions().append(base->index());
1563 instructions().append(addConstant(property));
1567 RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
1569 emitOpcode(op_get_argument_by_val);
1570 instructions().append(dst->index());
1571 ASSERT(base->index() == m_codeBlock->argumentsRegister());
1572 instructions().append(base->index());
1573 instructions().append(property->index());
1577 RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
1579 for (size_t i = m_forInContextStack.size(); i > 0; i--) {
1580 ForInContext& context = m_forInContextStack[i - 1];
1581 if (context.propertyRegister == property) {
1582 emitOpcode(op_get_by_pname);
1583 instructions().append(dst->index());
1584 instructions().append(base->index());
1585 instructions().append(property->index());
1586 instructions().append(context.expectedSubscriptRegister->index());
1587 instructions().append(context.iterRegister->index());
1588 instructions().append(context.indexRegister->index());
1592 emitOpcode(op_get_by_val);
1593 instructions().append(dst->index());
1594 instructions().append(base->index());
1595 instructions().append(property->index());
1599 RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
1601 emitOpcode(op_put_by_val);
1602 instructions().append(base->index());
1603 instructions().append(property->index());
1604 instructions().append(value->index());
1608 RegisterID* BytecodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
1610 emitOpcode(op_del_by_val);
1611 instructions().append(dst->index());
1612 instructions().append(base->index());
1613 instructions().append(property->index());
1617 RegisterID* BytecodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value)
1619 emitOpcode(op_put_by_index);
1620 instructions().append(base->index());
1621 instructions().append(index);
1622 instructions().append(value->index());
1626 RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst)
1628 emitOpcode(op_new_object);
1629 instructions().append(dst->index());
1633 unsigned BytecodeGenerator::addConstantBuffer(unsigned length)
1635 return m_codeBlock->addConstantBuffer(length);
1638 JSString* BytecodeGenerator::addStringConstant(const Identifier& identifier)
1640 JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).first->second;
1642 stringInMap = jsString(globalData(), identifier.ustring());
1643 addConstantValue(stringInMap);
1648 RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements, unsigned length)
1650 #if !ASSERT_DISABLED
1651 unsigned checkLength = 0;
1653 bool hadVariableExpression = false;
1655 for (ElementNode* n = elements; n; n = n->next()) {
1656 if (!n->value()->isNumber() && !n->value()->isString()) {
1657 hadVariableExpression = true;
1662 #if !ASSERT_DISABLED
1666 if (!hadVariableExpression) {
1667 ASSERT(length == checkLength);
1668 unsigned constantBufferIndex = addConstantBuffer(length);
1669 JSValue* constantBuffer = m_codeBlock->constantBuffer(constantBufferIndex);
1671 for (ElementNode* n = elements; index < length; n = n->next()) {
1672 if (n->value()->isNumber())
1673 constantBuffer[index++] = jsNumber(static_cast<NumberNode*>(n->value())->value());
1675 ASSERT(n->value()->isString());
1676 constantBuffer[index++] = addStringConstant(static_cast<StringNode*>(n->value())->value());
1679 emitOpcode(op_new_array_buffer);
1680 instructions().append(dst->index());
1681 instructions().append(constantBufferIndex);
1682 instructions().append(length);
1687 Vector<RefPtr<RegisterID>, 16> argv;
1688 for (ElementNode* n = elements; n; n = n->next()) {
1691 argv.append(newTemporary());
1692 // op_new_array requires the initial values to be a sequential range of registers
1693 ASSERT(argv.size() == 1 || argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1);
1694 emitNode(argv.last().get(), n->value());
1696 emitOpcode(op_new_array);
1697 instructions().append(dst->index());
1698 instructions().append(argv.size() ? argv[0]->index() : 0); // argv
1699 instructions().append(argv.size()); // argc
1703 RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function)
1705 return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)), false);
1708 RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* function)
1710 std::pair<FunctionOffsetMap::iterator, bool> ptr = m_functionOffsets.add(function, 0);
1712 ptr.first->second = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function));
1713 return emitNewFunctionInternal(dst, ptr.first->second, true);
1716 RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index, bool doNullCheck)
1718 createActivationIfNecessary();
1719 emitOpcode(op_new_func);
1720 instructions().append(dst->index());
1721 instructions().append(index);
1722 instructions().append(doNullCheck);
1726 RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
1728 emitOpcode(op_new_regexp);
1729 instructions().append(dst->index());
1730 instructions().append(addRegExp(regExp));
1734 RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
1736 FunctionBodyNode* function = n->body();
1737 unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function));
1739 createActivationIfNecessary();
1740 emitOpcode(op_new_func_exp);
1741 instructions().append(r0->index());
1742 instructions().append(index);
1746 RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
1748 return emitCall(op_call, dst, func, callArguments, divot, startOffset, endOffset);
1751 void BytecodeGenerator::createArgumentsIfNecessary()
1753 if (m_codeType != FunctionCode)
1756 if (!m_codeBlock->usesArguments())
1759 // If we're in strict mode we tear off the arguments on function
1760 // entry, so there's no need to check if we need to create them
1762 if (m_codeBlock->isStrictMode())
1765 emitOpcode(op_create_arguments);
1766 instructions().append(m_codeBlock->argumentsRegister());
1769 void BytecodeGenerator::createActivationIfNecessary()
1771 if (m_hasCreatedActivation)
1773 if (!m_codeBlock->needsFullScopeChain())
1775 emitOpcode(op_create_activation);
1776 instructions().append(m_activationRegister->index());
1779 RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
1781 return emitCall(op_call_eval, dst, func, callArguments, divot, startOffset, endOffset);
1784 RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
1786 ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
1787 ASSERT(func->refCount());
1789 if (m_shouldEmitProfileHooks)
1790 emitMove(callArguments.profileHookRegister(), func);
1792 // Generate code for arguments.
1793 unsigned argumentIndex = 0;
1794 for (ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; n; n = n->m_next)
1795 emitNode(callArguments.argumentRegister(argumentIndex++), n);
1797 // Reserve space for call frame.
1798 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
1799 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
1800 callFrame.append(newTemporary());
1802 if (m_shouldEmitProfileHooks) {
1803 emitOpcode(op_profile_will_call);
1804 instructions().append(callArguments.profileHookRegister()->index());
1807 emitExpressionInfo(divot, startOffset, endOffset);
1810 emitOpcode(opcodeID);
1811 instructions().append(func->index()); // func
1812 instructions().append(callArguments.count()); // argCount
1813 instructions().append(callArguments.callFrame()); // registerOffset
1814 if (dst != ignoredResult()) {
1815 emitOpcode(op_call_put_result);
1816 instructions().append(dst->index()); // dst
1819 if (m_shouldEmitProfileHooks) {
1820 emitOpcode(op_profile_did_call);
1821 instructions().append(callArguments.profileHookRegister()->index());
1827 RegisterID* BytecodeGenerator::emitLoadVarargs(RegisterID* argCountDst, RegisterID* thisRegister, RegisterID* arguments)
1829 ASSERT(argCountDst->index() < arguments->index());
1830 emitOpcode(op_load_varargs);
1831 instructions().append(argCountDst->index());
1832 instructions().append(arguments->index());
1833 instructions().append(thisRegister->index() + RegisterFile::CallFrameHeaderSize); // initial registerOffset
1837 RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* argCountRegister, unsigned divot, unsigned startOffset, unsigned endOffset)
1839 ASSERT(func->refCount());
1840 ASSERT(thisRegister->refCount());
1841 ASSERT(dst != func);
1842 if (m_shouldEmitProfileHooks) {
1843 emitOpcode(op_profile_will_call);
1844 instructions().append(func->index());
1847 emitExpressionInfo(divot, startOffset, endOffset);
1850 emitOpcode(op_call_varargs);
1851 instructions().append(func->index()); // func
1852 instructions().append(argCountRegister->index()); // arg count
1853 instructions().append(thisRegister->index() + RegisterFile::CallFrameHeaderSize); // initial registerOffset
1854 if (dst != ignoredResult()) {
1855 emitOpcode(op_call_put_result);
1856 instructions().append(dst->index()); // dst
1858 if (m_shouldEmitProfileHooks) {
1859 emitOpcode(op_profile_did_call);
1860 instructions().append(func->index());
1865 RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
1867 if (m_codeBlock->needsFullScopeChain()) {
1868 emitOpcode(op_tear_off_activation);
1869 instructions().append(m_activationRegister->index());
1870 instructions().append(m_codeBlock->argumentsRegister());
1871 } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1
1872 && !m_codeBlock->isStrictMode()) { // If there are no named parameters, there's nothing to tear off, since extra / unnamed parameters get copied to the arguments object at construct time.
1873 emitOpcode(op_tear_off_arguments);
1874 instructions().append(m_codeBlock->argumentsRegister());
1877 // Constructors use op_ret_object_or_this to check the result is an
1878 // object, unless we can trivially determine the check is not
1879 // necessary (currently, if the return value is 'this').
1880 if (isConstructor() && (src->index() != m_thisRegister.index())) {
1881 emitOpcode(op_ret_object_or_this);
1882 instructions().append(src->index());
1883 instructions().append(m_thisRegister.index());
1886 return emitUnaryNoDstOp(op_ret, src);
1889 RegisterID* BytecodeGenerator::emitUnaryNoDstOp(OpcodeID opcodeID, RegisterID* src)
1891 emitOpcode(opcodeID);
1892 instructions().append(src->index());
1896 RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
1898 ASSERT(func->refCount());
1900 if (m_shouldEmitProfileHooks)
1901 emitMove(callArguments.profileHookRegister(), func);
1903 // Generate code for arguments.
1904 unsigned argumentIndex = 0;
1905 if (ArgumentsNode* argumentsNode = callArguments.argumentsNode()) {
1906 for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next)
1907 emitNode(callArguments.argumentRegister(argumentIndex++), n);
1910 if (m_shouldEmitProfileHooks) {
1911 emitOpcode(op_profile_will_call);
1912 instructions().append(callArguments.profileHookRegister()->index());
1915 // Reserve space for call frame.
1916 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
1917 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
1918 callFrame.append(newTemporary());
1920 emitExpressionInfo(divot, startOffset, endOffset);
1922 emitOpcode(op_construct);
1923 instructions().append(func->index()); // func
1924 instructions().append(callArguments.count()); // argCount
1925 instructions().append(callArguments.callFrame()); // registerOffset
1926 if (dst != ignoredResult()) {
1927 emitOpcode(op_call_put_result);
1928 instructions().append(dst->index()); // dst
1931 if (m_shouldEmitProfileHooks) {
1932 emitOpcode(op_profile_did_call);
1933 instructions().append(callArguments.profileHookRegister()->index());
1939 RegisterID* BytecodeGenerator::emitStrcat(RegisterID* dst, RegisterID* src, int count)
1941 emitOpcode(op_strcat);
1942 instructions().append(dst->index());
1943 instructions().append(src->index());
1944 instructions().append(count);
1949 void BytecodeGenerator::emitToPrimitive(RegisterID* dst, RegisterID* src)
1951 emitOpcode(op_to_primitive);
1952 instructions().append(dst->index());
1953 instructions().append(src->index());
1956 RegisterID* BytecodeGenerator::emitPushScope(RegisterID* scope)
1958 ASSERT(scope->isTemporary());
1959 ControlFlowContext context;
1960 context.isFinallyBlock = false;
1961 m_scopeContextStack.append(context);
1962 m_dynamicScopeDepth++;
1964 return emitUnaryNoDstOp(op_push_scope, scope);
1967 void BytecodeGenerator::emitPopScope()
1969 ASSERT(m_scopeContextStack.size());
1970 ASSERT(!m_scopeContextStack.last().isFinallyBlock);
1972 emitOpcode(op_pop_scope);
1974 m_scopeContextStack.removeLast();
1975 m_dynamicScopeDepth--;
1978 void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine)
1980 #if ENABLE(DEBUG_WITH_BREAKPOINT)
1981 if (debugHookID != DidReachBreakpoint)
1984 if (!m_shouldEmitDebugHooks)
1987 emitOpcode(op_debug);
1988 instructions().append(debugHookID);
1989 instructions().append(firstLine);
1990 instructions().append(lastLine);
1993 void BytecodeGenerator::pushFinallyContext(Label* target, RegisterID* retAddrDst)
1995 ControlFlowContext scope;
1996 scope.isFinallyBlock = true;
1997 FinallyContext context = { target, retAddrDst };
1998 scope.finallyContext = context;
1999 m_scopeContextStack.append(scope);
2003 void BytecodeGenerator::popFinallyContext()
2005 ASSERT(m_scopeContextStack.size());
2006 ASSERT(m_scopeContextStack.last().isFinallyBlock);
2007 ASSERT(m_finallyDepth > 0);
2008 m_scopeContextStack.removeLast();
2012 LabelScope* BytecodeGenerator::breakTarget(const Identifier& name)
2014 // Reclaim free label scopes.
2016 // The condition was previously coded as 'm_labelScopes.size() && !m_labelScopes.last().refCount()',
2017 // however sometimes this appears to lead to GCC going a little haywire and entering the loop with
2018 // size 0, leading to segfaulty badness. We are yet to identify a valid cause within our code to
2019 // cause the GCC codegen to misbehave in this fashion, and as such the following refactoring of the
2020 // loop condition is a workaround.
2021 while (m_labelScopes.size()) {
2022 if (m_labelScopes.last().refCount())
2024 m_labelScopes.removeLast();
2027 if (!m_labelScopes.size())
2030 // We special-case the following, which is a syntax error in Firefox:
2033 if (name.isEmpty()) {
2034 for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
2035 LabelScope* scope = &m_labelScopes[i];
2036 if (scope->type() != LabelScope::NamedLabel) {
2037 ASSERT(scope->breakTarget());
2044 for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
2045 LabelScope* scope = &m_labelScopes[i];
2046 if (scope->name() && *scope->name() == name) {
2047 ASSERT(scope->breakTarget());
2054 LabelScope* BytecodeGenerator::continueTarget(const Identifier& name)
2056 // Reclaim free label scopes.
2057 while (m_labelScopes.size() && !m_labelScopes.last().refCount())
2058 m_labelScopes.removeLast();
2060 if (!m_labelScopes.size())
2063 if (name.isEmpty()) {
2064 for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
2065 LabelScope* scope = &m_labelScopes[i];
2066 if (scope->type() == LabelScope::Loop) {
2067 ASSERT(scope->continueTarget());
2074 // Continue to the loop nested nearest to the label scope that matches
2076 LabelScope* result = 0;
2077 for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
2078 LabelScope* scope = &m_labelScopes[i];
2079 if (scope->type() == LabelScope::Loop) {
2080 ASSERT(scope->continueTarget());
2083 if (scope->name() && *scope->name() == name)
2084 return result; // may be 0
2089 PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope)
2091 while (topScope > bottomScope) {
2092 // First we count the number of dynamic scopes we need to remove to get
2093 // to a finally block.
2094 int nNormalScopes = 0;
2095 while (topScope > bottomScope) {
2096 if (topScope->isFinallyBlock)
2102 if (nNormalScopes) {
2103 size_t begin = instructions().size();
2105 // We need to remove a number of dynamic scopes to get to the next
2107 emitOpcode(op_jmp_scopes);
2108 instructions().append(nNormalScopes);
2110 // If topScope == bottomScope then there isn't actually a finally block
2111 // left to emit, so make the jmp_scopes jump directly to the target label
2112 if (topScope == bottomScope) {
2113 instructions().append(target->bind(begin, instructions().size()));
2117 // Otherwise we just use jmp_scopes to pop a group of scopes and go
2118 // to the next instruction
2119 RefPtr<Label> nextInsn = newLabel();
2120 instructions().append(nextInsn->bind(begin, instructions().size()));
2121 emitLabel(nextInsn.get());
2124 while (topScope > bottomScope && topScope->isFinallyBlock) {
2125 emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr);
2129 return emitJump(target);
2132 PassRefPtr<Label> BytecodeGenerator::emitJumpScopes(Label* target, int targetScopeDepth)
2134 ASSERT(scopeDepth() - targetScopeDepth >= 0);
2135 ASSERT(target->isForward());
2137 size_t scopeDelta = scopeDepth() - targetScopeDepth;
2138 ASSERT(scopeDelta <= m_scopeContextStack.size());
2140 return emitJump(target);
2143 return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta);
2145 size_t begin = instructions().size();
2147 emitOpcode(op_jmp_scopes);
2148 instructions().append(scopeDelta);
2149 instructions().append(target->bind(begin, instructions().size()));
2153 RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget)
2155 size_t begin = instructions().size();
2157 emitOpcode(op_get_pnames);
2158 instructions().append(dst->index());
2159 instructions().append(base->index());
2160 instructions().append(i->index());
2161 instructions().append(size->index());
2162 instructions().append(breakTarget->bind(begin, instructions().size()));
2166 RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target)
2168 size_t begin = instructions().size();
2170 emitOpcode(op_next_pname);
2171 instructions().append(dst->index());
2172 instructions().append(base->index());
2173 instructions().append(i->index());
2174 instructions().append(size->index());
2175 instructions().append(iter->index());
2176 instructions().append(target->bind(begin, instructions().size()));
2180 RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* start, Label* end)
2182 m_usesExceptions = true;
2184 HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() };
2186 HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth };
2189 m_codeBlock->addExceptionHandler(info);
2190 emitOpcode(op_catch);
2191 instructions().append(targetRegister->index());
2192 return targetRegister;
2195 void BytecodeGenerator::emitThrowReferenceError(const UString& message)
2197 emitOpcode(op_throw_reference_error);
2198 instructions().append(addConstantValue(jsString(globalData(), message))->index());
2201 PassRefPtr<Label> BytecodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, Label* finally)
2203 size_t begin = instructions().size();
2206 instructions().append(retAddrDst->index());
2207 instructions().append(finally->bind(begin, instructions().size()));
2208 emitLabel(newLabel().get()); // Record the fact that the next instruction is implicitly labeled, because op_sret will return to it.
2212 void BytecodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc)
2214 emitOpcode(op_sret);
2215 instructions().append(retAddrSrc->index());
2218 void BytecodeGenerator::emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value)
2220 ControlFlowContext context;
2221 context.isFinallyBlock = false;
2222 m_scopeContextStack.append(context);
2223 m_dynamicScopeDepth++;
2225 emitOpcode(op_push_new_scope);
2226 instructions().append(dst->index());
2227 instructions().append(addConstant(property));
2228 instructions().append(value->index());
2231 void BytecodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type)
2233 SwitchInfo info = { instructions().size(), type };
2235 case SwitchInfo::SwitchImmediate:
2236 emitOpcode(op_switch_imm);
2238 case SwitchInfo::SwitchCharacter:
2239 emitOpcode(op_switch_char);
2241 case SwitchInfo::SwitchString:
2242 emitOpcode(op_switch_string);
2245 ASSERT_NOT_REACHED();
2248 instructions().append(0); // place holder for table index
2249 instructions().append(0); // place holder for default target
2250 instructions().append(scrutineeRegister->index());
2251 m_switchContextStack.append(info);
2254 static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max)
2257 ASSERT(node->isNumber());
2258 double value = static_cast<NumberNode*>(node)->value();
2259 int32_t key = static_cast<int32_t>(value);
2260 ASSERT(key == value);
2266 static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
2268 jumpTable.min = min;
2269 jumpTable.branchOffsets.resize(max - min + 1);
2270 jumpTable.branchOffsets.fill(0);
2271 for (uint32_t i = 0; i < clauseCount; ++i) {
2272 // We're emitting this after the clause labels should have been fixed, so
2273 // the labels should not be "forward" references
2274 ASSERT(!labels[i]->isForward());
2275 jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3));
2279 static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max)
2282 ASSERT(node->isString());
2283 StringImpl* clause = static_cast<StringNode*>(node)->value().impl();
2284 ASSERT(clause->length() == 1);
2286 int32_t key = (*clause)[0];
2292 static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
2294 jumpTable.min = min;
2295 jumpTable.branchOffsets.resize(max - min + 1);
2296 jumpTable.branchOffsets.fill(0);
2297 for (uint32_t i = 0; i < clauseCount; ++i) {
2298 // We're emitting this after the clause labels should have been fixed, so
2299 // the labels should not be "forward" references
2300 ASSERT(!labels[i]->isForward());
2301 jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3));
2305 static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes)
2307 for (uint32_t i = 0; i < clauseCount; ++i) {
2308 // We're emitting this after the clause labels should have been fixed, so
2309 // the labels should not be "forward" references
2310 ASSERT(!labels[i]->isForward());
2312 ASSERT(nodes[i]->isString());
2313 StringImpl* clause = static_cast<StringNode*>(nodes[i])->value().impl();
2314 OffsetLocation location;
2315 location.branchOffset = labels[i]->bind(switchAddress, switchAddress + 3);
2316 jumpTable.offsetTable.add(clause, location);
2320 void BytecodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, Label* defaultLabel, int32_t min, int32_t max)
2322 SwitchInfo switchInfo = m_switchContextStack.last();
2323 m_switchContextStack.removeLast();
2324 if (switchInfo.switchType == SwitchInfo::SwitchImmediate) {
2325 instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfImmediateSwitchJumpTables();
2326 instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
2328 SimpleJumpTable& jumpTable = m_codeBlock->addImmediateSwitchJumpTable();
2329 prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max);
2330 } else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) {
2331 instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfCharacterSwitchJumpTables();
2332 instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
2334 SimpleJumpTable& jumpTable = m_codeBlock->addCharacterSwitchJumpTable();
2335 prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max);
2337 ASSERT(switchInfo.switchType == SwitchInfo::SwitchString);
2338 instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfStringSwitchJumpTables();
2339 instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
2341 StringJumpTable& jumpTable = m_codeBlock->addStringSwitchJumpTable();
2342 prepareJumpTableForStringSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes);
2346 RegisterID* BytecodeGenerator::emitThrowExpressionTooDeepException()
2348 // It would be nice to do an even better job of identifying exactly where the expression is.
2349 // And we could make the caller pass the node pointer in, if there was some way of getting
2350 // that from an arbitrary node. However, calling emitExpressionInfo without any useful data
2351 // is still good enough to get us an accurate line number.
2352 m_expressionTooDeep = true;
2353 return newTemporary();
2356 void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunction)
2358 m_codeBlock->setIsNumericCompareFunction(isNumericCompareFunction);
2361 int BytecodeGenerator::argumentNumberFor(const Identifier& ident)
2363 int parameterCount = m_parameters.size(); // includes 'this'
2364 RegisterID* registerID = registerFor(ident);
2367 int index = registerID->index() + RegisterFile::CallFrameHeaderSize + parameterCount;
2368 return (index > 0 && index < parameterCount) ? index : 0;