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->numVars = 1; // Allocate space for "this"
207 JSGlobalObject* globalObject = scopeChain.globalObject();
208 ExecState* exec = globalObject->globalExec();
209 RegisterFile* registerFile = &exec->globalData().machine->registerFile();
211 // Shift register indexes in generated code to elide registers allocated by intermediate stack frames.
212 m_globalVarStorageOffset = -1 - RegisterFile::CallFrameHeaderSize - registerFile->size();
214 // Add previously defined symbols to bookkeeping.
215 m_locals.resize(symbolTable->size());
216 SymbolTable::iterator end = symbolTable->end();
217 for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
218 m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex() + m_globalVarStorageOffset);
220 bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();
221 if (canOptimizeNewGlobals) {
222 // Shift new symbols so they get stored prior to existing symbols.
223 m_nextVar -= symbolTable->size();
225 for (size_t i = 0; i < functionStack.size(); ++i) {
226 FuncDeclNode* funcDecl = functionStack[i].get();
227 globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
228 emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);
231 for (size_t i = 0; i < varStack.size(); ++i) {
232 if (!globalObject->hasProperty(exec, varStack[i].first))
233 emitLoad(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant), jsUndefined());
236 for (size_t i = 0; i < functionStack.size(); ++i) {
237 FuncDeclNode* funcDecl = functionStack[i].get();
238 globalObject->putWithAttributes(exec, funcDecl->m_ident, funcDecl->makeFunction(exec, scopeChain.node()), DontDelete);
240 for (size_t i = 0; i < varStack.size(); ++i) {
241 if (globalObject->hasProperty(exec, varStack[i].first))
243 int attributes = DontDelete;
244 if (varStack[i].second & DeclarationStacks::IsConstant)
245 attributes |= ReadOnly;
246 globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes);
251 CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock)
252 : m_shouldEmitDebugHooks(!!debugger)
253 , m_scopeChain(&scopeChain)
254 , m_symbolTable(symbolTable)
255 , m_scopeNode(functionBody)
256 , m_codeBlock(codeBlock)
258 , m_dynamicScopeDepth(0)
259 , m_codeType(FunctionCode)
262 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
263 , m_lastOpcodeID(op_end)
265 const Node::FunctionStack& functionStack = functionBody->functionStack();
266 for (size_t i = 0; i < functionStack.size(); ++i) {
267 FuncDeclNode* funcDecl = functionStack[i].get();
268 const Identifier& ident = funcDecl->m_ident;
270 m_functions.add(ident.ustring().rep());
271 emitNewFunction(addVar(ident, false), funcDecl);
274 const Node::VarStack& varStack = functionBody->varStack();
275 for (size_t i = 0; i < varStack.size(); ++i) {
276 const Identifier& ident = varStack[i].first;
277 if (ident == propertyNames().arguments)
279 addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
282 Vector<Identifier>& parameters = functionBody->parameters();
283 m_nextParameter = m_nextVar - parameters.size(); // parameters are allocated prior to vars
284 m_locals.resize(localsIndex(m_nextParameter) + 1); // localsIndex of 0 => m_locals size of 1
286 // Add "this" as a parameter
287 m_thisRegister.setIndex(m_nextParameter);
289 ++m_codeBlock->numParameters;
291 for (size_t i = 0; i < parameters.size(); ++i)
292 addParameter(parameters[i]);
295 CodeGenerator::CodeGenerator(EvalNode* evalNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock)
296 : m_shouldEmitDebugHooks(!!debugger)
297 , m_scopeChain(&scopeChain)
298 , m_symbolTable(symbolTable)
299 , m_scopeNode(evalNode)
300 , m_codeBlock(codeBlock)
301 , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
303 , m_dynamicScopeDepth(0)
304 , m_codeType(EvalCode)
306 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
307 , m_lastOpcodeID(op_end)
309 m_codeBlock->numVars = 1; // Allocate space for "this"
312 CodeGenerator::~CodeGenerator()
316 RegisterID* CodeGenerator::addParameter(const Identifier& ident)
318 // Parameters overwrite var declarations, but not function declarations,
319 // in the symbol table.
320 RegisterID* result = 0;
321 UString::Rep* rep = ident.ustring().rep();
322 if (!m_functions.contains(rep)) {
323 symbolTable().set(rep, m_nextParameter);
324 m_locals[localsIndex(m_nextParameter)].setIndex(m_nextParameter);
325 result = &(m_locals[localsIndex(m_nextParameter)]);
328 // To maintain the calling convention, we have to allocate unique space for
329 // each parameter, even if the parameter doesn't make it into the symbol table.
331 ++m_codeBlock->numParameters;
335 RegisterID* CodeGenerator::registerForLocal(const Identifier& ident)
337 if (m_codeType == FunctionCode && ident == propertyNames().arguments)
338 m_codeBlock->needsFullScopeChain = true;
340 if (ident == propertyNames().thisIdentifier)
341 return &m_thisRegister;
343 if (!shouldOptimizeLocals())
346 SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
350 return &m_locals[localsIndex(entry.getIndex())];
353 RegisterID* CodeGenerator::registerForLocalConstInit(const Identifier& ident)
355 if (m_codeType == EvalCode)
358 SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
359 ASSERT(!entry.isNull());
361 return &m_locals[localsIndex(entry.getIndex())];
364 bool CodeGenerator::isLocal(const Identifier& ident)
366 if (ident == propertyNames().thisIdentifier)
369 return shouldOptimizeLocals() && symbolTable().contains(ident.ustring().rep());
372 bool CodeGenerator::isLocalConstant(const Identifier& ident)
374 return symbolTable().get(ident.ustring().rep()).isReadOnly();
377 RegisterID* CodeGenerator::newTemporary()
379 // Reclaim free register IDs.
380 while (m_temporaries.size() && !m_temporaries.last().refCount())
381 m_temporaries.removeLast();
383 // Allocate new register ID.
384 m_temporaries.append(m_temporaries.size());
385 m_codeBlock->numTemporaries = max<int>(m_codeBlock->numTemporaries, m_temporaries.size());
386 return &m_temporaries.last();
389 RegisterID* CodeGenerator::highestUsedRegister()
391 while (m_temporaries.size() < static_cast<unsigned>(m_codeBlock->numTemporaries))
392 m_temporaries.append(m_temporaries.size());
393 return &m_temporaries.last();
396 PassRefPtr<LabelID> CodeGenerator::newLabel()
398 // Reclaim free label IDs.
399 while (m_labels.size() && !m_labels.last().refCount())
400 m_labels.removeLast();
402 // Allocate new label ID.
403 m_labels.append(m_codeBlock);
404 return &m_labels.last();
407 PassRefPtr<LabelID> CodeGenerator::emitLabel(LabelID* l0)
409 l0->setLocation(instructions().size());
411 // This disables peephole optimizations when an instruction is a jump target
412 m_lastOpcodeID = op_end;
417 void CodeGenerator::emitOpcode(OpcodeID opcodeID)
419 instructions().append(globalData()->machine->getOpcode(opcodeID));
420 m_lastOpcodeID = opcodeID;
423 void CodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
425 ASSERT(instructions().size() >= 4);
426 size_t size = instructions().size();
427 dstIndex = instructions().at(size - 3).u.operand;
428 src1Index = instructions().at(size - 2).u.operand;
429 src2Index = instructions().at(size - 1).u.operand;
432 void ALWAYS_INLINE CodeGenerator::rewindBinaryOp()
434 ASSERT(instructions().size() >= 4);
435 instructions().shrink(instructions().size() - 4);
438 PassRefPtr<LabelID> CodeGenerator::emitJump(LabelID* target)
440 emitOpcode(target->isForwardLabel() ? op_jmp : op_loop);
441 instructions().append(target->offsetFrom(instructions().size()));
445 PassRefPtr<LabelID> CodeGenerator::emitJumpIfTrue(RegisterID* cond, LabelID* target)
447 if (m_lastOpcodeID == op_less) {
452 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
454 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
456 emitOpcode(target->isForwardLabel() ? op_jless : op_loop_if_less);
457 instructions().append(src1Index);
458 instructions().append(src2Index);
459 instructions().append(target->offsetFrom(instructions().size()));
464 emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true);
465 instructions().append(cond->index());
466 instructions().append(target->offsetFrom(instructions().size()));
470 PassRefPtr<LabelID> CodeGenerator::emitJumpIfFalse(RegisterID* cond, LabelID* target)
472 ASSERT(target->isForwardLabel());
474 if (m_lastOpcodeID == op_less) {
479 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
481 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
483 emitOpcode(op_jnless);
484 instructions().append(src1Index);
485 instructions().append(src2Index);
486 instructions().append(target->offsetFrom(instructions().size()));
491 emitOpcode(op_jfalse);
492 instructions().append(cond->index());
493 instructions().append(target->offsetFrom(instructions().size()));
497 unsigned CodeGenerator::addConstant(FuncDeclNode* n)
499 // No need to explicitly unique function body nodes -- they're unique already.
500 int index = m_codeBlock->functions.size();
501 m_codeBlock->functions.append(n);
505 unsigned CodeGenerator::addConstant(FuncExprNode* n)
507 // No need to explicitly unique function expression nodes -- they're unique already.
508 int index = m_codeBlock->functionExpressions.size();
509 m_codeBlock->functionExpressions.append(n);
513 unsigned CodeGenerator::addConstant(const Identifier& ident)
515 UString::Rep* rep = ident.ustring().rep();
516 pair<IdentifierMap::iterator, bool> result = m_identifierMap.add(rep, m_codeBlock->identifiers.size());
517 if (result.second) // new entry
518 m_codeBlock->identifiers.append(Identifier(m_globalData, rep));
520 return result.first->second;
523 unsigned CodeGenerator::addConstant(JSValue* v)
525 pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(v, m_codeBlock->registers.size());
526 if (result.second) // new entry
527 m_codeBlock->registers.append(v);
529 return result.first->second;
532 unsigned CodeGenerator::addRegExp(RegExp* r)
534 int index = m_codeBlock->regexps.size();
535 m_codeBlock->regexps.append(r);
539 RegisterID* CodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
542 instructions().append(dst->index());
543 instructions().append(src->index());
547 RegisterID* CodeGenerator::emitUnaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src)
550 instructions().append(dst->index());
551 instructions().append(src->index());
555 RegisterID* CodeGenerator::emitPreInc(RegisterID* srcDst)
557 emitOpcode(op_pre_inc);
558 instructions().append(srcDst->index());
562 RegisterID* CodeGenerator::emitPreDec(RegisterID* srcDst)
564 emitOpcode(op_pre_dec);
565 instructions().append(srcDst->index());
569 RegisterID* CodeGenerator::emitPostInc(RegisterID* dst, RegisterID* srcDst)
571 emitOpcode(op_post_inc);
572 instructions().append(dst->index());
573 instructions().append(srcDst->index());
577 RegisterID* CodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst)
579 emitOpcode(op_post_dec);
580 instructions().append(dst->index());
581 instructions().append(srcDst->index());
585 RegisterID* CodeGenerator::emitBinaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src1, RegisterID* src2)
588 instructions().append(dst->index());
589 instructions().append(src1->index());
590 instructions().append(src2->index());
594 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, bool b)
597 instructions().append(dst->index());
598 instructions().append(addConstant(jsBoolean(b)));
602 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, double d)
605 instructions().append(dst->index());
606 instructions().append(addConstant(jsNumber(globalExec(), d)));
610 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, JSValue* v)
613 instructions().append(dst->index());
614 instructions().append(addConstant(v));
618 RegisterID* CodeGenerator::emitNullaryOp(OpcodeID opcode, RegisterID* dst)
621 instructions().append(dst->index());
625 bool CodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting)
627 // Cases where we cannot optimise the lookup
628 if (property == propertyNames().arguments || !canOptimizeNonLocals()) {
630 index = missingSymbolMarker();
634 ScopeChainIterator iter = m_scopeChain->begin();
635 ScopeChainIterator end = m_scopeChain->end();
638 for (; iter != end; ++iter, ++depth) {
639 JSObject* currentScope = *iter;
640 if (!currentScope->isVariableObject())
642 JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
643 SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.ustring().rep());
645 // Found the property
646 if (!entry.isNull()) {
647 if (entry.isReadOnly() && forWriting) {
649 index = missingSymbolMarker();
653 index = entry.getIndex();
656 if (currentVariableObject->isDynamicScope())
660 // Can't locate the property but we're able to avoid a few lookups
662 index = missingSymbolMarker();
666 RegisterID* CodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
670 if (!findScopedProperty(property, index, depth, false)) {
671 // We can't optimise at all :-(
672 emitOpcode(op_resolve);
673 instructions().append(dst->index());
674 instructions().append(addConstant(property));
678 if (index == missingSymbolMarker()) {
679 // In this case we are at least able to drop a few scope chains from the
680 // lookup chain, although we still need to hash from then on.
681 emitOpcode(op_resolve_skip);
682 instructions().append(dst->index());
683 instructions().append(addConstant(property));
684 instructions().append(depth);
688 // Directly index the property lookup across multiple scopes. Yay!
689 return emitGetScopedVar(dst, depth, index);
692 RegisterID* CodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index)
694 emitOpcode(op_get_scoped_var);
695 instructions().append(dst->index());
696 instructions().append(index);
697 instructions().append(depth);
701 RegisterID* CodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value)
703 emitOpcode(op_put_scoped_var);
704 instructions().append(index);
705 instructions().append(depth);
706 instructions().append(value->index());
710 RegisterID* CodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property)
712 emitOpcode(op_resolve_base);
713 instructions().append(dst->index());
714 instructions().append(addConstant(property));
718 RegisterID* CodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
720 emitOpcode(op_resolve_with_base);
721 instructions().append(baseDst->index());
722 instructions().append(propDst->index());
723 instructions().append(addConstant(property));
727 RegisterID* CodeGenerator::emitResolveFunction(RegisterID* baseDst, RegisterID* funcDst, const Identifier& property)
729 emitOpcode(op_resolve_func);
730 instructions().append(baseDst->index());
731 instructions().append(funcDst->index());
732 instructions().append(addConstant(property));
736 RegisterID* CodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
738 emitOpcode(op_get_by_id);
739 instructions().append(dst->index());
740 instructions().append(base->index());
741 instructions().append(addConstant(property));
745 RegisterID* CodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
747 emitOpcode(op_put_by_id);
748 instructions().append(base->index());
749 instructions().append(addConstant(property));
750 instructions().append(value->index());
754 RegisterID* CodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
756 emitOpcode(op_put_getter);
757 instructions().append(base->index());
758 instructions().append(addConstant(property));
759 instructions().append(value->index());
763 RegisterID* CodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
765 emitOpcode(op_put_setter);
766 instructions().append(base->index());
767 instructions().append(addConstant(property));
768 instructions().append(value->index());
772 RegisterID* CodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
774 emitOpcode(op_del_by_id);
775 instructions().append(dst->index());
776 instructions().append(base->index());
777 instructions().append(addConstant(property));
781 RegisterID* CodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
783 emitOpcode(op_get_by_val);
784 instructions().append(dst->index());
785 instructions().append(base->index());
786 instructions().append(property->index());
790 RegisterID* CodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
792 emitOpcode(op_put_by_val);
793 instructions().append(base->index());
794 instructions().append(property->index());
795 instructions().append(value->index());
799 RegisterID* CodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
801 emitOpcode(op_del_by_val);
802 instructions().append(dst->index());
803 instructions().append(base->index());
804 instructions().append(property->index());
808 RegisterID* CodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value)
810 emitOpcode(op_put_by_index);
811 instructions().append(base->index());
812 instructions().append(index);
813 instructions().append(value->index());
817 RegisterID* CodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements)
819 Vector<RefPtr<RegisterID>, 16> argv;
820 for (ElementNode* n = elements; n; n = n->next()) {
823 argv.append(newTemporary());
824 emitNode(argv.last().get(), n->value());
826 emitOpcode(op_new_array);
827 instructions().append(dst->index());
828 instructions().append(argv.size() ? argv[0]->index() : 0); // argv
829 instructions().append(argv.size()); // argc
833 RegisterID* CodeGenerator::emitNewFunction(RegisterID* dst, FuncDeclNode* n)
835 emitOpcode(op_new_func);
836 instructions().append(dst->index());
837 instructions().append(addConstant(n));
841 RegisterID* CodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
843 emitOpcode(op_new_regexp);
844 instructions().append(dst->index());
845 instructions().append(addRegExp(regExp));
850 RegisterID* CodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
852 emitOpcode(op_new_func_exp);
853 instructions().append(r0->index());
854 instructions().append(addConstant(n));
858 RegisterID* CodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
860 return emitCall(op_call, dst, func, base, argumentsNode, divot, startOffset, endOffset);
863 RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
865 return emitCall(op_call_eval, dst, func, base, argumentsNode, divot, startOffset, endOffset);
868 RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
870 ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
872 // Ordinarily, we might ref "func" and "base", to avoid allocating new
873 // temporaries in the same registers. In this case, though, we actually
874 // want the call frame we allocate to overlap "func" and "base", if they're
875 // not otherwise referenced. op_call will read "func" and "base" before
876 // writing out the call frame, so this is safe.
878 // Reserve space for call frame.
879 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
880 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
881 callFrame.append(newTemporary());
883 // Generate code for arguments.
884 Vector<RefPtr<RegisterID>, 16> argv;
885 argv.append(newTemporary()); // reserve space for "this"
886 for (ArgumentListNode* n = argumentsNode->m_listNode.get(); n; n = n->m_next.get()) {
887 argv.append(newTemporary());
888 emitNode(argv.last().get(), n);
891 emitExpressionInfo(divot, startOffset, endOffset);
892 emitOpcode(opcodeID);
893 instructions().append(dst->index());
894 instructions().append(func->index());
895 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.
896 instructions().append(argv.size() ? argv[0]->index() : m_temporaries.size()); // argv
897 instructions().append(argv.size()); // argc
901 RegisterID* CodeGenerator::emitUnaryNoDstOp(OpcodeID opcode, RegisterID* src)
904 instructions().append(src->index());
908 RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode* argumentsNode)
910 // Ordinarily, we might ref "func", to avoid allocating a new temporary in
911 // the same register. In this case, though, we actually want the call
912 // frame we allocate to overlap "func", if it's not otherwise referenced.
913 // op_construct will read "func" before writing out the call frame, so this
916 // Reserve space for call frame.
917 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
918 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
919 callFrame.append(newTemporary());
921 // Generate code for arguments.
922 Vector<RefPtr<RegisterID>, 16> argv;
923 argv.append(newTemporary()); // reserve space for "this"
924 for (ArgumentListNode* n = argumentsNode ? argumentsNode->m_listNode.get() : 0; n; n = n->m_next.get()) {
925 argv.append(newTemporary());
926 emitNode(argv.last().get(), n);
929 emitOpcode(op_construct);
930 instructions().append(dst->index());
931 instructions().append(func->index());
932 instructions().append(argv.size() ? argv[0]->index() : m_temporaries.size()); // argv
933 instructions().append(argv.size()); // argc
937 RegisterID* CodeGenerator::emitPushScope(RegisterID* scope)
939 m_codeBlock->needsFullScopeChain = true;
940 ControlFlowContext context;
941 context.isFinallyBlock = false;
942 m_scopeContextStack.append(context);
943 m_dynamicScopeDepth++;
945 return emitUnaryNoDstOp(op_push_scope, scope);
948 void CodeGenerator::emitPopScope()
950 ASSERT(m_scopeContextStack.size());
951 ASSERT(!m_scopeContextStack.last().isFinallyBlock);
953 emitOpcode(op_pop_scope);
955 m_scopeContextStack.removeLast();
956 m_dynamicScopeDepth--;
959 void CodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine)
961 if (!m_shouldEmitDebugHooks)
963 emitOpcode(op_debug);
964 instructions().append(debugHookID);
965 instructions().append(firstLine);
966 instructions().append(lastLine);
969 void CodeGenerator::pushFinallyContext(LabelID* target, RegisterID* retAddrDst)
971 ControlFlowContext scope;
972 scope.isFinallyBlock = true;
973 FinallyContext context = { target, retAddrDst };
974 scope.finallyContext = context;
975 m_scopeContextStack.append(scope);
979 void CodeGenerator::popFinallyContext()
981 ASSERT(m_scopeContextStack.size());
982 ASSERT(m_scopeContextStack.last().isFinallyBlock);
983 ASSERT(m_finallyDepth > 0);
984 m_scopeContextStack.removeLast();
988 void CodeGenerator::pushJumpContext(LabelStack* labels, LabelID* continueTarget, LabelID* breakTarget, bool isValidUnlabeledBreakTarget)
990 JumpContext context = { labels, continueTarget, breakTarget, scopeDepth(), isValidUnlabeledBreakTarget };
991 m_jumpContextStack.append(context);
996 void CodeGenerator::popJumpContext()
998 ASSERT(m_jumpContextStack.size());
999 if (m_jumpContextStack.last().continueTarget)
1001 m_jumpContextStack.removeLast();
1004 JumpContext* CodeGenerator::jumpContextForContinue(const Identifier& label)
1006 if(!m_jumpContextStack.size())
1009 if (label.isEmpty()) {
1010 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1011 JumpContext* scope = &m_jumpContextStack[i];
1012 if (scope->continueTarget)
1018 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1019 JumpContext* scope = &m_jumpContextStack[i];
1020 if (scope->labels->contains(label))
1026 JumpContext* CodeGenerator::jumpContextForBreak(const Identifier& label)
1028 if(!m_jumpContextStack.size())
1031 if (label.isEmpty()) {
1032 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1033 JumpContext* scope = &m_jumpContextStack[i];
1034 if (scope->isValidUnlabeledBreakTarget)
1040 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1041 JumpContext* scope = &m_jumpContextStack[i];
1042 if (scope->labels->contains(label))
1048 PassRefPtr<LabelID> CodeGenerator::emitComplexJumpScopes(LabelID* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope)
1050 while (topScope > bottomScope) {
1051 // First we count the number of dynamic scopes we need to remove to get
1052 // to a finally block.
1053 int nNormalScopes = 0;
1054 while (topScope > bottomScope) {
1055 if (topScope->isFinallyBlock)
1061 if (nNormalScopes) {
1062 // We need to remove a number of dynamic scopes to get to the next
1064 emitOpcode(op_jmp_scopes);
1065 instructions().append(nNormalScopes);
1067 // If topScope == bottomScope then there isn't actually a finally block
1068 // left to emit, so make the jmp_scopes jump directly to the target label
1069 if (topScope == bottomScope) {
1070 instructions().append(target->offsetFrom(instructions().size()));
1074 // Otherwise we just use jmp_scopes to pop a group of scopes and go
1075 // to the next instruction
1076 RefPtr<LabelID> nextInsn = newLabel();
1077 instructions().append(nextInsn->offsetFrom(instructions().size()));
1078 emitLabel(nextInsn.get());
1081 // To get here there must be at least one finally block present
1083 ASSERT(topScope->isFinallyBlock);
1084 emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr);
1086 if (!topScope->isFinallyBlock)
1088 } while (topScope > bottomScope);
1090 return emitJump(target);
1093 PassRefPtr<LabelID> CodeGenerator::emitJumpScopes(LabelID* target, int targetScopeDepth)
1095 ASSERT(scopeDepth() - targetScopeDepth >= 0);
1096 ASSERT(target->isForwardLabel());
1098 size_t scopeDelta = scopeDepth() - targetScopeDepth;
1099 ASSERT(scopeDelta <= m_scopeContextStack.size());
1101 return emitJump(target);
1104 return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta);
1106 emitOpcode(op_jmp_scopes);
1107 instructions().append(scopeDelta);
1108 instructions().append(target->offsetFrom(instructions().size()));
1112 RegisterID* CodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* iter, LabelID* target)
1114 emitOpcode(op_next_pname);
1115 instructions().append(dst->index());
1116 instructions().append(iter->index());
1117 instructions().append(target->offsetFrom(instructions().size()));
1121 RegisterID* CodeGenerator::emitCatch(RegisterID* targetRegister, LabelID* start, LabelID* end)
1123 HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth };
1124 exceptionHandlers().append(info);
1125 emitOpcode(op_catch);
1126 instructions().append(targetRegister->index());
1127 return targetRegister;
1130 RegisterID* CodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValue* message)
1132 emitOpcode(op_new_error);
1133 instructions().append(dst->index());
1134 instructions().append(static_cast<int>(type));
1135 instructions().append(addConstant(message));
1139 PassRefPtr<LabelID> CodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, LabelID* finally)
1142 instructions().append(retAddrDst->index());
1143 instructions().append(finally->offsetFrom(instructions().size()));
1147 void CodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc)
1149 emitOpcode(op_sret);
1150 instructions().append(retAddrSrc->index());
1153 void CodeGenerator::emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value)
1155 m_codeBlock->needsFullScopeChain = true;
1156 ControlFlowContext context;
1157 context.isFinallyBlock = false;
1158 m_scopeContextStack.append(context);
1159 m_dynamicScopeDepth++;
1161 emitOpcode(op_push_new_scope);
1162 instructions().append(dst->index());
1163 instructions().append(addConstant(property));
1164 instructions().append(value->index());
1167 void CodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type)
1169 SwitchInfo info = { instructions().size(), type };
1171 case SwitchInfo::SwitchImmediate:
1172 emitOpcode(op_switch_imm);
1174 case SwitchInfo::SwitchCharacter:
1175 emitOpcode(op_switch_char);
1177 case SwitchInfo::SwitchString:
1178 emitOpcode(op_switch_string);
1181 ASSERT_NOT_REACHED();
1184 instructions().append(0); // place holder for table index
1185 instructions().append(0); // place holder for default target
1186 instructions().append(scrutineeRegister->index());
1187 m_switchContextStack.append(info);
1190 static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max)
1193 ASSERT(node->isNumber());
1194 double value = static_cast<NumberNode*>(node)->value();
1195 ASSERT(JSImmediate::from(value));
1196 int32_t key = static_cast<int32_t>(value);
1197 ASSERT(key == value);
1203 static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1205 jumpTable.min = min;
1206 jumpTable.branchOffsets.resize(max - min + 1);
1207 jumpTable.branchOffsets.fill(0);
1208 for (uint32_t i = 0; i < clauseCount; ++i) {
1209 // We're emitting this after the clause labels should have been fixed, so
1210 // the labels should not be "forward" references
1211 ASSERT(!labels[i]->isForwardLabel());
1212 jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress));
1216 static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max)
1219 ASSERT(node->isString());
1220 UString::Rep* clause = static_cast<StringNode*>(node)->value().rep();
1221 ASSERT(clause->size() == 1);
1223 int32_t key = clause->data()[0];
1229 static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1231 jumpTable.min = min;
1232 jumpTable.branchOffsets.resize(max - min + 1);
1233 jumpTable.branchOffsets.fill(0);
1234 for (uint32_t i = 0; i < clauseCount; ++i) {
1235 // We're emitting this after the clause labels should have been fixed, so
1236 // the labels should not be "forward" references
1237 ASSERT(!labels[i]->isForwardLabel());
1238 jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress));
1242 static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes)
1244 for (uint32_t i = 0; i < clauseCount; ++i) {
1245 // We're emitting this after the clause labels should have been fixed, so
1246 // the labels should not be "forward" references
1247 ASSERT(!labels[i]->isForwardLabel());
1249 ASSERT(nodes[i]->isString());
1250 UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().rep();
1251 jumpTable.add(clause, labels[i]->offsetFrom(switchAddress));
1255 void CodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, LabelID* defaultLabel, int32_t min, int32_t max)
1257 SwitchInfo switchInfo = m_switchContextStack.last();
1258 m_switchContextStack.removeLast();
1259 if (switchInfo.switchType == SwitchInfo::SwitchImmediate) {
1260 instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->immediateSwitchJumpTables.size();
1261 instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1263 m_codeBlock->immediateSwitchJumpTables.append(SimpleJumpTable());
1264 SimpleJumpTable& jumpTable = m_codeBlock->immediateSwitchJumpTables.last();
1266 prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes, min, max);
1267 } else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) {
1268 instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->characterSwitchJumpTables.size();
1269 instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1271 m_codeBlock->characterSwitchJumpTables.append(SimpleJumpTable());
1272 SimpleJumpTable& jumpTable = m_codeBlock->characterSwitchJumpTables.last();
1274 prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes, min, max);
1276 ASSERT(switchInfo.switchType == SwitchInfo::SwitchString);
1277 instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->stringSwitchJumpTables.size();
1278 instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1280 m_codeBlock->stringSwitchJumpTables.append(StringJumpTable());
1281 StringJumpTable& jumpTable = m_codeBlock->stringSwitchJumpTables.last();
1283 prepareJumpTableForStringSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes);