2 * Copyright (C) 2008 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 "CodeGenerator.h"
33 #include "JSFunction.h"
42 The layout of a register frame looks like this:
53 assuming (x) and (y) generated temporaries t1 and t2, you would have
55 ------------------------------------
56 | x | y | g | v2 | v1 | t1 | t2 | <-- value held
57 ------------------------------------
58 | -5 | -4 | -3 | -2 | -1 | +0 | +1 | <-- register index
59 ------------------------------------
60 | params->|<-locals | temps->
62 Because temporary registers are allocated in a stack-like fashion, we
63 can reclaim them with a simple popping algorithm. The same goes for labels.
64 (We never reclaim parameter or local registers, because parameters and
65 locals are DontDelete.)
67 The register layout before a function call looks like this:
77 > <------------------------------
78 < > reserved: call frame | 1 | <-- value held
79 > >snip< <------------------------------
80 < > +0 | +1 | +2 | +3 | +4 | +5 | <-- register index
81 > <------------------------------
82 | params->|<-locals | temps->
84 The call instruction fills in the "call frame" registers. It also pads
85 missing arguments at the end of the call:
87 > <-----------------------------------
88 < > reserved: call frame | 1 | ? | <-- value held ("?" stands for "undefined")
89 > >snip< <-----------------------------------
90 < > +0 | +1 | +2 | +3 | +4 | +5 | +6 | <-- register index
91 > <-----------------------------------
92 | params->|<-locals | temps->
94 After filling in missing arguments, the call instruction sets up the new
95 stack frame to overlap the end of the old stack frame:
97 |----------------------------------> <
98 | reserved: call frame | 1 | ? < > <-- value held ("?" stands for "undefined")
99 |----------------------------------> >snip< <
100 | -7 | -6 | -5 | -4 | -3 | -2 | -1 < > <-- register index
101 |----------------------------------> <
102 | | params->|<-locals | temps->
104 That way, arguments are "copied" into the callee's stack frame for free.
106 If the caller supplies too many arguments, this trick doesn't work. The
107 extra arguments protrude into space reserved for locals and temporaries.
108 In that case, the call instruction makes a real copy of the call frame header,
109 along with just the arguments expected by the callee, leaving the original
110 call frame header and arguments behind. (The call instruction can't just discard
111 extra arguments, because the "arguments" object may access them later.)
112 This copying strategy ensures that all named values will be at the indices
113 expected by the callee.
117 bool CodeGenerator::s_dumpsGeneratedCode = false;
120 void CodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode)
123 s_dumpsGeneratedCode = dumpsGeneratedCode;
125 UNUSED_PARAM(dumpsGeneratedCode);
129 void CodeGenerator::generate()
131 m_codeBlock->numLocals = m_codeBlock->numVars + m_codeBlock->numParameters;
132 m_codeBlock->thisRegister = m_thisRegister.index();
133 if (m_shouldEmitDebugHooks)
134 m_codeBlock->needsFullScopeChain = true;
136 m_scopeNode->emitCode(*this);
139 if (s_dumpsGeneratedCode) {
140 JSGlobalObject* globalObject = m_scopeChain->globalObject();
141 m_codeBlock->dump(globalObject->globalExec());
145 m_scopeNode->children().shrinkCapacity(0);
146 if (m_codeType != EvalCode) { // eval code needs to hang on to its declaration stacks to keep declaration info alive until Machine::execute time.
147 m_scopeNode->varStack().shrinkCapacity(0);
148 m_scopeNode->functionStack().shrinkCapacity(0);
152 bool CodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
154 int index = m_nextVar;
155 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
156 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
159 index = result.first->second.getIndex();
162 ++m_codeBlock->numVars;
164 m_locals.append(index);
167 r0 = &m_locals[localsIndex(index)];
168 return result.second;
171 bool CodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
173 int index = m_nextVar;
174 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
175 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
178 index = result.first->second.getIndex();
181 m_locals.append(index + m_globalVarStorageOffset);
184 r0 = &m_locals[localsIndex(index)];
185 return result.second;
188 CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, VarStack& varStack, FunctionStack& functionStack)
189 : m_shouldEmitDebugHooks(!!debugger)
190 , m_scopeChain(&scopeChain)
191 , m_symbolTable(symbolTable)
192 , m_scopeNode(programNode)
193 , m_codeBlock(codeBlock)
194 , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
196 , m_dynamicScopeDepth(0)
197 , m_codeType(GlobalCode)
200 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
201 , m_lastOpcodeID(op_end)
203 // FIXME: Move code that modifies the global object to Machine::execute.
205 m_codeBlock->numConstants = programNode->neededConstants();
206 m_codeBlock->numVars = 1; // Allocate space for "this"
208 JSGlobalObject* globalObject = scopeChain.globalObject();
209 ExecState* exec = globalObject->globalExec();
210 RegisterFile* registerFile = &exec->globalData().machine->registerFile();
212 // Shift register indexes in generated code to elide registers allocated by intermediate stack frames.
213 m_globalVarStorageOffset = -1 - RegisterFile::CallFrameHeaderSize - registerFile->size();
215 // Add previously defined symbols to bookkeeping.
216 m_locals.resize(symbolTable->size());
217 SymbolTable::iterator end = symbolTable->end();
218 for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
219 m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex() + m_globalVarStorageOffset);
221 bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();
222 if (canOptimizeNewGlobals) {
223 // Shift new symbols so they get stored prior to existing symbols.
224 m_nextVar -= symbolTable->size();
226 for (size_t i = 0; i < functionStack.size(); ++i) {
227 FuncDeclNode* funcDecl = functionStack[i].get();
228 globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
229 emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);
232 for (size_t i = 0; i < varStack.size(); ++i) {
233 if (!globalObject->hasProperty(exec, varStack[i].first))
234 emitLoad(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant), jsUndefined());
237 for (size_t i = 0; i < functionStack.size(); ++i) {
238 FuncDeclNode* funcDecl = functionStack[i].get();
239 globalObject->putWithAttributes(exec, funcDecl->m_ident, funcDecl->makeFunction(exec, scopeChain.node()), DontDelete);
241 for (size_t i = 0; i < varStack.size(); ++i) {
242 if (globalObject->hasProperty(exec, varStack[i].first))
244 int attributes = DontDelete;
245 if (varStack[i].second & DeclarationStacks::IsConstant)
246 attributes |= ReadOnly;
247 globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes);
252 CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock)
253 : m_shouldEmitDebugHooks(!!debugger)
254 , m_scopeChain(&scopeChain)
255 , m_symbolTable(symbolTable)
256 , m_scopeNode(functionBody)
257 , m_codeBlock(codeBlock)
259 , m_dynamicScopeDepth(0)
260 , m_codeType(FunctionCode)
263 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
264 , m_lastOpcodeID(op_end)
266 m_codeBlock->numConstants = functionBody->neededConstants();
268 const Node::FunctionStack& functionStack = functionBody->functionStack();
269 for (size_t i = 0; i < functionStack.size(); ++i) {
270 FuncDeclNode* funcDecl = functionStack[i].get();
271 const Identifier& ident = funcDecl->m_ident;
273 m_functions.add(ident.ustring().rep());
274 emitNewFunction(addVar(ident, false), funcDecl);
277 const Node::VarStack& varStack = functionBody->varStack();
278 for (size_t i = 0; i < varStack.size(); ++i) {
279 const Identifier& ident = varStack[i].first;
280 if (ident == propertyNames().arguments)
282 addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
285 Vector<Identifier>& parameters = functionBody->parameters();
286 m_nextParameter = m_nextVar - parameters.size(); // parameters are allocated prior to vars
287 m_locals.resize(localsIndex(m_nextParameter) + 1); // localsIndex of 0 => m_locals size of 1
289 // Add "this" as a parameter
290 m_thisRegister.setIndex(m_nextParameter);
292 ++m_codeBlock->numParameters;
294 for (size_t i = 0; i < parameters.size(); ++i)
295 addParameter(parameters[i]);
298 CodeGenerator::CodeGenerator(EvalNode* evalNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock)
299 : m_shouldEmitDebugHooks(!!debugger)
300 , m_scopeChain(&scopeChain)
301 , m_symbolTable(symbolTable)
302 , m_scopeNode(evalNode)
303 , m_codeBlock(codeBlock)
304 , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
306 , m_dynamicScopeDepth(0)
307 , m_codeType(EvalCode)
309 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
310 , m_lastOpcodeID(op_end)
312 m_codeBlock->numConstants = evalNode->neededConstants();
313 m_codeBlock->numVars = 1; // Allocate space for "this"
316 CodeGenerator::~CodeGenerator()
320 RegisterID* CodeGenerator::addParameter(const Identifier& ident)
322 // Parameters overwrite var declarations, but not function declarations,
323 // in the symbol table.
324 RegisterID* result = 0;
325 UString::Rep* rep = ident.ustring().rep();
326 if (!m_functions.contains(rep)) {
327 symbolTable().set(rep, m_nextParameter);
328 m_locals[localsIndex(m_nextParameter)].setIndex(m_nextParameter);
329 result = &(m_locals[localsIndex(m_nextParameter)]);
332 // To maintain the calling convention, we have to allocate unique space for
333 // each parameter, even if the parameter doesn't make it into the symbol table.
335 ++m_codeBlock->numParameters;
339 RegisterID* CodeGenerator::registerForLocal(const Identifier& ident)
341 if (m_codeType == FunctionCode && ident == propertyNames().arguments)
342 m_codeBlock->needsFullScopeChain = true;
344 if (ident == propertyNames().thisIdentifier)
345 return &m_thisRegister;
347 if (!shouldOptimizeLocals())
350 SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
354 return &m_locals[localsIndex(entry.getIndex())];
357 RegisterID* CodeGenerator::registerForLocalConstInit(const Identifier& ident)
359 if (m_codeType == EvalCode)
362 SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
363 ASSERT(!entry.isNull());
365 return &m_locals[localsIndex(entry.getIndex())];
368 bool CodeGenerator::isLocal(const Identifier& ident)
370 if (ident == propertyNames().thisIdentifier)
373 return shouldOptimizeLocals() && symbolTable().contains(ident.ustring().rep());
376 bool CodeGenerator::isLocalConstant(const Identifier& ident)
378 return symbolTable().get(ident.ustring().rep()).isReadOnly();
381 RegisterID* CodeGenerator::newTemporary()
383 // Reclaim free register IDs.
384 while (m_temporaries.size() && !m_temporaries.last().refCount())
385 m_temporaries.removeLast();
387 // Allocate new register ID.
388 m_temporaries.append(m_temporaries.size() + m_codeBlock->numConstants);
389 m_codeBlock->numTemporaries = max<int>(m_codeBlock->numTemporaries, m_temporaries.size());
390 return &m_temporaries.last();
393 RegisterID* CodeGenerator::highestUsedRegister()
395 while (m_temporaries.size() < static_cast<unsigned>(m_codeBlock->numTemporaries))
396 m_temporaries.append(m_temporaries.size());
397 return &m_temporaries.last();
400 PassRefPtr<LabelID> CodeGenerator::newLabel()
402 // Reclaim free label IDs.
403 while (m_labels.size() && !m_labels.last().refCount())
404 m_labels.removeLast();
406 // Allocate new label ID.
407 m_labels.append(m_codeBlock);
408 return &m_labels.last();
411 PassRefPtr<LabelID> CodeGenerator::emitLabel(LabelID* l0)
413 l0->setLocation(instructions().size());
415 // This disables peephole optimizations when an instruction is a jump target
416 m_lastOpcodeID = op_end;
421 void CodeGenerator::emitOpcode(OpcodeID opcodeID)
423 instructions().append(globalData()->machine->getOpcode(opcodeID));
424 m_lastOpcodeID = opcodeID;
427 void CodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
429 ASSERT(instructions().size() >= 4);
430 size_t size = instructions().size();
431 dstIndex = instructions().at(size - 3).u.operand;
432 src1Index = instructions().at(size - 2).u.operand;
433 src2Index = instructions().at(size - 1).u.operand;
436 void ALWAYS_INLINE CodeGenerator::rewindBinaryOp()
438 ASSERT(instructions().size() >= 4);
439 instructions().shrink(instructions().size() - 4);
442 PassRefPtr<LabelID> CodeGenerator::emitJump(LabelID* target)
444 emitOpcode(target->isForwardLabel() ? op_jmp : op_loop);
445 instructions().append(target->offsetFrom(instructions().size()));
449 PassRefPtr<LabelID> CodeGenerator::emitJumpIfTrue(RegisterID* cond, LabelID* target)
451 if (m_lastOpcodeID == op_less) {
456 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
458 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
460 emitOpcode(target->isForwardLabel() ? op_jless : op_loop_if_less);
461 instructions().append(src1Index);
462 instructions().append(src2Index);
463 instructions().append(target->offsetFrom(instructions().size()));
468 emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true);
469 instructions().append(cond->index());
470 instructions().append(target->offsetFrom(instructions().size()));
474 PassRefPtr<LabelID> CodeGenerator::emitJumpIfFalse(RegisterID* cond, LabelID* target)
476 ASSERT(target->isForwardLabel());
478 if (m_lastOpcodeID == op_less) {
483 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
485 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
487 emitOpcode(op_jnless);
488 instructions().append(src1Index);
489 instructions().append(src2Index);
490 instructions().append(target->offsetFrom(instructions().size()));
495 emitOpcode(op_jfalse);
496 instructions().append(cond->index());
497 instructions().append(target->offsetFrom(instructions().size()));
501 unsigned CodeGenerator::addConstant(FuncDeclNode* n)
503 // No need to explicitly unique function body nodes -- they're unique already.
504 int index = m_codeBlock->functions.size();
505 m_codeBlock->functions.append(n);
509 unsigned CodeGenerator::addConstant(FuncExprNode* n)
511 // No need to explicitly unique function expression nodes -- they're unique already.
512 int index = m_codeBlock->functionExpressions.size();
513 m_codeBlock->functionExpressions.append(n);
517 unsigned CodeGenerator::addConstant(const Identifier& ident)
519 UString::Rep* rep = ident.ustring().rep();
520 pair<IdentifierMap::iterator, bool> result = m_identifierMap.add(rep, m_codeBlock->identifiers.size());
521 if (result.second) // new entry
522 m_codeBlock->identifiers.append(Identifier(m_globalData, rep));
524 return result.first->second;
527 RegisterID* CodeGenerator::addConstant(JSValue* v)
529 pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(v, m_codeBlock->constantRegisters.size());
531 m_constants.append(m_codeBlock->constantRegisters.size());
532 m_constants.last().makeConstant();
533 m_codeBlock->constantRegisters.append(v);
534 ASSERT(m_codeBlock->constantRegisters.size() <= (unsigned) m_codeBlock->numConstants);
535 return &m_constants.last();
538 return &m_constants[result.first->second];
541 unsigned CodeGenerator::addUnexpectedConstant(JSValue* v)
543 int index = m_codeBlock->regexps.size();
544 m_codeBlock->unexpectedConstants.append(v);
548 unsigned CodeGenerator::addRegExp(RegExp* r)
550 int index = m_codeBlock->regexps.size();
551 m_codeBlock->regexps.append(r);
555 RegisterID* CodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
558 instructions().append(dst->index());
559 instructions().append(src->index());
563 RegisterID* CodeGenerator::emitUnaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src)
566 instructions().append(dst->index());
567 instructions().append(src->index());
571 RegisterID* CodeGenerator::emitPreInc(RegisterID* srcDst)
573 emitOpcode(op_pre_inc);
574 instructions().append(srcDst->index());
578 RegisterID* CodeGenerator::emitPreDec(RegisterID* srcDst)
580 emitOpcode(op_pre_dec);
581 instructions().append(srcDst->index());
585 RegisterID* CodeGenerator::emitPostInc(RegisterID* dst, RegisterID* srcDst)
587 emitOpcode(op_post_inc);
588 instructions().append(dst->index());
589 instructions().append(srcDst->index());
593 RegisterID* CodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst)
595 emitOpcode(op_post_dec);
596 instructions().append(dst->index());
597 instructions().append(srcDst->index());
601 RegisterID* CodeGenerator::emitBinaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src1, RegisterID* src2)
604 instructions().append(dst->index());
605 instructions().append(src1->index());
606 instructions().append(src2->index());
610 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, bool b)
612 return emitLoad(dst, jsBoolean(b));
615 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, double d)
617 return emitLoad(dst, jsNumber(globalExec(), d));
620 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, JSValue* v)
622 RegisterID* constantID = addConstant(v);
624 return emitMove(dst, constantID);
628 RegisterID* CodeGenerator::emitUnexpectedLoad(RegisterID* dst, bool b)
630 emitOpcode(op_unexpected_load);
631 instructions().append(dst->index());
632 instructions().append(addUnexpectedConstant(jsBoolean(b)));
636 RegisterID* CodeGenerator::emitNullaryOp(OpcodeID opcode, RegisterID* dst)
639 instructions().append(dst->index());
643 bool CodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting)
645 // Cases where we cannot optimise the lookup
646 if (property == propertyNames().arguments || !canOptimizeNonLocals()) {
648 index = missingSymbolMarker();
652 ScopeChainIterator iter = m_scopeChain->begin();
653 ScopeChainIterator end = m_scopeChain->end();
656 for (; iter != end; ++iter, ++depth) {
657 JSObject* currentScope = *iter;
658 if (!currentScope->isVariableObject())
660 JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
661 SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.ustring().rep());
663 // Found the property
664 if (!entry.isNull()) {
665 if (entry.isReadOnly() && forWriting) {
667 index = missingSymbolMarker();
671 index = entry.getIndex();
674 if (currentVariableObject->isDynamicScope())
678 // Can't locate the property but we're able to avoid a few lookups
680 index = missingSymbolMarker();
684 RegisterID* CodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
688 if (!findScopedProperty(property, index, depth, false)) {
689 // We can't optimise at all :-(
690 emitOpcode(op_resolve);
691 instructions().append(dst->index());
692 instructions().append(addConstant(property));
696 if (index == missingSymbolMarker()) {
697 // In this case we are at least able to drop a few scope chains from the
698 // lookup chain, although we still need to hash from then on.
699 emitOpcode(op_resolve_skip);
700 instructions().append(dst->index());
701 instructions().append(addConstant(property));
702 instructions().append(depth);
706 // Directly index the property lookup across multiple scopes. Yay!
707 return emitGetScopedVar(dst, depth, index);
710 RegisterID* CodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index)
712 emitOpcode(op_get_scoped_var);
713 instructions().append(dst->index());
714 instructions().append(index);
715 instructions().append(depth);
719 RegisterID* CodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value)
721 emitOpcode(op_put_scoped_var);
722 instructions().append(index);
723 instructions().append(depth);
724 instructions().append(value->index());
728 RegisterID* CodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property)
730 emitOpcode(op_resolve_base);
731 instructions().append(dst->index());
732 instructions().append(addConstant(property));
736 RegisterID* CodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
738 emitOpcode(op_resolve_with_base);
739 instructions().append(baseDst->index());
740 instructions().append(propDst->index());
741 instructions().append(addConstant(property));
745 RegisterID* CodeGenerator::emitResolveFunction(RegisterID* baseDst, RegisterID* funcDst, const Identifier& property)
747 emitOpcode(op_resolve_func);
748 instructions().append(baseDst->index());
749 instructions().append(funcDst->index());
750 instructions().append(addConstant(property));
754 RegisterID* CodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
756 emitOpcode(op_get_by_id);
757 instructions().append(dst->index());
758 instructions().append(base->index());
759 instructions().append(addConstant(property));
763 RegisterID* CodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
765 emitOpcode(op_put_by_id);
766 instructions().append(base->index());
767 instructions().append(addConstant(property));
768 instructions().append(value->index());
772 RegisterID* CodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
774 emitOpcode(op_put_getter);
775 instructions().append(base->index());
776 instructions().append(addConstant(property));
777 instructions().append(value->index());
781 RegisterID* CodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
783 emitOpcode(op_put_setter);
784 instructions().append(base->index());
785 instructions().append(addConstant(property));
786 instructions().append(value->index());
790 RegisterID* CodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
792 emitOpcode(op_del_by_id);
793 instructions().append(dst->index());
794 instructions().append(base->index());
795 instructions().append(addConstant(property));
799 RegisterID* CodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
801 emitOpcode(op_get_by_val);
802 instructions().append(dst->index());
803 instructions().append(base->index());
804 instructions().append(property->index());
808 RegisterID* CodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
810 emitOpcode(op_put_by_val);
811 instructions().append(base->index());
812 instructions().append(property->index());
813 instructions().append(value->index());
817 RegisterID* CodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
819 emitOpcode(op_del_by_val);
820 instructions().append(dst->index());
821 instructions().append(base->index());
822 instructions().append(property->index());
826 RegisterID* CodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value)
828 emitOpcode(op_put_by_index);
829 instructions().append(base->index());
830 instructions().append(index);
831 instructions().append(value->index());
835 RegisterID* CodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements)
837 Vector<RefPtr<RegisterID>, 16> argv;
838 for (ElementNode* n = elements; n; n = n->next()) {
841 argv.append(newTemporary());
842 emitNode(argv.last().get(), n->value());
844 emitOpcode(op_new_array);
845 instructions().append(dst->index());
846 instructions().append(argv.size() ? argv[0]->index() : 0); // argv
847 instructions().append(argv.size()); // argc
851 RegisterID* CodeGenerator::emitNewFunction(RegisterID* dst, FuncDeclNode* n)
853 emitOpcode(op_new_func);
854 instructions().append(dst->index());
855 instructions().append(addConstant(n));
859 RegisterID* CodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
861 emitOpcode(op_new_regexp);
862 instructions().append(dst->index());
863 instructions().append(addRegExp(regExp));
868 RegisterID* CodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
870 emitOpcode(op_new_func_exp);
871 instructions().append(r0->index());
872 instructions().append(addConstant(n));
876 RegisterID* CodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
878 return emitCall(op_call, dst, func, base, argumentsNode, divot, startOffset, endOffset);
881 RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
883 return emitCall(op_call_eval, dst, func, base, argumentsNode, divot, startOffset, endOffset);
886 RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
888 ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
890 // Ordinarily, we might ref "func" and "base", to avoid allocating new
891 // temporaries in the same registers. In this case, though, we actually
892 // want the call frame we allocate to overlap "func" and "base", if they're
893 // not otherwise referenced. op_call will read "func" and "base" before
894 // writing out the call frame, so this is safe.
896 // Reserve space for call frame.
897 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
898 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
899 callFrame.append(newTemporary());
901 // Generate code for arguments.
902 Vector<RefPtr<RegisterID>, 16> argv;
903 argv.append(newTemporary()); // reserve space for "this"
904 for (ArgumentListNode* n = argumentsNode->m_listNode.get(); n; n = n->m_next.get()) {
905 argv.append(newTemporary());
906 emitNode(argv.last().get(), n);
909 emitExpressionInfo(divot, startOffset, endOffset);
910 emitOpcode(opcodeID);
911 instructions().append(dst->index());
912 instructions().append(func->index());
913 instructions().append(base ? base->index() : missingThisObjectMarker()); // We encode the "this" value in the instruction stream, to avoid an explicit instruction for copying or loading it.
914 instructions().append(argv.size() ? argv[0]->index() : m_temporaries.size()); // argv
915 instructions().append(argv.size()); // argc
919 RegisterID* CodeGenerator::emitUnaryNoDstOp(OpcodeID opcode, RegisterID* src)
922 instructions().append(src->index());
926 RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode* argumentsNode)
928 // Ordinarily, we might ref "func", to avoid allocating a new temporary in
929 // the same register. In this case, though, we actually want the call
930 // frame we allocate to overlap "func", if it's not otherwise referenced.
931 // op_construct will read "func" before writing out the call frame, so this
934 // Reserve space for call frame.
935 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
936 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
937 callFrame.append(newTemporary());
939 // Generate code for arguments.
940 Vector<RefPtr<RegisterID>, 16> argv;
941 argv.append(newTemporary()); // reserve space for "this"
942 for (ArgumentListNode* n = argumentsNode ? argumentsNode->m_listNode.get() : 0; n; n = n->m_next.get()) {
943 argv.append(newTemporary());
944 emitNode(argv.last().get(), n);
947 emitOpcode(op_construct);
948 instructions().append(dst->index());
949 instructions().append(func->index());
950 instructions().append(argv.size() ? argv[0]->index() : m_temporaries.size()); // argv
951 instructions().append(argv.size()); // argc
955 RegisterID* CodeGenerator::emitPushScope(RegisterID* scope)
957 m_codeBlock->needsFullScopeChain = true;
958 ControlFlowContext context;
959 context.isFinallyBlock = false;
960 m_scopeContextStack.append(context);
961 m_dynamicScopeDepth++;
963 return emitUnaryNoDstOp(op_push_scope, scope);
966 void CodeGenerator::emitPopScope()
968 ASSERT(m_scopeContextStack.size());
969 ASSERT(!m_scopeContextStack.last().isFinallyBlock);
971 emitOpcode(op_pop_scope);
973 m_scopeContextStack.removeLast();
974 m_dynamicScopeDepth--;
977 void CodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine)
979 if (!m_shouldEmitDebugHooks)
981 emitOpcode(op_debug);
982 instructions().append(debugHookID);
983 instructions().append(firstLine);
984 instructions().append(lastLine);
987 void CodeGenerator::pushFinallyContext(LabelID* target, RegisterID* retAddrDst)
989 ControlFlowContext scope;
990 scope.isFinallyBlock = true;
991 FinallyContext context = { target, retAddrDst };
992 scope.finallyContext = context;
993 m_scopeContextStack.append(scope);
997 void CodeGenerator::popFinallyContext()
999 ASSERT(m_scopeContextStack.size());
1000 ASSERT(m_scopeContextStack.last().isFinallyBlock);
1001 ASSERT(m_finallyDepth > 0);
1002 m_scopeContextStack.removeLast();
1006 void CodeGenerator::pushJumpContext(LabelStack* labels, LabelID* continueTarget, LabelID* breakTarget, bool isValidUnlabeledBreakTarget)
1008 JumpContext context = { labels, continueTarget, breakTarget, scopeDepth(), isValidUnlabeledBreakTarget };
1009 m_jumpContextStack.append(context);
1014 void CodeGenerator::popJumpContext()
1016 ASSERT(m_jumpContextStack.size());
1017 if (m_jumpContextStack.last().continueTarget)
1019 m_jumpContextStack.removeLast();
1022 JumpContext* CodeGenerator::jumpContextForContinue(const Identifier& label)
1024 if(!m_jumpContextStack.size())
1027 if (label.isEmpty()) {
1028 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1029 JumpContext* scope = &m_jumpContextStack[i];
1030 if (scope->continueTarget)
1036 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1037 JumpContext* scope = &m_jumpContextStack[i];
1038 if (scope->labels->contains(label))
1044 JumpContext* CodeGenerator::jumpContextForBreak(const Identifier& label)
1046 if(!m_jumpContextStack.size())
1049 if (label.isEmpty()) {
1050 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1051 JumpContext* scope = &m_jumpContextStack[i];
1052 if (scope->isValidUnlabeledBreakTarget)
1058 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1059 JumpContext* scope = &m_jumpContextStack[i];
1060 if (scope->labels->contains(label))
1066 PassRefPtr<LabelID> CodeGenerator::emitComplexJumpScopes(LabelID* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope)
1068 while (topScope > bottomScope) {
1069 // First we count the number of dynamic scopes we need to remove to get
1070 // to a finally block.
1071 int nNormalScopes = 0;
1072 while (topScope > bottomScope) {
1073 if (topScope->isFinallyBlock)
1079 if (nNormalScopes) {
1080 // We need to remove a number of dynamic scopes to get to the next
1082 emitOpcode(op_jmp_scopes);
1083 instructions().append(nNormalScopes);
1085 // If topScope == bottomScope then there isn't actually a finally block
1086 // left to emit, so make the jmp_scopes jump directly to the target label
1087 if (topScope == bottomScope) {
1088 instructions().append(target->offsetFrom(instructions().size()));
1092 // Otherwise we just use jmp_scopes to pop a group of scopes and go
1093 // to the next instruction
1094 RefPtr<LabelID> nextInsn = newLabel();
1095 instructions().append(nextInsn->offsetFrom(instructions().size()));
1096 emitLabel(nextInsn.get());
1099 // To get here there must be at least one finally block present
1101 ASSERT(topScope->isFinallyBlock);
1102 emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr);
1104 if (!topScope->isFinallyBlock)
1106 } while (topScope > bottomScope);
1108 return emitJump(target);
1111 PassRefPtr<LabelID> CodeGenerator::emitJumpScopes(LabelID* target, int targetScopeDepth)
1113 ASSERT(scopeDepth() - targetScopeDepth >= 0);
1114 ASSERT(target->isForwardLabel());
1116 size_t scopeDelta = scopeDepth() - targetScopeDepth;
1117 ASSERT(scopeDelta <= m_scopeContextStack.size());
1119 return emitJump(target);
1122 return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta);
1124 emitOpcode(op_jmp_scopes);
1125 instructions().append(scopeDelta);
1126 instructions().append(target->offsetFrom(instructions().size()));
1130 RegisterID* CodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* iter, LabelID* target)
1132 emitOpcode(op_next_pname);
1133 instructions().append(dst->index());
1134 instructions().append(iter->index());
1135 instructions().append(target->offsetFrom(instructions().size()));
1139 RegisterID* CodeGenerator::emitCatch(RegisterID* targetRegister, LabelID* start, LabelID* end)
1141 HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth };
1142 exceptionHandlers().append(info);
1143 emitOpcode(op_catch);
1144 instructions().append(targetRegister->index());
1145 return targetRegister;
1148 RegisterID* CodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValue* message)
1150 emitOpcode(op_new_error);
1151 instructions().append(dst->index());
1152 instructions().append(static_cast<int>(type));
1153 instructions().append(addUnexpectedConstant(message));
1157 PassRefPtr<LabelID> CodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, LabelID* finally)
1160 instructions().append(retAddrDst->index());
1161 instructions().append(finally->offsetFrom(instructions().size()));
1165 void CodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc)
1167 emitOpcode(op_sret);
1168 instructions().append(retAddrSrc->index());
1171 void CodeGenerator::emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value)
1173 m_codeBlock->needsFullScopeChain = true;
1174 ControlFlowContext context;
1175 context.isFinallyBlock = false;
1176 m_scopeContextStack.append(context);
1177 m_dynamicScopeDepth++;
1179 emitOpcode(op_push_new_scope);
1180 instructions().append(dst->index());
1181 instructions().append(addConstant(property));
1182 instructions().append(value->index());
1185 void CodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type)
1187 SwitchInfo info = { instructions().size(), type };
1189 case SwitchInfo::SwitchImmediate:
1190 emitOpcode(op_switch_imm);
1192 case SwitchInfo::SwitchCharacter:
1193 emitOpcode(op_switch_char);
1195 case SwitchInfo::SwitchString:
1196 emitOpcode(op_switch_string);
1199 ASSERT_NOT_REACHED();
1202 instructions().append(0); // place holder for table index
1203 instructions().append(0); // place holder for default target
1204 instructions().append(scrutineeRegister->index());
1205 m_switchContextStack.append(info);
1208 static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max)
1211 ASSERT(node->isNumber());
1212 double value = static_cast<NumberNode*>(node)->value();
1213 ASSERT(JSImmediate::from(value));
1214 int32_t key = static_cast<int32_t>(value);
1215 ASSERT(key == value);
1221 static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1223 jumpTable.min = min;
1224 jumpTable.branchOffsets.resize(max - min + 1);
1225 jumpTable.branchOffsets.fill(0);
1226 for (uint32_t i = 0; i < clauseCount; ++i) {
1227 // We're emitting this after the clause labels should have been fixed, so
1228 // the labels should not be "forward" references
1229 ASSERT(!labels[i]->isForwardLabel());
1230 jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress));
1234 static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max)
1237 ASSERT(node->isString());
1238 UString::Rep* clause = static_cast<StringNode*>(node)->value().rep();
1239 ASSERT(clause->size() == 1);
1241 int32_t key = clause->data()[0];
1247 static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1249 jumpTable.min = min;
1250 jumpTable.branchOffsets.resize(max - min + 1);
1251 jumpTable.branchOffsets.fill(0);
1252 for (uint32_t i = 0; i < clauseCount; ++i) {
1253 // We're emitting this after the clause labels should have been fixed, so
1254 // the labels should not be "forward" references
1255 ASSERT(!labels[i]->isForwardLabel());
1256 jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress));
1260 static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes)
1262 for (uint32_t i = 0; i < clauseCount; ++i) {
1263 // We're emitting this after the clause labels should have been fixed, so
1264 // the labels should not be "forward" references
1265 ASSERT(!labels[i]->isForwardLabel());
1267 ASSERT(nodes[i]->isString());
1268 UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().rep();
1269 jumpTable.add(clause, labels[i]->offsetFrom(switchAddress));
1273 void CodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, LabelID* defaultLabel, int32_t min, int32_t max)
1275 SwitchInfo switchInfo = m_switchContextStack.last();
1276 m_switchContextStack.removeLast();
1277 if (switchInfo.switchType == SwitchInfo::SwitchImmediate) {
1278 instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->immediateSwitchJumpTables.size();
1279 instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1281 m_codeBlock->immediateSwitchJumpTables.append(SimpleJumpTable());
1282 SimpleJumpTable& jumpTable = m_codeBlock->immediateSwitchJumpTables.last();
1284 prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes, min, max);
1285 } else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) {
1286 instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->characterSwitchJumpTables.size();
1287 instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1289 m_codeBlock->characterSwitchJumpTables.append(SimpleJumpTable());
1290 SimpleJumpTable& jumpTable = m_codeBlock->characterSwitchJumpTables.last();
1292 prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes, min, max);
1294 ASSERT(switchInfo.switchType == SwitchInfo::SwitchString);
1295 instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->stringSwitchJumpTables.size();
1296 instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1298 m_codeBlock->stringSwitchJumpTables.append(StringJumpTable());
1299 StringJumpTable& jumpTable = m_codeBlock->stringSwitchJumpTables.last();
1301 prepareJumpTableForStringSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes);