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"
37 #include "StrongInlines.h"
45 The layout of a register frame looks like this:
56 assuming (x) and (y) generated temporaries t1 and t2, you would have
58 ------------------------------------
59 | x | y | g | v2 | v1 | t1 | t2 | <-- value held
60 ------------------------------------
61 | -5 | -4 | -3 | -2 | -1 | +0 | +1 | <-- register index
62 ------------------------------------
63 | params->|<-locals | temps->
65 Because temporary registers are allocated in a stack-like fashion, we
66 can reclaim them with a simple popping algorithm. The same goes for labels.
67 (We never reclaim parameter or local registers, because parameters and
68 locals are DontDelete.)
70 The register layout before a function call looks like this:
80 > <------------------------------
81 < > reserved: call frame | 1 | <-- value held
82 > >snip< <------------------------------
83 < > +0 | +1 | +2 | +3 | +4 | +5 | <-- register index
84 > <------------------------------
85 | params->|<-locals | temps->
87 The call instruction fills in the "call frame" registers. It also pads
88 missing arguments at the end of the call:
90 > <-----------------------------------
91 < > reserved: call frame | 1 | ? | <-- value held ("?" stands for "undefined")
92 > >snip< <-----------------------------------
93 < > +0 | +1 | +2 | +3 | +4 | +5 | +6 | <-- register index
94 > <-----------------------------------
95 | params->|<-locals | temps->
97 After filling in missing arguments, the call instruction sets up the new
98 stack frame to overlap the end of the old stack frame:
100 |----------------------------------> <
101 | reserved: call frame | 1 | ? < > <-- value held ("?" stands for "undefined")
102 |----------------------------------> >snip< <
103 | -7 | -6 | -5 | -4 | -3 | -2 | -1 < > <-- register index
104 |----------------------------------> <
105 | | params->|<-locals | temps->
107 That way, arguments are "copied" into the callee's stack frame for free.
109 If the caller supplies too many arguments, this trick doesn't work. The
110 extra arguments protrude into space reserved for locals and temporaries.
111 In that case, the call instruction makes a real copy of the call frame header,
112 along with just the arguments expected by the callee, leaving the original
113 call frame header and arguments behind. (The call instruction can't just discard
114 extra arguments, because the "arguments" object may access them later.)
115 This copying strategy ensures that all named values will be at the indices
116 expected by the callee.
120 static bool s_dumpsGeneratedCode = false;
123 void BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode)
126 s_dumpsGeneratedCode = dumpsGeneratedCode;
128 UNUSED_PARAM(dumpsGeneratedCode);
132 bool BytecodeGenerator::dumpsGeneratedCode()
135 return s_dumpsGeneratedCode;
141 JSObject* BytecodeGenerator::generate()
143 SamplingRegion samplingRegion("Bytecode Generation");
145 m_codeBlock->setThisRegister(m_thisRegister.index());
147 m_scopeNode->emitBytecode(*this);
149 m_codeBlock->setInstructionCount(m_codeBlock->instructions().size());
152 if (s_dumpsGeneratedCode)
153 m_codeBlock->dump(m_scopeChain->globalObject->globalExec());
156 if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode)
157 symbolTable().clear();
159 m_codeBlock->shrinkToFit();
161 if (m_expressionTooDeep)
162 return createOutOfMemoryError(m_scopeChain->globalObject.get());
166 bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
168 int index = m_calleeRegisters.size();
169 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
170 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry);
172 if (!result.second) {
173 r0 = ®isterFor(result.first->second.getIndex());
181 int BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant)
183 int index = symbolTable().size();
184 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
185 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.impl(), newEntry);
187 index = result.first->second.getIndex();
191 void BytecodeGenerator::preserveLastVar()
193 if ((m_firstConstantIndex = m_calleeRegisters.size()) != 0)
194 m_lastVar = &m_calleeRegisters.last();
197 BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock, CompilationKind compilationKind)
198 : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
199 , m_shouldEmitProfileHooks(scopeChain->globalObject->globalObjectMethodTable()->supportsProfiling(scopeChain->globalObject.get()))
200 , m_shouldEmitRichSourceInfo(scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get()))
201 , m_scopeChain(*scopeChain->globalData, scopeChain)
202 , m_symbolTable(symbolTable)
203 , m_scopeNode(programNode)
204 , m_codeBlock(codeBlock)
205 , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
207 , m_dynamicScopeDepth(0)
208 , m_baseScopeDepth(0)
209 , m_codeType(GlobalCode)
210 , m_nextConstantOffset(0)
211 , m_globalConstantIndex(0)
212 , m_hasCreatedActivation(true)
213 , m_firstLazyFunction(0)
214 , m_lastLazyFunction(0)
215 , m_globalData(scopeChain->globalData)
216 , m_lastOpcodeID(op_end)
218 , m_lastOpcodePosition(0)
220 , m_stack(m_globalData->stack())
221 , m_usesExceptions(false)
222 , m_expressionTooDeep(false)
224 m_globalData->startedCompiling(m_codeBlock);
225 if (m_shouldEmitDebugHooks)
226 m_codeBlock->setNeedsFullScopeChain(true);
228 emitOpcode(op_enter);
229 codeBlock->setGlobalData(m_globalData);
231 // FIXME: Move code that modifies the global object to Interpreter::execute.
233 m_codeBlock->m_numParameters = 1; // Allocate space for "this"
234 codeBlock->m_numCapturedVars = codeBlock->m_numVars;
236 if (compilationKind == OptimizingCompilation)
239 JSGlobalObject* globalObject = scopeChain->globalObject.get();
240 ExecState* exec = globalObject->globalExec();
242 BatchedTransitionOptimizer optimizer(*m_globalData, globalObject);
244 const VarStack& varStack = programNode->varStack();
245 const FunctionStack& functionStack = programNode->functionStack();
247 size_t newGlobals = varStack.size() + functionStack.size();
250 globalObject->resizeRegisters(symbolTable->size() + newGlobals);
252 for (size_t i = 0; i < functionStack.size(); ++i) {
253 FunctionBodyNode* function = functionStack[i];
254 globalObject->removeDirect(*m_globalData, function->ident()); // Newly declared functions overwrite existing properties.
256 JSValue value = JSFunction::create(exec, makeFunction(exec, function), scopeChain);
257 int index = addGlobalVar(function->ident(), false);
258 globalObject->registerAt(index).set(*m_globalData, globalObject, value);
261 for (size_t i = 0; i < varStack.size(); ++i) {
262 if (globalObject->hasProperty(exec, *varStack[i].first))
264 addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
268 BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, ScopeChainNode* scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, CompilationKind)
269 : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
270 , m_shouldEmitProfileHooks(scopeChain->globalObject->globalObjectMethodTable()->supportsProfiling(scopeChain->globalObject.get()))
271 , m_shouldEmitRichSourceInfo(scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get()))
272 , m_scopeChain(*scopeChain->globalData, scopeChain)
273 , m_symbolTable(symbolTable)
274 , m_scopeNode(functionBody)
275 , m_codeBlock(codeBlock)
276 , m_activationRegister(0)
278 , m_dynamicScopeDepth(0)
279 , m_baseScopeDepth(0)
280 , m_codeType(FunctionCode)
281 , m_nextConstantOffset(0)
282 , m_globalConstantIndex(0)
283 , m_hasCreatedActivation(false)
284 , m_firstLazyFunction(0)
285 , m_lastLazyFunction(0)
286 , m_globalData(scopeChain->globalData)
287 , m_lastOpcodeID(op_end)
289 , m_lastOpcodePosition(0)
291 , m_stack(m_globalData->stack())
292 , m_usesExceptions(false)
293 , m_expressionTooDeep(false)
295 m_globalData->startedCompiling(m_codeBlock);
296 if (m_shouldEmitDebugHooks)
297 m_codeBlock->setNeedsFullScopeChain(true);
299 codeBlock->setGlobalData(m_globalData);
301 emitOpcode(op_enter);
302 if (m_codeBlock->needsFullScopeChain()) {
303 m_activationRegister = addVar();
304 emitInitLazyRegister(m_activationRegister);
305 m_codeBlock->setActivationRegister(m_activationRegister->index());
308 // Both op_tear_off_activation and op_tear_off_arguments tear off the 'arguments'
309 // object, if created.
310 if (m_codeBlock->needsFullScopeChain() || functionBody->usesArguments()) {
311 RegisterID* unmodifiedArgumentsRegister = addVar(); // Anonymous, so it can't be modified by user code.
312 RegisterID* argumentsRegister = addVar(propertyNames().arguments, false); // Can be changed by assigning to 'arguments'.
314 // We can save a little space by hard-coding the knowledge that the two
315 // 'arguments' values are stored in consecutive registers, and storing
316 // only the index of the assignable one.
317 codeBlock->setArgumentsRegister(argumentsRegister->index());
318 ASSERT_UNUSED(unmodifiedArgumentsRegister, unmodifiedArgumentsRegister->index() == JSC::unmodifiedArgumentsRegister(codeBlock->argumentsRegister()));
320 emitInitLazyRegister(argumentsRegister);
321 emitInitLazyRegister(unmodifiedArgumentsRegister);
323 if (m_codeBlock->isStrictMode()) {
324 emitOpcode(op_create_arguments);
325 instructions().append(argumentsRegister->index());
328 // The debugger currently retrieves the arguments object from an activation rather than pulling
329 // it from a call frame. In the long-term it should stop doing that (<rdar://problem/6911886>),
330 // but for now we force eager creation of the arguments object when debugging.
331 if (m_shouldEmitDebugHooks) {
332 emitOpcode(op_create_arguments);
333 instructions().append(argumentsRegister->index());
337 const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack();
338 const DeclarationStacks::VarStack& varStack = functionBody->varStack();
340 // Captured variables and functions go first so that activations don't have
341 // to step over the non-captured locals to mark them.
342 m_hasCreatedActivation = false;
343 if (functionBody->hasCapturedVariables()) {
344 for (size_t i = 0; i < functionStack.size(); ++i) {
345 FunctionBodyNode* function = functionStack[i];
346 const Identifier& ident = function->ident();
347 if (functionBody->captures(ident)) {
348 if (!m_hasCreatedActivation) {
349 m_hasCreatedActivation = true;
350 emitOpcode(op_create_activation);
351 instructions().append(m_activationRegister->index());
353 m_functions.add(ident.impl());
354 emitNewFunction(addVar(ident, false), function);
357 for (size_t i = 0; i < varStack.size(); ++i) {
358 const Identifier& ident = *varStack[i].first;
359 if (functionBody->captures(ident))
360 addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
363 bool canLazilyCreateFunctions = !functionBody->needsActivationForMoreThanVariables() && !m_shouldEmitDebugHooks;
364 if (!canLazilyCreateFunctions && !m_hasCreatedActivation) {
365 m_hasCreatedActivation = true;
366 emitOpcode(op_create_activation);
367 instructions().append(m_activationRegister->index());
370 codeBlock->m_numCapturedVars = codeBlock->m_numVars;
371 m_firstLazyFunction = codeBlock->m_numVars;
372 for (size_t i = 0; i < functionStack.size(); ++i) {
373 FunctionBodyNode* function = functionStack[i];
374 const Identifier& ident = function->ident();
375 if (!functionBody->captures(ident)) {
376 m_functions.add(ident.impl());
377 RefPtr<RegisterID> reg = addVar(ident, false);
378 // Don't lazily create functions that override the name 'arguments'
379 // as this would complicate lazy instantiation of actual arguments.
380 if (!canLazilyCreateFunctions || ident == propertyNames().arguments)
381 emitNewFunction(reg.get(), function);
383 emitInitLazyRegister(reg.get());
384 m_lazyFunctions.set(reg->index(), function);
388 m_lastLazyFunction = canLazilyCreateFunctions ? codeBlock->m_numVars : m_firstLazyFunction;
389 for (size_t i = 0; i < varStack.size(); ++i) {
390 const Identifier& ident = *varStack[i].first;
391 if (!functionBody->captures(ident))
392 addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
395 if (m_shouldEmitDebugHooks)
396 codeBlock->m_numCapturedVars = codeBlock->m_numVars;
398 FunctionParameters& parameters = *functionBody->parameters();
399 size_t parameterCount = parameters.size();
400 int nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1;
401 m_parameters.grow(1 + parameterCount); // reserve space for "this"
403 // Add "this" as a parameter
404 m_thisRegister.setIndex(nextParameterIndex);
405 ++m_codeBlock->m_numParameters;
407 for (size_t i = 0; i < parameterCount; ++i)
408 addParameter(parameters[i], ++nextParameterIndex);
412 if (isConstructor()) {
413 RefPtr<RegisterID> func = newTemporary();
414 RefPtr<RegisterID> funcProto = newTemporary();
416 emitOpcode(op_get_callee);
417 instructions().append(func->index());
419 emitGetById(funcProto.get(), func.get(), globalData()->propertyNames->prototype);
421 emitOpcode(op_create_this);
422 instructions().append(m_thisRegister.index());
423 instructions().append(funcProto->index());
424 } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) {
425 emitOpcode(op_convert_this);
426 instructions().append(m_thisRegister.index());
430 BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, ScopeChainNode* scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock, CompilationKind)
431 : m_shouldEmitDebugHooks(scopeChain->globalObject->debugger())
432 , m_shouldEmitProfileHooks(scopeChain->globalObject->globalObjectMethodTable()->supportsProfiling(scopeChain->globalObject.get()))
433 , m_shouldEmitRichSourceInfo(scopeChain->globalObject->globalObjectMethodTable()->supportsRichSourceInfo(scopeChain->globalObject.get()))
434 , m_scopeChain(*scopeChain->globalData, scopeChain)
435 , m_symbolTable(symbolTable)
436 , m_scopeNode(evalNode)
437 , m_codeBlock(codeBlock)
438 , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
440 , m_dynamicScopeDepth(0)
441 , m_baseScopeDepth(codeBlock->baseScopeDepth())
442 , m_codeType(EvalCode)
443 , m_nextConstantOffset(0)
444 , m_globalConstantIndex(0)
445 , m_hasCreatedActivation(true)
446 , m_firstLazyFunction(0)
447 , m_lastLazyFunction(0)
448 , m_globalData(scopeChain->globalData)
449 , m_lastOpcodeID(op_end)
451 , m_lastOpcodePosition(0)
453 , m_stack(m_globalData->stack())
454 , m_usesExceptions(false)
455 , m_expressionTooDeep(false)
457 m_globalData->startedCompiling(m_codeBlock);
458 if (m_shouldEmitDebugHooks || m_baseScopeDepth)
459 m_codeBlock->setNeedsFullScopeChain(true);
461 emitOpcode(op_enter);
462 codeBlock->setGlobalData(m_globalData);
463 m_codeBlock->m_numParameters = 1; // Allocate space for "this"
465 const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack();
466 for (size_t i = 0; i < functionStack.size(); ++i)
467 m_codeBlock->addFunctionDecl(makeFunction(m_globalData, functionStack[i]));
469 const DeclarationStacks::VarStack& varStack = evalNode->varStack();
470 unsigned numVariables = varStack.size();
471 Vector<Identifier> variables;
472 variables.reserveCapacity(numVariables);
473 for (size_t i = 0; i < numVariables; ++i)
474 variables.append(*varStack[i].first);
475 codeBlock->adoptVariables(variables);
476 codeBlock->m_numCapturedVars = codeBlock->m_numVars;
480 BytecodeGenerator::~BytecodeGenerator()
482 m_globalData->finishedCompiling(m_codeBlock);
485 RegisterID* BytecodeGenerator::emitInitLazyRegister(RegisterID* reg)
487 emitOpcode(op_init_lazy_reg);
488 instructions().append(reg->index());
492 void BytecodeGenerator::addParameter(const Identifier& ident, int parameterIndex)
494 // Parameters overwrite var declarations, but not function declarations.
495 StringImpl* rep = ident.impl();
496 if (!m_functions.contains(rep)) {
497 symbolTable().set(rep, parameterIndex);
498 RegisterID& parameter = registerFor(parameterIndex);
499 parameter.setIndex(parameterIndex);
502 // To maintain the calling convention, we have to allocate unique space for
503 // each parameter, even if the parameter doesn't make it into the symbol table.
504 ++m_codeBlock->m_numParameters;
507 RegisterID* BytecodeGenerator::registerFor(const Identifier& ident)
509 if (ident == propertyNames().thisIdentifier)
510 return &m_thisRegister;
512 if (m_codeType == GlobalCode)
515 if (!shouldOptimizeLocals())
518 SymbolTableEntry entry = symbolTable().get(ident.impl());
522 if (ident == propertyNames().arguments)
523 createArgumentsIfNecessary();
525 return createLazyRegisterIfNecessary(®isterFor(entry.getIndex()));
528 RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident)
530 if (m_codeType == EvalCode)
533 if (m_codeType == GlobalCode)
536 SymbolTableEntry entry = symbolTable().get(ident.impl());
540 return createLazyRegisterIfNecessary(®isterFor(entry.getIndex()));
543 bool BytecodeGenerator::willResolveToArguments(const Identifier& ident)
545 if (ident != propertyNames().arguments)
548 if (!shouldOptimizeLocals())
551 SymbolTableEntry entry = symbolTable().get(ident.impl());
555 if (m_codeBlock->usesArguments() && m_codeType == FunctionCode)
561 RegisterID* BytecodeGenerator::uncheckedRegisterForArguments()
563 ASSERT(willResolveToArguments(propertyNames().arguments));
565 SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.impl());
566 ASSERT(!entry.isNull());
567 return ®isterFor(entry.getIndex());
570 RegisterID* BytecodeGenerator::createLazyRegisterIfNecessary(RegisterID* reg)
572 if (m_lastLazyFunction <= reg->index() || reg->index() < m_firstLazyFunction)
574 emitLazyNewFunction(reg, m_lazyFunctions.get(reg->index()));
578 bool BytecodeGenerator::isLocal(const Identifier& ident)
580 if (ident == propertyNames().thisIdentifier)
583 return shouldOptimizeLocals() && symbolTable().contains(ident.impl());
586 bool BytecodeGenerator::isLocalConstant(const Identifier& ident)
588 return symbolTable().get(ident.impl()).isReadOnly();
591 RegisterID* BytecodeGenerator::newRegister()
593 m_calleeRegisters.append(m_calleeRegisters.size());
594 m_codeBlock->m_numCalleeRegisters = max<int>(m_codeBlock->m_numCalleeRegisters, m_calleeRegisters.size());
595 return &m_calleeRegisters.last();
598 RegisterID* BytecodeGenerator::newTemporary()
600 // Reclaim free register IDs.
601 while (m_calleeRegisters.size() && !m_calleeRegisters.last().refCount())
602 m_calleeRegisters.removeLast();
604 RegisterID* result = newRegister();
605 result->setTemporary();
609 RegisterID* BytecodeGenerator::highestUsedRegister()
611 size_t count = m_codeBlock->m_numCalleeRegisters;
612 while (m_calleeRegisters.size() < count)
614 return &m_calleeRegisters.last();
617 PassRefPtr<LabelScope> BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name)
619 // Reclaim free label scopes.
620 while (m_labelScopes.size() && !m_labelScopes.last().refCount())
621 m_labelScopes.removeLast();
623 // Allocate new label scope.
624 LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : PassRefPtr<Label>()); // Only loops have continue targets.
625 m_labelScopes.append(scope);
626 return &m_labelScopes.last();
629 PassRefPtr<Label> BytecodeGenerator::newLabel()
631 // Reclaim free label IDs.
632 while (m_labels.size() && !m_labels.last().refCount())
633 m_labels.removeLast();
635 // Allocate new label ID.
636 m_labels.append(m_codeBlock);
637 return &m_labels.last();
640 PassRefPtr<Label> BytecodeGenerator::emitLabel(Label* l0)
642 unsigned newLabelIndex = instructions().size();
643 l0->setLocation(newLabelIndex);
645 if (m_codeBlock->numberOfJumpTargets()) {
646 unsigned lastLabelIndex = m_codeBlock->lastJumpTarget();
647 ASSERT(lastLabelIndex <= newLabelIndex);
648 if (newLabelIndex == lastLabelIndex) {
649 // Peephole optimizations have already been disabled by emitting the last label
654 m_codeBlock->addJumpTarget(newLabelIndex);
656 // This disables peephole optimizations when an instruction is a jump target
657 m_lastOpcodeID = op_end;
661 void BytecodeGenerator::emitOpcode(OpcodeID opcodeID)
664 size_t opcodePosition = instructions().size();
665 ASSERT(opcodePosition - m_lastOpcodePosition == opcodeLength(m_lastOpcodeID) || m_lastOpcodeID == op_end);
666 m_lastOpcodePosition = opcodePosition;
668 instructions().append(globalData()->interpreter->getOpcode(opcodeID));
669 m_lastOpcodeID = opcodeID;
672 void BytecodeGenerator::emitLoopHint()
675 emitOpcode(op_loop_hint);
679 void BytecodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
681 ASSERT(instructions().size() >= 4);
682 size_t size = instructions().size();
683 dstIndex = instructions().at(size - 3).u.operand;
684 src1Index = instructions().at(size - 2).u.operand;
685 src2Index = instructions().at(size - 1).u.operand;
688 void BytecodeGenerator::retrieveLastUnaryOp(int& dstIndex, int& srcIndex)
690 ASSERT(instructions().size() >= 3);
691 size_t size = instructions().size();
692 dstIndex = instructions().at(size - 2).u.operand;
693 srcIndex = instructions().at(size - 1).u.operand;
696 void ALWAYS_INLINE BytecodeGenerator::rewindBinaryOp()
698 ASSERT(instructions().size() >= 4);
699 instructions().shrink(instructions().size() - 4);
700 m_lastOpcodeID = op_end;
703 void ALWAYS_INLINE BytecodeGenerator::rewindUnaryOp()
705 ASSERT(instructions().size() >= 3);
706 instructions().shrink(instructions().size() - 3);
707 m_lastOpcodeID = op_end;
710 PassRefPtr<Label> BytecodeGenerator::emitJump(Label* target)
712 size_t begin = instructions().size();
713 emitOpcode(target->isForward() ? op_jmp : op_loop);
714 instructions().append(target->bind(begin, instructions().size()));
718 PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* target)
720 if (m_lastOpcodeID == op_less) {
725 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
727 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
730 size_t begin = instructions().size();
731 emitOpcode(target->isForward() ? op_jless : op_loop_if_less);
732 instructions().append(src1Index);
733 instructions().append(src2Index);
734 instructions().append(target->bind(begin, instructions().size()));
737 } else if (m_lastOpcodeID == op_lesseq) {
742 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
744 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
747 size_t begin = instructions().size();
748 emitOpcode(target->isForward() ? op_jlesseq : op_loop_if_lesseq);
749 instructions().append(src1Index);
750 instructions().append(src2Index);
751 instructions().append(target->bind(begin, instructions().size()));
754 } else if (m_lastOpcodeID == op_greater) {
759 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
761 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
764 size_t begin = instructions().size();
765 emitOpcode(target->isForward() ? op_jgreater : op_loop_if_greater);
766 instructions().append(src1Index);
767 instructions().append(src2Index);
768 instructions().append(target->bind(begin, instructions().size()));
771 } else if (m_lastOpcodeID == op_greatereq) {
776 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
778 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
781 size_t begin = instructions().size();
782 emitOpcode(target->isForward() ? op_jgreatereq : op_loop_if_greatereq);
783 instructions().append(src1Index);
784 instructions().append(src2Index);
785 instructions().append(target->bind(begin, instructions().size()));
788 } else if (m_lastOpcodeID == op_eq_null && target->isForward()) {
792 retrieveLastUnaryOp(dstIndex, srcIndex);
794 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
797 size_t begin = instructions().size();
798 emitOpcode(op_jeq_null);
799 instructions().append(srcIndex);
800 instructions().append(target->bind(begin, instructions().size()));
803 } else if (m_lastOpcodeID == op_neq_null && target->isForward()) {
807 retrieveLastUnaryOp(dstIndex, srcIndex);
809 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
812 size_t begin = instructions().size();
813 emitOpcode(op_jneq_null);
814 instructions().append(srcIndex);
815 instructions().append(target->bind(begin, instructions().size()));
820 size_t begin = instructions().size();
822 emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true);
823 instructions().append(cond->index());
824 instructions().append(target->bind(begin, instructions().size()));
828 PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* target)
830 if (m_lastOpcodeID == op_less && target->isForward()) {
835 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
837 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
840 size_t begin = instructions().size();
841 emitOpcode(op_jnless);
842 instructions().append(src1Index);
843 instructions().append(src2Index);
844 instructions().append(target->bind(begin, instructions().size()));
847 } else if (m_lastOpcodeID == op_lesseq && target->isForward()) {
852 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
854 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
857 size_t begin = instructions().size();
858 emitOpcode(op_jnlesseq);
859 instructions().append(src1Index);
860 instructions().append(src2Index);
861 instructions().append(target->bind(begin, instructions().size()));
864 } else if (m_lastOpcodeID == op_greater && target->isForward()) {
869 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
871 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
874 size_t begin = instructions().size();
875 emitOpcode(op_jngreater);
876 instructions().append(src1Index);
877 instructions().append(src2Index);
878 instructions().append(target->bind(begin, instructions().size()));
881 } else if (m_lastOpcodeID == op_greatereq && target->isForward()) {
886 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
888 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
891 size_t begin = instructions().size();
892 emitOpcode(op_jngreatereq);
893 instructions().append(src1Index);
894 instructions().append(src2Index);
895 instructions().append(target->bind(begin, instructions().size()));
898 } else if (m_lastOpcodeID == op_not) {
902 retrieveLastUnaryOp(dstIndex, srcIndex);
904 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
907 size_t begin = instructions().size();
908 emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true);
909 instructions().append(srcIndex);
910 instructions().append(target->bind(begin, instructions().size()));
913 } else if (m_lastOpcodeID == op_eq_null && target->isForward()) {
917 retrieveLastUnaryOp(dstIndex, srcIndex);
919 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
922 size_t begin = instructions().size();
923 emitOpcode(op_jneq_null);
924 instructions().append(srcIndex);
925 instructions().append(target->bind(begin, instructions().size()));
928 } else if (m_lastOpcodeID == op_neq_null && target->isForward()) {
932 retrieveLastUnaryOp(dstIndex, srcIndex);
934 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
937 size_t begin = instructions().size();
938 emitOpcode(op_jeq_null);
939 instructions().append(srcIndex);
940 instructions().append(target->bind(begin, instructions().size()));
945 size_t begin = instructions().size();
946 emitOpcode(target->isForward() ? op_jfalse : op_loop_if_false);
947 instructions().append(cond->index());
948 instructions().append(target->bind(begin, instructions().size()));
952 PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(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->callFunction()));
959 instructions().append(target->bind(begin, instructions().size()));
963 PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond, Label* target)
965 size_t begin = instructions().size();
967 emitOpcode(op_jneq_ptr);
968 instructions().append(cond->index());
969 instructions().append(Instruction(*m_globalData, m_codeBlock->ownerExecutable(), m_scopeChain->globalObject->applyFunction()));
970 instructions().append(target->bind(begin, instructions().size()));
974 unsigned BytecodeGenerator::addConstant(const Identifier& ident)
976 StringImpl* rep = ident.impl();
977 pair<IdentifierMap::iterator, bool> result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers());
978 if (result.second) // new entry
979 m_codeBlock->addIdentifier(Identifier(m_globalData, rep));
981 return result.first->second;
984 RegisterID* BytecodeGenerator::addConstantValue(JSValue v)
986 int index = m_nextConstantOffset;
988 pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(JSValue::encode(v), m_nextConstantOffset);
990 m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset);
991 ++m_nextConstantOffset;
992 m_codeBlock->addConstant(JSValue(v));
994 index = result.first->second;
996 return &m_constantPoolRegisters[index];
999 unsigned BytecodeGenerator::addRegExp(RegExp* r)
1001 return m_codeBlock->addRegExp(r);
1004 RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
1007 instructions().append(dst->index());
1008 instructions().append(src->index());
1012 RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src)
1014 emitOpcode(opcodeID);
1015 instructions().append(dst->index());
1016 instructions().append(src->index());
1020 RegisterID* BytecodeGenerator::emitPreInc(RegisterID* srcDst)
1022 emitOpcode(op_pre_inc);
1023 instructions().append(srcDst->index());
1027 RegisterID* BytecodeGenerator::emitPreDec(RegisterID* srcDst)
1029 emitOpcode(op_pre_dec);
1030 instructions().append(srcDst->index());
1034 RegisterID* BytecodeGenerator::emitPostInc(RegisterID* dst, RegisterID* srcDst)
1036 emitOpcode(op_post_inc);
1037 instructions().append(dst->index());
1038 instructions().append(srcDst->index());
1042 RegisterID* BytecodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst)
1044 emitOpcode(op_post_dec);
1045 instructions().append(dst->index());
1046 instructions().append(srcDst->index());
1050 RegisterID* BytecodeGenerator::emitBinaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types)
1052 emitOpcode(opcodeID);
1053 instructions().append(dst->index());
1054 instructions().append(src1->index());
1055 instructions().append(src2->index());
1057 if (opcodeID == op_bitor || opcodeID == op_bitand || opcodeID == op_bitxor ||
1058 opcodeID == op_add || opcodeID == op_mul || opcodeID == op_sub || opcodeID == op_div)
1059 instructions().append(types.toInt());
1064 RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2)
1066 if (m_lastOpcodeID == op_typeof) {
1070 retrieveLastUnaryOp(dstIndex, srcIndex);
1072 if (src1->index() == dstIndex
1073 && src1->isTemporary()
1074 && m_codeBlock->isConstantRegisterIndex(src2->index())
1075 && m_codeBlock->constantRegister(src2->index()).get().isString()) {
1076 const UString& value = asString(m_codeBlock->constantRegister(src2->index()).get())->tryGetValue();
1077 if (value == "undefined") {
1079 emitOpcode(op_is_undefined);
1080 instructions().append(dst->index());
1081 instructions().append(srcIndex);
1084 if (value == "boolean") {
1086 emitOpcode(op_is_boolean);
1087 instructions().append(dst->index());
1088 instructions().append(srcIndex);
1091 if (value == "number") {
1093 emitOpcode(op_is_number);
1094 instructions().append(dst->index());
1095 instructions().append(srcIndex);
1098 if (value == "string") {
1100 emitOpcode(op_is_string);
1101 instructions().append(dst->index());
1102 instructions().append(srcIndex);
1105 if (value == "object") {
1107 emitOpcode(op_is_object);
1108 instructions().append(dst->index());
1109 instructions().append(srcIndex);
1112 if (value == "function") {
1114 emitOpcode(op_is_function);
1115 instructions().append(dst->index());
1116 instructions().append(srcIndex);
1122 emitOpcode(opcodeID);
1123 instructions().append(dst->index());
1124 instructions().append(src1->index());
1125 instructions().append(src2->index());
1129 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, bool b)
1131 return emitLoad(dst, jsBoolean(b));
1134 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, double number)
1136 // FIXME: Our hash tables won't hold infinity, so we make a new JSValue each time.
1137 // Later we can do the extra work to handle that like the other cases. They also don't
1138 // work correctly with NaN as a key.
1139 if (isnan(number) || number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number))
1140 return emitLoad(dst, jsNumber(number));
1141 JSValue& valueInMap = m_numberMap.add(number, JSValue()).first->second;
1143 valueInMap = jsNumber(number);
1144 return emitLoad(dst, valueInMap);
1147 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier)
1149 JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).first->second;
1151 stringInMap = jsOwnedString(globalData(), identifier.ustring());
1152 return emitLoad(dst, JSValue(stringInMap));
1155 RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v)
1157 RegisterID* constantID = addConstantValue(v);
1159 return emitMove(dst, constantID);
1163 bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, bool& requiresDynamicChecks, JSObject*& globalObject)
1165 // Cases where we cannot statically optimize the lookup.
1166 if (property == propertyNames().arguments || !canOptimizeNonLocals()) {
1168 index = missingSymbolMarker();
1170 if (shouldOptimizeLocals() && m_codeType == GlobalCode) {
1171 ScopeChainIterator iter = m_scopeChain->begin();
1172 globalObject = iter->get();
1173 ASSERT((++iter) == m_scopeChain->end());
1179 requiresDynamicChecks = false;
1180 ScopeChainIterator iter = m_scopeChain->begin();
1181 ScopeChainIterator end = m_scopeChain->end();
1182 for (; iter != end; ++iter, ++depth) {
1183 JSObject* currentScope = iter->get();
1184 if (!currentScope->isVariableObject())
1186 JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
1187 SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.impl());
1189 // Found the property
1190 if (!entry.isNull()) {
1191 if (entry.isReadOnly() && forWriting) {
1193 index = missingSymbolMarker();
1195 globalObject = currentVariableObject;
1198 stackDepth = depth + m_codeBlock->needsFullScopeChain();
1199 index = entry.getIndex();
1201 globalObject = currentVariableObject;
1204 bool scopeRequiresDynamicChecks = false;
1205 if (currentVariableObject->isDynamicScope(scopeRequiresDynamicChecks))
1207 requiresDynamicChecks |= scopeRequiresDynamicChecks;
1209 // Can't locate the property but we're able to avoid a few lookups.
1210 stackDepth = depth + m_codeBlock->needsFullScopeChain();
1211 index = missingSymbolMarker();
1212 JSObject* scope = iter->get();
1214 globalObject = scope;
1218 void BytecodeGenerator::emitCheckHasInstance(RegisterID* base)
1220 emitOpcode(op_check_has_instance);
1221 instructions().append(base->index());
1224 RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype)
1226 emitOpcode(op_instanceof);
1227 instructions().append(dst->index());
1228 instructions().append(value->index());
1229 instructions().append(base->index());
1230 instructions().append(basePrototype->index());
1234 static const unsigned maxGlobalResolves = 128;
1236 bool BytecodeGenerator::shouldAvoidResolveGlobal()
1238 return m_codeBlock->globalResolveInfoCount() > maxGlobalResolves && !m_labelScopes.size();
1241 RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
1245 JSObject* globalObject = 0;
1246 bool requiresDynamicChecks = false;
1247 if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) && !globalObject) {
1248 // We can't optimise at all :-(
1249 emitOpcode(op_resolve);
1250 instructions().append(dst->index());
1251 instructions().append(addConstant(property));
1254 if (shouldAvoidResolveGlobal()) {
1256 requiresDynamicChecks = true;
1260 if (index != missingSymbolMarker() && !requiresDynamicChecks) {
1261 // Directly index the property lookup across multiple scopes.
1262 return emitGetScopedVar(dst, depth, index, globalObject);
1266 m_codeBlock->addGlobalResolveInfo(instructions().size());
1268 #if ENABLE(INTERPRETER)
1269 m_codeBlock->addGlobalResolveInstruction(instructions().size());
1271 emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
1272 instructions().append(dst->index());
1273 instructions().append(addConstant(property));
1274 instructions().append(0);
1275 instructions().append(0);
1276 if (requiresDynamicChecks)
1277 instructions().append(depth);
1281 if (requiresDynamicChecks) {
1282 // If we get here we have eval nested inside a |with| just give up
1283 emitOpcode(op_resolve);
1284 instructions().append(dst->index());
1285 instructions().append(addConstant(property));
1289 if (index != missingSymbolMarker()) {
1290 // Directly index the property lookup across multiple scopes.
1291 return emitGetScopedVar(dst, depth, index, globalObject);
1294 // In this case we are at least able to drop a few scope chains from the
1295 // lookup chain, although we still need to hash from then on.
1296 emitOpcode(op_resolve_skip);
1297 instructions().append(dst->index());
1298 instructions().append(addConstant(property));
1299 instructions().append(depth);
1303 RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValue globalObject)
1306 if (m_lastOpcodeID == op_put_global_var) {
1309 retrieveLastUnaryOp(dstIndex, srcIndex);
1311 if (dstIndex == index && srcIndex == dst->index())
1315 emitOpcode(op_get_global_var);
1316 instructions().append(dst->index());
1317 instructions().append(index);
1321 emitOpcode(op_get_scoped_var);
1322 instructions().append(dst->index());
1323 instructions().append(index);
1324 instructions().append(depth);
1328 RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValue globalObject)
1331 emitOpcode(op_put_global_var);
1332 instructions().append(index);
1333 instructions().append(value->index());
1336 emitOpcode(op_put_scoped_var);
1337 instructions().append(index);
1338 instructions().append(depth);
1339 instructions().append(value->index());
1343 RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property)
1347 JSObject* globalObject = 0;
1348 bool requiresDynamicChecks = false;
1349 findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject);
1350 if (!globalObject || requiresDynamicChecks) {
1351 // We can't optimise at all :-(
1352 emitOpcode(op_resolve_base);
1353 instructions().append(dst->index());
1354 instructions().append(addConstant(property));
1355 instructions().append(false);
1359 // Global object is the base
1360 return emitLoad(dst, JSValue(globalObject));
1363 RegisterID* BytecodeGenerator::emitResolveBaseForPut(RegisterID* dst, const Identifier& property)
1365 if (!m_codeBlock->isStrictMode())
1366 return emitResolveBase(dst, property);
1369 JSObject* globalObject = 0;
1370 bool requiresDynamicChecks = false;
1371 findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject);
1372 if (!globalObject || requiresDynamicChecks) {
1373 // We can't optimise at all :-(
1374 emitOpcode(op_resolve_base);
1375 instructions().append(dst->index());
1376 instructions().append(addConstant(property));
1377 instructions().append(true);
1381 // Global object is the base
1382 RefPtr<RegisterID> result = emitLoad(dst, JSValue(globalObject));
1383 emitOpcode(op_ensure_property_exists);
1384 instructions().append(dst->index());
1385 instructions().append(addConstant(property));
1386 return result.get();
1389 RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
1393 JSObject* globalObject = 0;
1394 bool requiresDynamicChecks = false;
1395 if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) {
1396 // We can't optimise at all :-(
1397 emitOpcode(op_resolve_with_base);
1398 instructions().append(baseDst->index());
1399 instructions().append(propDst->index());
1400 instructions().append(addConstant(property));
1404 bool forceGlobalResolve = false;
1406 // Global object is the base
1407 emitLoad(baseDst, JSValue(globalObject));
1409 if (index != missingSymbolMarker() && !forceGlobalResolve) {
1410 // Directly index the property lookup across multiple scopes.
1411 emitGetScopedVar(propDst, depth, index, globalObject);
1414 if (shouldAvoidResolveGlobal()) {
1415 emitOpcode(op_resolve);
1416 instructions().append(propDst->index());
1417 instructions().append(addConstant(property));
1421 m_codeBlock->addGlobalResolveInfo(instructions().size());
1423 #if ENABLE(INTERPRETER)
1424 m_codeBlock->addGlobalResolveInstruction(instructions().size());
1426 emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
1427 instructions().append(propDst->index());
1428 instructions().append(addConstant(property));
1429 instructions().append(0);
1430 instructions().append(0);
1431 if (requiresDynamicChecks)
1432 instructions().append(depth);
1436 RegisterID* BytecodeGenerator::emitResolveWithThis(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
1440 JSObject* globalObject = 0;
1441 bool requiresDynamicChecks = false;
1442 if (!findScopedProperty(property, index, depth, false, requiresDynamicChecks, globalObject) || !globalObject || requiresDynamicChecks) {
1443 // We can't optimise at all :-(
1444 emitOpcode(op_resolve_with_this);
1445 instructions().append(baseDst->index());
1446 instructions().append(propDst->index());
1447 instructions().append(addConstant(property));
1451 bool forceGlobalResolve = false;
1453 // Global object is the base
1454 emitLoad(baseDst, jsUndefined());
1456 if (index != missingSymbolMarker() && !forceGlobalResolve) {
1457 // Directly index the property lookup across multiple scopes.
1458 emitGetScopedVar(propDst, depth, index, globalObject);
1461 if (shouldAvoidResolveGlobal()) {
1462 emitOpcode(op_resolve);
1463 instructions().append(propDst->index());
1464 instructions().append(addConstant(property));
1468 m_codeBlock->addGlobalResolveInfo(instructions().size());
1470 #if ENABLE(INTERPRETER)
1471 m_codeBlock->addGlobalResolveInstruction(instructions().size());
1473 emitOpcode(requiresDynamicChecks ? op_resolve_global_dynamic : op_resolve_global);
1474 instructions().append(propDst->index());
1475 instructions().append(addConstant(property));
1476 instructions().append(0);
1477 instructions().append(0);
1478 if (requiresDynamicChecks)
1479 instructions().append(depth);
1483 void BytecodeGenerator::emitMethodCheck()
1485 emitOpcode(op_method_check);
1488 RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
1490 #if ENABLE(INTERPRETER)
1491 m_codeBlock->addPropertyAccessInstruction(instructions().size());
1494 emitOpcode(op_get_by_id);
1495 instructions().append(dst->index());
1496 instructions().append(base->index());
1497 instructions().append(addConstant(property));
1498 instructions().append(0);
1499 instructions().append(0);
1500 instructions().append(0);
1501 instructions().append(0);
1505 RegisterID* BytecodeGenerator::emitGetArgumentsLength(RegisterID* dst, RegisterID* base)
1507 emitOpcode(op_get_arguments_length);
1508 instructions().append(dst->index());
1509 ASSERT(base->index() == m_codeBlock->argumentsRegister());
1510 instructions().append(base->index());
1511 instructions().append(addConstant(propertyNames().length));
1515 RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
1517 #if ENABLE(INTERPRETER)
1518 m_codeBlock->addPropertyAccessInstruction(instructions().size());
1521 emitOpcode(op_put_by_id);
1522 instructions().append(base->index());
1523 instructions().append(addConstant(property));
1524 instructions().append(value->index());
1525 instructions().append(0);
1526 instructions().append(0);
1527 instructions().append(0);
1528 instructions().append(0);
1529 instructions().append(0);
1533 RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value)
1535 #if ENABLE(INTERPRETER)
1536 m_codeBlock->addPropertyAccessInstruction(instructions().size());
1539 emitOpcode(op_put_by_id);
1540 instructions().append(base->index());
1541 instructions().append(addConstant(property));
1542 instructions().append(value->index());
1543 instructions().append(0);
1544 instructions().append(0);
1545 instructions().append(0);
1546 instructions().append(0);
1547 instructions().append(property != m_globalData->propertyNames->underscoreProto);
1551 RegisterID* BytecodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
1553 emitOpcode(op_put_getter);
1554 instructions().append(base->index());
1555 instructions().append(addConstant(property));
1556 instructions().append(value->index());
1560 RegisterID* BytecodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
1562 emitOpcode(op_put_setter);
1563 instructions().append(base->index());
1564 instructions().append(addConstant(property));
1565 instructions().append(value->index());
1569 RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
1571 emitOpcode(op_del_by_id);
1572 instructions().append(dst->index());
1573 instructions().append(base->index());
1574 instructions().append(addConstant(property));
1578 RegisterID* BytecodeGenerator::emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
1580 emitOpcode(op_get_argument_by_val);
1581 instructions().append(dst->index());
1582 ASSERT(base->index() == m_codeBlock->argumentsRegister());
1583 instructions().append(base->index());
1584 instructions().append(property->index());
1588 RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
1590 for (size_t i = m_forInContextStack.size(); i > 0; i--) {
1591 ForInContext& context = m_forInContextStack[i - 1];
1592 if (context.propertyRegister == property) {
1593 emitOpcode(op_get_by_pname);
1594 instructions().append(dst->index());
1595 instructions().append(base->index());
1596 instructions().append(property->index());
1597 instructions().append(context.expectedSubscriptRegister->index());
1598 instructions().append(context.iterRegister->index());
1599 instructions().append(context.indexRegister->index());
1603 emitOpcode(op_get_by_val);
1604 instructions().append(dst->index());
1605 instructions().append(base->index());
1606 instructions().append(property->index());
1610 RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
1612 emitOpcode(op_put_by_val);
1613 instructions().append(base->index());
1614 instructions().append(property->index());
1615 instructions().append(value->index());
1619 RegisterID* BytecodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
1621 emitOpcode(op_del_by_val);
1622 instructions().append(dst->index());
1623 instructions().append(base->index());
1624 instructions().append(property->index());
1628 RegisterID* BytecodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value)
1630 emitOpcode(op_put_by_index);
1631 instructions().append(base->index());
1632 instructions().append(index);
1633 instructions().append(value->index());
1637 RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst)
1639 emitOpcode(op_new_object);
1640 instructions().append(dst->index());
1644 unsigned BytecodeGenerator::addConstantBuffer(unsigned length)
1646 return m_codeBlock->addConstantBuffer(length);
1649 JSString* BytecodeGenerator::addStringConstant(const Identifier& identifier)
1651 JSString*& stringInMap = m_stringMap.add(identifier.impl(), 0).first->second;
1653 stringInMap = jsString(globalData(), identifier.ustring());
1654 addConstantValue(stringInMap);
1659 RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements, unsigned length)
1661 #if !ASSERT_DISABLED
1662 unsigned checkLength = 0;
1664 bool hadVariableExpression = false;
1666 for (ElementNode* n = elements; n; n = n->next()) {
1667 if (!n->value()->isNumber() && !n->value()->isString()) {
1668 hadVariableExpression = true;
1673 #if !ASSERT_DISABLED
1677 if (!hadVariableExpression) {
1678 ASSERT(length == checkLength);
1679 unsigned constantBufferIndex = addConstantBuffer(length);
1680 JSValue* constantBuffer = m_codeBlock->constantBuffer(constantBufferIndex);
1682 for (ElementNode* n = elements; index < length; n = n->next()) {
1683 if (n->value()->isNumber())
1684 constantBuffer[index++] = jsNumber(static_cast<NumberNode*>(n->value())->value());
1686 ASSERT(n->value()->isString());
1687 constantBuffer[index++] = addStringConstant(static_cast<StringNode*>(n->value())->value());
1690 emitOpcode(op_new_array_buffer);
1691 instructions().append(dst->index());
1692 instructions().append(constantBufferIndex);
1693 instructions().append(length);
1698 Vector<RefPtr<RegisterID>, 16> argv;
1699 for (ElementNode* n = elements; n; n = n->next()) {
1702 argv.append(newTemporary());
1703 // op_new_array requires the initial values to be a sequential range of registers
1704 ASSERT(argv.size() == 1 || argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1);
1705 emitNode(argv.last().get(), n->value());
1707 emitOpcode(op_new_array);
1708 instructions().append(dst->index());
1709 instructions().append(argv.size() ? argv[0]->index() : 0); // argv
1710 instructions().append(argv.size()); // argc
1714 RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function)
1716 return emitNewFunctionInternal(dst, m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)), false);
1719 RegisterID* BytecodeGenerator::emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* function)
1721 std::pair<FunctionOffsetMap::iterator, bool> ptr = m_functionOffsets.add(function, 0);
1723 ptr.first->second = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function));
1724 return emitNewFunctionInternal(dst, ptr.first->second, true);
1727 RegisterID* BytecodeGenerator::emitNewFunctionInternal(RegisterID* dst, unsigned index, bool doNullCheck)
1729 createActivationIfNecessary();
1730 emitOpcode(op_new_func);
1731 instructions().append(dst->index());
1732 instructions().append(index);
1733 instructions().append(doNullCheck);
1737 RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
1739 emitOpcode(op_new_regexp);
1740 instructions().append(dst->index());
1741 instructions().append(addRegExp(regExp));
1745 RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
1747 FunctionBodyNode* function = n->body();
1748 unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function));
1750 createActivationIfNecessary();
1751 emitOpcode(op_new_func_exp);
1752 instructions().append(r0->index());
1753 instructions().append(index);
1757 RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
1759 return emitCall(op_call, dst, func, callArguments, divot, startOffset, endOffset);
1762 void BytecodeGenerator::createArgumentsIfNecessary()
1764 if (m_codeType != FunctionCode)
1767 if (!m_codeBlock->usesArguments())
1770 // If we're in strict mode we tear off the arguments on function
1771 // entry, so there's no need to check if we need to create them
1773 if (m_codeBlock->isStrictMode())
1776 emitOpcode(op_create_arguments);
1777 instructions().append(m_codeBlock->argumentsRegister());
1780 void BytecodeGenerator::createActivationIfNecessary()
1782 if (m_hasCreatedActivation)
1784 if (!m_codeBlock->needsFullScopeChain())
1786 emitOpcode(op_create_activation);
1787 instructions().append(m_activationRegister->index());
1790 RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
1792 return emitCall(op_call_eval, dst, func, callArguments, divot, startOffset, endOffset);
1795 RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
1797 ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
1798 ASSERT(func->refCount());
1800 if (m_shouldEmitProfileHooks)
1801 emitMove(callArguments.profileHookRegister(), func);
1803 // Generate code for arguments.
1804 unsigned argumentIndex = 0;
1805 for (ArgumentListNode* n = callArguments.argumentsNode()->m_listNode; n; n = n->m_next)
1806 emitNode(callArguments.argumentRegister(argumentIndex++), n);
1808 // Reserve space for call frame.
1809 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
1810 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
1811 callFrame.append(newTemporary());
1813 if (m_shouldEmitProfileHooks) {
1814 emitOpcode(op_profile_will_call);
1815 instructions().append(callArguments.profileHookRegister()->index());
1818 emitExpressionInfo(divot, startOffset, endOffset);
1821 emitOpcode(opcodeID);
1822 instructions().append(func->index()); // func
1823 instructions().append(callArguments.count()); // argCount
1824 instructions().append(callArguments.registerOffset()); // registerOffset
1825 if (dst != ignoredResult()) {
1826 emitOpcode(op_call_put_result);
1827 instructions().append(dst->index()); // dst
1830 if (m_shouldEmitProfileHooks) {
1831 emitOpcode(op_profile_did_call);
1832 instructions().append(callArguments.profileHookRegister()->index());
1838 RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, RegisterID* profileHookRegister, unsigned divot, unsigned startOffset, unsigned endOffset)
1840 if (m_shouldEmitProfileHooks) {
1841 emitMove(profileHookRegister, func);
1842 emitOpcode(op_profile_will_call);
1843 instructions().append(profileHookRegister->index());
1846 emitExpressionInfo(divot, startOffset, endOffset);
1849 emitOpcode(op_call_varargs);
1850 instructions().append(func->index());
1851 instructions().append(thisRegister->index());
1852 instructions().append(arguments->index());
1853 instructions().append(firstFreeRegister->index());
1854 if (dst != ignoredResult()) {
1855 emitOpcode(op_call_put_result);
1856 instructions().append(dst->index());
1858 if (m_shouldEmitProfileHooks) {
1859 emitOpcode(op_profile_did_call);
1860 instructions().append(profileHookRegister->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 && !m_codeBlock->isStrictMode()) {
1872 emitOpcode(op_tear_off_arguments);
1873 instructions().append(m_codeBlock->argumentsRegister());
1876 // Constructors use op_ret_object_or_this to check the result is an
1877 // object, unless we can trivially determine the check is not
1878 // necessary (currently, if the return value is 'this').
1879 if (isConstructor() && (src->index() != m_thisRegister.index())) {
1880 emitOpcode(op_ret_object_or_this);
1881 instructions().append(src->index());
1882 instructions().append(m_thisRegister.index());
1885 return emitUnaryNoDstOp(op_ret, src);
1888 RegisterID* BytecodeGenerator::emitUnaryNoDstOp(OpcodeID opcodeID, RegisterID* src)
1890 emitOpcode(opcodeID);
1891 instructions().append(src->index());
1895 RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, CallArguments& callArguments, unsigned divot, unsigned startOffset, unsigned endOffset)
1897 ASSERT(func->refCount());
1899 if (m_shouldEmitProfileHooks)
1900 emitMove(callArguments.profileHookRegister(), func);
1902 // Generate code for arguments.
1903 unsigned argumentIndex = 0;
1904 if (ArgumentsNode* argumentsNode = callArguments.argumentsNode()) {
1905 for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next)
1906 emitNode(callArguments.argumentRegister(argumentIndex++), n);
1909 if (m_shouldEmitProfileHooks) {
1910 emitOpcode(op_profile_will_call);
1911 instructions().append(callArguments.profileHookRegister()->index());
1914 // Reserve space for call frame.
1915 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
1916 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
1917 callFrame.append(newTemporary());
1919 emitExpressionInfo(divot, startOffset, endOffset);
1921 emitOpcode(op_construct);
1922 instructions().append(func->index()); // func
1923 instructions().append(callArguments.count()); // argCount
1924 instructions().append(callArguments.registerOffset()); // registerOffset
1925 if (dst != ignoredResult()) {
1926 emitOpcode(op_call_put_result);
1927 instructions().append(dst->index()); // dst
1930 if (m_shouldEmitProfileHooks) {
1931 emitOpcode(op_profile_did_call);
1932 instructions().append(callArguments.profileHookRegister()->index());
1938 RegisterID* BytecodeGenerator::emitStrcat(RegisterID* dst, RegisterID* src, int count)
1940 emitOpcode(op_strcat);
1941 instructions().append(dst->index());
1942 instructions().append(src->index());
1943 instructions().append(count);
1948 void BytecodeGenerator::emitToPrimitive(RegisterID* dst, RegisterID* src)
1950 emitOpcode(op_to_primitive);
1951 instructions().append(dst->index());
1952 instructions().append(src->index());
1955 RegisterID* BytecodeGenerator::emitPushScope(RegisterID* scope)
1957 ASSERT(scope->isTemporary());
1958 ControlFlowContext context;
1959 context.isFinallyBlock = false;
1960 m_scopeContextStack.append(context);
1961 m_dynamicScopeDepth++;
1963 return emitUnaryNoDstOp(op_push_scope, scope);
1966 void BytecodeGenerator::emitPopScope()
1968 ASSERT(m_scopeContextStack.size());
1969 ASSERT(!m_scopeContextStack.last().isFinallyBlock);
1971 emitOpcode(op_pop_scope);
1973 m_scopeContextStack.removeLast();
1974 m_dynamicScopeDepth--;
1977 void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine)
1979 #if ENABLE(DEBUG_WITH_BREAKPOINT)
1980 if (debugHookID != DidReachBreakpoint)
1983 if (!m_shouldEmitDebugHooks)
1986 emitOpcode(op_debug);
1987 instructions().append(debugHookID);
1988 instructions().append(firstLine);
1989 instructions().append(lastLine);
1992 void BytecodeGenerator::pushFinallyContext(Label* target, RegisterID* retAddrDst)
1994 ControlFlowContext scope;
1995 scope.isFinallyBlock = true;
1996 FinallyContext context = { target, retAddrDst };
1997 scope.finallyContext = context;
1998 m_scopeContextStack.append(scope);
2002 void BytecodeGenerator::popFinallyContext()
2004 ASSERT(m_scopeContextStack.size());
2005 ASSERT(m_scopeContextStack.last().isFinallyBlock);
2006 ASSERT(m_finallyDepth > 0);
2007 m_scopeContextStack.removeLast();
2011 LabelScope* BytecodeGenerator::breakTarget(const Identifier& name)
2013 // Reclaim free label scopes.
2015 // The condition was previously coded as 'm_labelScopes.size() && !m_labelScopes.last().refCount()',
2016 // however sometimes this appears to lead to GCC going a little haywire and entering the loop with
2017 // size 0, leading to segfaulty badness. We are yet to identify a valid cause within our code to
2018 // cause the GCC codegen to misbehave in this fashion, and as such the following refactoring of the
2019 // loop condition is a workaround.
2020 while (m_labelScopes.size()) {
2021 if (m_labelScopes.last().refCount())
2023 m_labelScopes.removeLast();
2026 if (!m_labelScopes.size())
2029 // We special-case the following, which is a syntax error in Firefox:
2032 if (name.isEmpty()) {
2033 for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
2034 LabelScope* scope = &m_labelScopes[i];
2035 if (scope->type() != LabelScope::NamedLabel) {
2036 ASSERT(scope->breakTarget());
2043 for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
2044 LabelScope* scope = &m_labelScopes[i];
2045 if (scope->name() && *scope->name() == name) {
2046 ASSERT(scope->breakTarget());
2053 LabelScope* BytecodeGenerator::continueTarget(const Identifier& name)
2055 // Reclaim free label scopes.
2056 while (m_labelScopes.size() && !m_labelScopes.last().refCount())
2057 m_labelScopes.removeLast();
2059 if (!m_labelScopes.size())
2062 if (name.isEmpty()) {
2063 for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
2064 LabelScope* scope = &m_labelScopes[i];
2065 if (scope->type() == LabelScope::Loop) {
2066 ASSERT(scope->continueTarget());
2073 // Continue to the loop nested nearest to the label scope that matches
2075 LabelScope* result = 0;
2076 for (int i = m_labelScopes.size() - 1; i >= 0; --i) {
2077 LabelScope* scope = &m_labelScopes[i];
2078 if (scope->type() == LabelScope::Loop) {
2079 ASSERT(scope->continueTarget());
2082 if (scope->name() && *scope->name() == name)
2083 return result; // may be 0
2088 PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope)
2090 while (topScope > bottomScope) {
2091 // First we count the number of dynamic scopes we need to remove to get
2092 // to a finally block.
2093 int nNormalScopes = 0;
2094 while (topScope > bottomScope) {
2095 if (topScope->isFinallyBlock)
2101 if (nNormalScopes) {
2102 size_t begin = instructions().size();
2104 // We need to remove a number of dynamic scopes to get to the next
2106 emitOpcode(op_jmp_scopes);
2107 instructions().append(nNormalScopes);
2109 // If topScope == bottomScope then there isn't actually a finally block
2110 // left to emit, so make the jmp_scopes jump directly to the target label
2111 if (topScope == bottomScope) {
2112 instructions().append(target->bind(begin, instructions().size()));
2116 // Otherwise we just use jmp_scopes to pop a group of scopes and go
2117 // to the next instruction
2118 RefPtr<Label> nextInsn = newLabel();
2119 instructions().append(nextInsn->bind(begin, instructions().size()));
2120 emitLabel(nextInsn.get());
2123 while (topScope > bottomScope && topScope->isFinallyBlock) {
2124 emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr);
2128 return emitJump(target);
2131 PassRefPtr<Label> BytecodeGenerator::emitJumpScopes(Label* target, int targetScopeDepth)
2133 ASSERT(scopeDepth() - targetScopeDepth >= 0);
2134 ASSERT(target->isForward());
2136 size_t scopeDelta = scopeDepth() - targetScopeDepth;
2137 ASSERT(scopeDelta <= m_scopeContextStack.size());
2139 return emitJump(target);
2142 return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta);
2144 size_t begin = instructions().size();
2146 emitOpcode(op_jmp_scopes);
2147 instructions().append(scopeDelta);
2148 instructions().append(target->bind(begin, instructions().size()));
2152 RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget)
2154 size_t begin = instructions().size();
2156 emitOpcode(op_get_pnames);
2157 instructions().append(dst->index());
2158 instructions().append(base->index());
2159 instructions().append(i->index());
2160 instructions().append(size->index());
2161 instructions().append(breakTarget->bind(begin, instructions().size()));
2165 RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target)
2167 size_t begin = instructions().size();
2169 emitOpcode(op_next_pname);
2170 instructions().append(dst->index());
2171 instructions().append(base->index());
2172 instructions().append(i->index());
2173 instructions().append(size->index());
2174 instructions().append(iter->index());
2175 instructions().append(target->bind(begin, instructions().size()));
2179 RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* start, Label* end)
2181 m_usesExceptions = true;
2183 HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() };
2185 HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth };
2188 m_codeBlock->addExceptionHandler(info);
2189 emitOpcode(op_catch);
2190 instructions().append(targetRegister->index());
2191 return targetRegister;
2194 void BytecodeGenerator::emitThrowReferenceError(const UString& message)
2196 emitOpcode(op_throw_reference_error);
2197 instructions().append(addConstantValue(jsString(globalData(), message))->index());
2200 PassRefPtr<Label> BytecodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, Label* finally)
2202 size_t begin = instructions().size();
2205 instructions().append(retAddrDst->index());
2206 instructions().append(finally->bind(begin, instructions().size()));
2207 emitLabel(newLabel().get()); // Record the fact that the next instruction is implicitly labeled, because op_sret will return to it.
2211 void BytecodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc)
2213 emitOpcode(op_sret);
2214 instructions().append(retAddrSrc->index());
2217 void BytecodeGenerator::emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value)
2219 ControlFlowContext context;
2220 context.isFinallyBlock = false;
2221 m_scopeContextStack.append(context);
2222 m_dynamicScopeDepth++;
2224 emitOpcode(op_push_new_scope);
2225 instructions().append(dst->index());
2226 instructions().append(addConstant(property));
2227 instructions().append(value->index());
2230 void BytecodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type)
2232 SwitchInfo info = { instructions().size(), type };
2234 case SwitchInfo::SwitchImmediate:
2235 emitOpcode(op_switch_imm);
2237 case SwitchInfo::SwitchCharacter:
2238 emitOpcode(op_switch_char);
2240 case SwitchInfo::SwitchString:
2241 emitOpcode(op_switch_string);
2244 ASSERT_NOT_REACHED();
2247 instructions().append(0); // place holder for table index
2248 instructions().append(0); // place holder for default target
2249 instructions().append(scrutineeRegister->index());
2250 m_switchContextStack.append(info);
2253 static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max)
2256 ASSERT(node->isNumber());
2257 double value = static_cast<NumberNode*>(node)->value();
2258 int32_t key = static_cast<int32_t>(value);
2259 ASSERT(key == value);
2265 static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
2267 jumpTable.min = min;
2268 jumpTable.branchOffsets.resize(max - min + 1);
2269 jumpTable.branchOffsets.fill(0);
2270 for (uint32_t i = 0; i < clauseCount; ++i) {
2271 // We're emitting this after the clause labels should have been fixed, so
2272 // the labels should not be "forward" references
2273 ASSERT(!labels[i]->isForward());
2274 jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3));
2278 static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max)
2281 ASSERT(node->isString());
2282 StringImpl* clause = static_cast<StringNode*>(node)->value().impl();
2283 ASSERT(clause->length() == 1);
2285 int32_t key = (*clause)[0];
2291 static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
2293 jumpTable.min = min;
2294 jumpTable.branchOffsets.resize(max - min + 1);
2295 jumpTable.branchOffsets.fill(0);
2296 for (uint32_t i = 0; i < clauseCount; ++i) {
2297 // We're emitting this after the clause labels should have been fixed, so
2298 // the labels should not be "forward" references
2299 ASSERT(!labels[i]->isForward());
2300 jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3));
2304 static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes)
2306 for (uint32_t i = 0; i < clauseCount; ++i) {
2307 // We're emitting this after the clause labels should have been fixed, so
2308 // the labels should not be "forward" references
2309 ASSERT(!labels[i]->isForward());
2311 ASSERT(nodes[i]->isString());
2312 StringImpl* clause = static_cast<StringNode*>(nodes[i])->value().impl();
2313 OffsetLocation location;
2314 location.branchOffset = labels[i]->bind(switchAddress, switchAddress + 3);
2315 jumpTable.offsetTable.add(clause, location);
2319 void BytecodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, Label* defaultLabel, int32_t min, int32_t max)
2321 SwitchInfo switchInfo = m_switchContextStack.last();
2322 m_switchContextStack.removeLast();
2323 if (switchInfo.switchType == SwitchInfo::SwitchImmediate) {
2324 instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfImmediateSwitchJumpTables();
2325 instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
2327 SimpleJumpTable& jumpTable = m_codeBlock->addImmediateSwitchJumpTable();
2328 prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max);
2329 } else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) {
2330 instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfCharacterSwitchJumpTables();
2331 instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
2333 SimpleJumpTable& jumpTable = m_codeBlock->addCharacterSwitchJumpTable();
2334 prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max);
2336 ASSERT(switchInfo.switchType == SwitchInfo::SwitchString);
2337 instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfStringSwitchJumpTables();
2338 instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3);
2340 StringJumpTable& jumpTable = m_codeBlock->addStringSwitchJumpTable();
2341 prepareJumpTableForStringSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes);
2345 RegisterID* BytecodeGenerator::emitThrowExpressionTooDeepException()
2347 // It would be nice to do an even better job of identifying exactly where the expression is.
2348 // And we could make the caller pass the node pointer in, if there was some way of getting
2349 // that from an arbitrary node. However, calling emitExpressionInfo without any useful data
2350 // is still good enough to get us an accurate line number.
2351 m_expressionTooDeep = true;
2352 return newTemporary();
2355 void BytecodeGenerator::setIsNumericCompareFunction(bool isNumericCompareFunction)
2357 m_codeBlock->setIsNumericCompareFunction(isNumericCompareFunction);
2360 bool BytecodeGenerator::isArgumentNumber(const Identifier& ident, int argumentNumber)
2362 RegisterID* registerID = registerFor(ident);
2363 if (!registerID || registerID->index() >= 0)
2365 return registerID->index() - m_thisRegister.index() - 1 == argumentNumber;