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 "BatchedTransitionOptimizer.h"
34 #include "JSFunction.h"
43 The layout of a register frame looks like this:
54 assuming (x) and (y) generated temporaries t1 and t2, you would have
56 ------------------------------------
57 | x | y | g | v2 | v1 | t1 | t2 | <-- value held
58 ------------------------------------
59 | -5 | -4 | -3 | -2 | -1 | +0 | +1 | <-- register index
60 ------------------------------------
61 | params->|<-locals | temps->
63 Because temporary registers are allocated in a stack-like fashion, we
64 can reclaim them with a simple popping algorithm. The same goes for labels.
65 (We never reclaim parameter or local registers, because parameters and
66 locals are DontDelete.)
68 The register layout before a function call looks like this:
78 > <------------------------------
79 < > reserved: call frame | 1 | <-- value held
80 > >snip< <------------------------------
81 < > +0 | +1 | +2 | +3 | +4 | +5 | <-- register index
82 > <------------------------------
83 | params->|<-locals | temps->
85 The call instruction fills in the "call frame" registers. It also pads
86 missing arguments at the end of the call:
88 > <-----------------------------------
89 < > reserved: call frame | 1 | ? | <-- value held ("?" stands for "undefined")
90 > >snip< <-----------------------------------
91 < > +0 | +1 | +2 | +3 | +4 | +5 | +6 | <-- register index
92 > <-----------------------------------
93 | params->|<-locals | temps->
95 After filling in missing arguments, the call instruction sets up the new
96 stack frame to overlap the end of the old stack frame:
98 |----------------------------------> <
99 | reserved: call frame | 1 | ? < > <-- value held ("?" stands for "undefined")
100 |----------------------------------> >snip< <
101 | -7 | -6 | -5 | -4 | -3 | -2 | -1 < > <-- register index
102 |----------------------------------> <
103 | | params->|<-locals | temps->
105 That way, arguments are "copied" into the callee's stack frame for free.
107 If the caller supplies too many arguments, this trick doesn't work. The
108 extra arguments protrude into space reserved for locals and temporaries.
109 In that case, the call instruction makes a real copy of the call frame header,
110 along with just the arguments expected by the callee, leaving the original
111 call frame header and arguments behind. (The call instruction can't just discard
112 extra arguments, because the "arguments" object may access them later.)
113 This copying strategy ensures that all named values will be at the indices
114 expected by the callee.
118 bool CodeGenerator::s_dumpsGeneratedCode = false;
121 void CodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode)
124 s_dumpsGeneratedCode = dumpsGeneratedCode;
126 UNUSED_PARAM(dumpsGeneratedCode);
130 void CodeGenerator::generate()
132 m_codeBlock->thisRegister = m_thisRegister.index();
134 m_scopeNode->emitCode(*this);
137 if (s_dumpsGeneratedCode) {
138 JSGlobalObject* globalObject = m_scopeChain->globalObject();
139 m_codeBlock->dump(globalObject->globalExec());
143 m_scopeNode->children().shrinkCapacity(0);
144 if (m_codeType != EvalCode) { // eval code needs to hang on to its declaration stacks to keep declaration info alive until Machine::execute time.
145 m_scopeNode->varStack().shrinkCapacity(0);
146 m_scopeNode->functionStack().shrinkCapacity(0);
150 bool CodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
152 int index = m_calleeRegisters.size();
153 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
154 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
156 if (!result.second) {
157 r0 = ®isterFor(result.first->second.getIndex());
161 ++m_codeBlock->numVars;
166 bool CodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
168 int index = m_nextGlobal;
169 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
170 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
173 index = result.first->second.getIndex();
176 m_globals.append(index + m_globalVarStorageOffset);
179 r0 = ®isterFor(index);
180 return result.second;
183 void CodeGenerator::allocateConstants(size_t count)
185 m_codeBlock->numConstants = count;
189 m_nextConstant = m_calleeRegisters.size();
191 for (size_t i = 0; i < count; ++i)
193 m_lastConstant = &m_calleeRegisters.last();
196 CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, VarStack& varStack, FunctionStack& functionStack)
197 : m_shouldEmitDebugHooks(!!debugger)
198 , m_scopeChain(&scopeChain)
199 , m_symbolTable(symbolTable)
200 , m_scopeNode(programNode)
201 , m_codeBlock(codeBlock)
202 , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
204 , m_dynamicScopeDepth(0)
205 , m_codeType(GlobalCode)
208 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
209 , m_lastOpcodeID(op_end)
211 if (m_shouldEmitDebugHooks)
212 m_codeBlock->needsFullScopeChain = true;
214 emitOpcode(op_enter);
215 codeBlock->globalData = m_globalData;
217 // FIXME: Move code that modifies the global object to Machine::execute.
219 m_codeBlock->numParameters = 1; // Allocate space for "this"
221 JSGlobalObject* globalObject = scopeChain.globalObject();
222 ExecState* exec = globalObject->globalExec();
223 RegisterFile* registerFile = &exec->globalData().machine->registerFile();
225 // Shift register indexes in generated code to elide registers allocated by intermediate stack frames.
226 m_globalVarStorageOffset = -RegisterFile::CallFrameHeaderSize - m_codeBlock->numParameters - registerFile->size();
228 // Add previously defined symbols to bookkeeping.
229 m_globals.resize(symbolTable->size());
230 SymbolTable::iterator end = symbolTable->end();
231 for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
232 registerFor(it->second.getIndex()).setIndex(it->second.getIndex() + m_globalVarStorageOffset);
234 BatchedTransitionOptimizer optimizer(globalObject);
236 bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();
237 if (canOptimizeNewGlobals) {
238 // Shift new symbols so they get stored prior to existing symbols.
239 m_nextGlobal -= symbolTable->size();
241 for (size_t i = 0; i < functionStack.size(); ++i) {
242 FuncDeclNode* funcDecl = functionStack[i].get();
243 globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
244 emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);
247 Vector<RegisterID*, 32> newVars;
248 for (size_t i = 0; i < varStack.size(); ++i)
249 if (!globalObject->hasProperty(exec, varStack[i].first))
250 newVars.append(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant));
252 allocateConstants(programNode->neededConstants());
254 for (size_t i = 0; i < newVars.size(); ++i)
255 emitLoad(newVars[i], jsUndefined());
257 for (size_t i = 0; i < functionStack.size(); ++i) {
258 FuncDeclNode* funcDecl = functionStack[i].get();
259 globalObject->putWithAttributes(exec, funcDecl->m_ident, funcDecl->makeFunction(exec, scopeChain.node()), DontDelete);
261 for (size_t i = 0; i < varStack.size(); ++i) {
262 if (globalObject->hasProperty(exec, varStack[i].first))
264 int attributes = DontDelete;
265 if (varStack[i].second & DeclarationStacks::IsConstant)
266 attributes |= ReadOnly;
267 globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes);
270 allocateConstants(programNode->neededConstants());
274 CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock)
275 : m_shouldEmitDebugHooks(!!debugger)
276 , m_scopeChain(&scopeChain)
277 , m_symbolTable(symbolTable)
278 , m_scopeNode(functionBody)
279 , m_codeBlock(codeBlock)
281 , m_dynamicScopeDepth(0)
282 , m_codeType(FunctionCode)
284 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
285 , m_lastOpcodeID(op_end)
287 if (m_shouldEmitDebugHooks)
288 m_codeBlock->needsFullScopeChain = true;
290 codeBlock->globalData = m_globalData;
292 bool usesArguments = functionBody->usesArguments();
293 codeBlock->usesArguments = usesArguments;
295 m_argumentsRegister.setIndex(RegisterFile::OptionalCalleeArguments);
296 addVar(propertyNames().arguments, false);
299 if (m_codeBlock->needsFullScopeChain) {
300 ++m_codeBlock->numVars;
301 m_activationRegisterIndex = newRegister()->index();
302 emitOpcode(op_enter_with_activation);
303 instructions().append(m_activationRegisterIndex);
305 emitOpcode(op_enter);
308 emitOpcode(op_create_arguments);
310 const Node::FunctionStack& functionStack = functionBody->functionStack();
311 for (size_t i = 0; i < functionStack.size(); ++i) {
312 FuncDeclNode* funcDecl = functionStack[i].get();
313 const Identifier& ident = funcDecl->m_ident;
314 m_functions.add(ident.ustring().rep());
315 emitNewFunction(addVar(ident, false), funcDecl);
318 const Node::VarStack& varStack = functionBody->varStack();
319 for (size_t i = 0; i < varStack.size(); ++i)
320 addVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant);
322 const Identifier* parameters = functionBody->parameters();
323 size_t parameterCount = functionBody->parameterCount();
324 m_nextParameter = -RegisterFile::CallFrameHeaderSize - parameterCount - 1;
325 m_parameters.resize(1 + parameterCount); // reserve space for "this"
327 // Add "this" as a parameter
328 m_thisRegister.setIndex(m_nextParameter);
330 ++m_codeBlock->numParameters;
332 if (functionBody->usesThis()) {
333 emitOpcode(op_convert_this);
334 instructions().append(m_thisRegister.index());
337 for (size_t i = 0; i < parameterCount; ++i)
338 addParameter(parameters[i]);
340 allocateConstants(functionBody->neededConstants());
343 CodeGenerator::CodeGenerator(EvalNode* evalNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock)
344 : m_shouldEmitDebugHooks(!!debugger)
345 , m_scopeChain(&scopeChain)
346 , m_symbolTable(symbolTable)
347 , m_scopeNode(evalNode)
348 , m_codeBlock(codeBlock)
349 , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
351 , m_dynamicScopeDepth(0)
352 , m_codeType(EvalCode)
354 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
355 , m_lastOpcodeID(op_end)
357 if (m_shouldEmitDebugHooks)
358 m_codeBlock->needsFullScopeChain = true;
360 emitOpcode(op_enter);
361 codeBlock->globalData = m_globalData;
362 m_codeBlock->numParameters = 1; // Allocate space for "this"
364 allocateConstants(evalNode->neededConstants());
367 RegisterID* CodeGenerator::addParameter(const Identifier& ident)
369 // Parameters overwrite var declarations, but not function declarations.
370 RegisterID* result = 0;
371 UString::Rep* rep = ident.ustring().rep();
372 if (!m_functions.contains(rep)) {
373 symbolTable().set(rep, m_nextParameter);
374 RegisterID& parameter = registerFor(m_nextParameter);
375 parameter.setIndex(m_nextParameter);
379 // To maintain the calling convention, we have to allocate unique space for
380 // each parameter, even if the parameter doesn't make it into the symbol table.
382 ++m_codeBlock->numParameters;
386 RegisterID* CodeGenerator::registerFor(const Identifier& ident)
388 if (ident == propertyNames().thisIdentifier)
389 return &m_thisRegister;
391 if (!shouldOptimizeLocals())
394 SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
398 return ®isterFor(entry.getIndex());
401 RegisterID* CodeGenerator::constRegisterFor(const Identifier& ident)
403 if (m_codeType == EvalCode)
406 SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
407 ASSERT(!entry.isNull());
409 return ®isterFor(entry.getIndex());
412 bool CodeGenerator::isLocal(const Identifier& ident)
414 if (ident == propertyNames().thisIdentifier)
417 return shouldOptimizeLocals() && symbolTable().contains(ident.ustring().rep());
420 bool CodeGenerator::isLocalConstant(const Identifier& ident)
422 return symbolTable().get(ident.ustring().rep()).isReadOnly();
425 RegisterID* CodeGenerator::newRegister()
427 m_calleeRegisters.append(m_calleeRegisters.size());
428 m_codeBlock->numCalleeRegisters = max<int>(m_codeBlock->numCalleeRegisters, m_calleeRegisters.size());
429 return &m_calleeRegisters.last();
432 RegisterID* CodeGenerator::newTemporary()
434 // Reclaim free register IDs.
435 while (m_calleeRegisters.size() && !m_calleeRegisters.last().refCount())
436 m_calleeRegisters.removeLast();
438 RegisterID* result = newRegister();
439 result->setTemporary();
443 RegisterID* CodeGenerator::highestUsedRegister()
445 size_t count = m_codeBlock->numCalleeRegisters;
446 while (m_calleeRegisters.size() < count)
448 return &m_calleeRegisters.last();
451 PassRefPtr<LabelID> CodeGenerator::newLabel()
453 // Reclaim free label IDs.
454 while (m_labels.size() && !m_labels.last().refCount())
455 m_labels.removeLast();
457 // Allocate new label ID.
458 m_labels.append(m_codeBlock);
459 return &m_labels.last();
462 PassRefPtr<LabelID> CodeGenerator::emitLabel(LabelID* l0)
464 l0->setLocation(instructions().size());
466 // This disables peephole optimizations when an instruction is a jump target
467 m_lastOpcodeID = op_end;
472 void CodeGenerator::emitOpcode(OpcodeID opcodeID)
474 instructions().append(globalData()->machine->getOpcode(opcodeID));
475 m_lastOpcodeID = opcodeID;
478 void CodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
480 ASSERT(instructions().size() >= 4);
481 size_t size = instructions().size();
482 dstIndex = instructions().at(size - 3).u.operand;
483 src1Index = instructions().at(size - 2).u.operand;
484 src2Index = instructions().at(size - 1).u.operand;
487 void CodeGenerator::retrieveLastUnaryOp(int& dstIndex, int& srcIndex)
489 ASSERT(instructions().size() >= 3);
490 size_t size = instructions().size();
491 dstIndex = instructions().at(size - 2).u.operand;
492 srcIndex = instructions().at(size - 1).u.operand;
495 void ALWAYS_INLINE CodeGenerator::rewindBinaryOp()
497 ASSERT(instructions().size() >= 4);
498 instructions().shrink(instructions().size() - 4);
501 void ALWAYS_INLINE CodeGenerator::rewindUnaryOp()
503 ASSERT(instructions().size() >= 3);
504 instructions().shrink(instructions().size() - 3);
507 PassRefPtr<LabelID> CodeGenerator::emitJump(LabelID* target)
509 emitOpcode(target->isForwardLabel() ? op_jmp : op_loop);
510 instructions().append(target->offsetFrom(instructions().size()));
514 PassRefPtr<LabelID> CodeGenerator::emitJumpIfTrue(RegisterID* cond, LabelID* target)
516 if (m_lastOpcodeID == op_less && !target->isForwardLabel()) {
521 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
523 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
525 emitOpcode(op_loop_if_less);
526 instructions().append(src1Index);
527 instructions().append(src2Index);
528 instructions().append(target->offsetFrom(instructions().size()));
531 } else if (m_lastOpcodeID == op_lesseq && !target->isForwardLabel()) {
536 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
538 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
540 emitOpcode(op_loop_if_lesseq);
541 instructions().append(src1Index);
542 instructions().append(src2Index);
543 instructions().append(target->offsetFrom(instructions().size()));
548 emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true);
549 instructions().append(cond->index());
550 instructions().append(target->offsetFrom(instructions().size()));
554 PassRefPtr<LabelID> CodeGenerator::emitJumpIfFalse(RegisterID* cond, LabelID* target)
556 ASSERT(target->isForwardLabel());
558 if (m_lastOpcodeID == op_less) {
563 retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
565 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
567 emitOpcode(op_jnless);
568 instructions().append(src1Index);
569 instructions().append(src2Index);
570 instructions().append(target->offsetFrom(instructions().size()));
573 } else if (m_lastOpcodeID == op_not) {
577 retrieveLastUnaryOp(dstIndex, srcIndex);
579 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
581 emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true);
582 instructions().append(srcIndex);
583 instructions().append(target->offsetFrom(instructions().size()));
588 emitOpcode(op_jfalse);
589 instructions().append(cond->index());
590 instructions().append(target->offsetFrom(instructions().size()));
594 unsigned CodeGenerator::addConstant(FuncDeclNode* n)
596 // No need to explicitly unique function body nodes -- they're unique already.
597 int index = m_codeBlock->functions.size();
598 m_codeBlock->functions.append(n);
602 unsigned CodeGenerator::addConstant(FuncExprNode* n)
604 // No need to explicitly unique function expression nodes -- they're unique already.
605 int index = m_codeBlock->functionExpressions.size();
606 m_codeBlock->functionExpressions.append(n);
610 unsigned CodeGenerator::addConstant(const Identifier& ident)
612 UString::Rep* rep = ident.ustring().rep();
613 pair<IdentifierMap::iterator, bool> result = m_identifierMap.add(rep, m_codeBlock->identifiers.size());
614 if (result.second) // new entry
615 m_codeBlock->identifiers.append(Identifier(m_globalData, rep));
617 return result.first->second;
620 RegisterID* CodeGenerator::addConstant(JSValue* v)
622 pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(v, m_nextConstant);
624 RegisterID& constant = m_calleeRegisters[m_nextConstant];
628 m_codeBlock->constantRegisters.append(v);
632 return ®isterFor(result.first->second);
635 unsigned CodeGenerator::addUnexpectedConstant(JSValue* v)
637 int index = m_codeBlock->unexpectedConstants.size();
638 m_codeBlock->unexpectedConstants.append(v);
642 unsigned CodeGenerator::addRegExp(RegExp* r)
644 int index = m_codeBlock->regexps.size();
645 m_codeBlock->regexps.append(r);
649 RegisterID* CodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
652 instructions().append(dst->index());
653 instructions().append(src->index());
657 RegisterID* CodeGenerator::emitUnaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src)
660 instructions().append(dst->index());
661 instructions().append(src->index());
665 RegisterID* CodeGenerator::emitPreInc(RegisterID* srcDst)
667 emitOpcode(op_pre_inc);
668 instructions().append(srcDst->index());
672 RegisterID* CodeGenerator::emitPreDec(RegisterID* srcDst)
674 emitOpcode(op_pre_dec);
675 instructions().append(srcDst->index());
679 RegisterID* CodeGenerator::emitPostInc(RegisterID* dst, RegisterID* srcDst)
681 emitOpcode(op_post_inc);
682 instructions().append(dst->index());
683 instructions().append(srcDst->index());
687 RegisterID* CodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst)
689 emitOpcode(op_post_dec);
690 instructions().append(dst->index());
691 instructions().append(srcDst->index());
695 RegisterID* CodeGenerator::emitBinaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types)
698 instructions().append(dst->index());
699 instructions().append(src1->index());
700 instructions().append(src2->index());
702 if (opcode == op_bitor || opcode == op_bitand || opcode == op_bitxor ||
703 opcode == op_add || opcode == op_mul || opcode == op_sub) {
704 instructions().append(types.toInt());
710 RegisterID* CodeGenerator::emitEqualityOp(OpcodeID opcode, RegisterID* dst, RegisterID* src1, RegisterID* src2)
712 if (m_lastOpcodeID == op_typeof) {
716 retrieveLastUnaryOp(dstIndex, srcIndex);
718 if (src1->index() == dstIndex
719 && src1->isTemporary()
720 && static_cast<unsigned>(src2->index()) < m_codeBlock->constantRegisters.size()
721 && m_codeBlock->constantRegisters[src2->index()].jsValue(m_scopeChain->globalObject()->globalExec())->isString()) {
722 const UString& value = static_cast<JSString*>(m_codeBlock->constantRegisters[src2->index()].jsValue(m_scopeChain->globalObject()->globalExec()))->value();
723 if (value == "undefined") {
725 emitOpcode(op_is_undefined);
726 instructions().append(dst->index());
727 instructions().append(srcIndex);
730 if (value == "boolean") {
732 emitOpcode(op_is_boolean);
733 instructions().append(dst->index());
734 instructions().append(srcIndex);
737 if (value == "number") {
739 emitOpcode(op_is_number);
740 instructions().append(dst->index());
741 instructions().append(srcIndex);
744 if (value == "string") {
746 emitOpcode(op_is_string);
747 instructions().append(dst->index());
748 instructions().append(srcIndex);
751 if (value == "object") {
753 emitOpcode(op_is_object);
754 instructions().append(dst->index());
755 instructions().append(srcIndex);
758 if (value == "function") {
760 emitOpcode(op_is_function);
761 instructions().append(dst->index());
762 instructions().append(srcIndex);
769 instructions().append(dst->index());
770 instructions().append(src1->index());
771 instructions().append(src2->index());
775 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, bool b)
777 return emitLoad(dst, jsBoolean(b));
780 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, double number)
782 // FIXME: Our hash tables won't hold infinity, so we make a new JSNumberCell each time.
783 // Later we can do the extra work to handle that like the other cases.
784 if (number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number))
785 return emitLoad(dst, jsNumber(globalData(), number));
786 JSValue*& valueInMap = m_numberMap.add(number, 0).first->second;
788 valueInMap = jsNumber(globalData(), number);
789 return emitLoad(dst, valueInMap);
792 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier)
794 JSString*& valueInMap = m_stringMap.add(identifier.ustring().rep(), 0).first->second;
796 valueInMap = jsOwnedString(globalData(), identifier.ustring());
797 return emitLoad(dst, valueInMap);
800 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, JSValue* v)
802 RegisterID* constantID = addConstant(v);
804 return emitMove(dst, constantID);
808 RegisterID* CodeGenerator::emitUnexpectedLoad(RegisterID* dst, bool b)
810 emitOpcode(op_unexpected_load);
811 instructions().append(dst->index());
812 instructions().append(addUnexpectedConstant(jsBoolean(b)));
816 RegisterID* CodeGenerator::emitUnexpectedLoad(RegisterID* dst, double d)
818 emitOpcode(op_unexpected_load);
819 instructions().append(dst->index());
820 instructions().append(addUnexpectedConstant(jsNumber(globalData(), d)));
824 bool CodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, JSValue*& globalObject)
826 // Cases where we cannot statically optimise the lookup
827 if (property == propertyNames().arguments || !canOptimizeNonLocals()) {
829 index = missingSymbolMarker();
831 if (shouldOptimizeLocals() && m_codeType == GlobalCode) {
832 ScopeChainIterator iter = m_scopeChain->begin();
833 globalObject = *iter;
834 ASSERT((++iter) == m_scopeChain->end());
841 ScopeChainIterator iter = m_scopeChain->begin();
842 ScopeChainIterator end = m_scopeChain->end();
843 for (; iter != end; ++iter, ++depth) {
844 JSObject* currentScope = *iter;
845 if (!currentScope->isVariableObject())
847 JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
848 SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.ustring().rep());
850 // Found the property
851 if (!entry.isNull()) {
852 if (entry.isReadOnly() && forWriting) {
854 index = missingSymbolMarker();
856 globalObject = currentVariableObject;
860 index = entry.getIndex();
862 globalObject = currentVariableObject;
865 if (currentVariableObject->isDynamicScope())
869 // Can't locate the property but we're able to avoid a few lookups
871 index = missingSymbolMarker();
872 JSObject* scope = *iter;
874 globalObject = scope;
878 RegisterID* CodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype)
880 emitOpcode(op_instanceof);
881 instructions().append(dst->index());
882 instructions().append(value->index());
883 instructions().append(base->index());
884 instructions().append(basePrototype->index());
888 RegisterID* CodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
892 JSValue* globalObject = 0;
893 if (!findScopedProperty(property, index, depth, false, globalObject) && !globalObject) {
894 // We can't optimise at all :-(
895 emitOpcode(op_resolve);
896 instructions().append(dst->index());
897 instructions().append(addConstant(property));
901 if (index != missingSymbolMarker()) {
902 // Directly index the property lookup across multiple scopes. Yay!
903 return emitGetScopedVar(dst, depth, index, globalObject);
907 m_codeBlock->structureIDInstructions.append(instructions().size());
908 emitOpcode(op_resolve_global);
909 instructions().append(dst->index());
910 instructions().append(static_cast<JSCell*>(globalObject));
911 instructions().append(addConstant(property));
912 instructions().append(0);
913 instructions().append(0);
917 // In this case we are at least able to drop a few scope chains from the
918 // lookup chain, although we still need to hash from then on.
919 emitOpcode(op_resolve_skip);
920 instructions().append(dst->index());
921 instructions().append(addConstant(property));
922 instructions().append(depth);
926 RegisterID* CodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValue* globalObject)
929 emitOpcode(op_get_global_var);
930 instructions().append(dst->index());
931 instructions().append(static_cast<JSCell*>(globalObject));
932 instructions().append(index);
936 emitOpcode(op_get_scoped_var);
937 instructions().append(dst->index());
938 instructions().append(index);
939 instructions().append(depth);
943 RegisterID* CodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValue* globalObject)
946 emitOpcode(op_put_global_var);
947 instructions().append(static_cast<JSCell*>(globalObject));
948 instructions().append(index);
949 instructions().append(value->index());
952 emitOpcode(op_put_scoped_var);
953 instructions().append(index);
954 instructions().append(depth);
955 instructions().append(value->index());
959 RegisterID* CodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property)
961 emitOpcode(op_resolve_base);
962 instructions().append(dst->index());
963 instructions().append(addConstant(property));
967 RegisterID* CodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
969 emitOpcode(op_resolve_with_base);
970 instructions().append(baseDst->index());
971 instructions().append(propDst->index());
972 instructions().append(addConstant(property));
976 RegisterID* CodeGenerator::emitResolveFunction(RegisterID* baseDst, RegisterID* funcDst, const Identifier& property)
978 emitOpcode(op_resolve_func);
979 instructions().append(baseDst->index());
980 instructions().append(funcDst->index());
981 instructions().append(addConstant(property));
985 RegisterID* CodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
987 m_codeBlock->structureIDInstructions.append(instructions().size());
989 emitOpcode(op_get_by_id);
990 instructions().append(dst->index());
991 instructions().append(base->index());
992 instructions().append(addConstant(property));
993 instructions().append(0);
994 instructions().append(0);
995 instructions().append(0);
996 instructions().append(0);
1000 RegisterID* CodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
1002 m_codeBlock->structureIDInstructions.append(instructions().size());
1004 emitOpcode(op_put_by_id);
1005 instructions().append(base->index());
1006 instructions().append(addConstant(property));
1007 instructions().append(value->index());
1008 instructions().append(0);
1009 instructions().append(0);
1010 instructions().append(0);
1011 instructions().append(0);
1015 RegisterID* CodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
1017 emitOpcode(op_put_getter);
1018 instructions().append(base->index());
1019 instructions().append(addConstant(property));
1020 instructions().append(value->index());
1024 RegisterID* CodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
1026 emitOpcode(op_put_setter);
1027 instructions().append(base->index());
1028 instructions().append(addConstant(property));
1029 instructions().append(value->index());
1033 RegisterID* CodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
1035 emitOpcode(op_del_by_id);
1036 instructions().append(dst->index());
1037 instructions().append(base->index());
1038 instructions().append(addConstant(property));
1042 RegisterID* CodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
1044 emitOpcode(op_get_by_val);
1045 instructions().append(dst->index());
1046 instructions().append(base->index());
1047 instructions().append(property->index());
1051 RegisterID* CodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
1053 emitOpcode(op_put_by_val);
1054 instructions().append(base->index());
1055 instructions().append(property->index());
1056 instructions().append(value->index());
1060 RegisterID* CodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
1062 emitOpcode(op_del_by_val);
1063 instructions().append(dst->index());
1064 instructions().append(base->index());
1065 instructions().append(property->index());
1069 RegisterID* CodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value)
1071 emitOpcode(op_put_by_index);
1072 instructions().append(base->index());
1073 instructions().append(index);
1074 instructions().append(value->index());
1078 RegisterID* CodeGenerator::emitNewObject(RegisterID* dst)
1080 emitOpcode(op_new_object);
1081 instructions().append(dst->index());
1085 RegisterID* CodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements)
1087 Vector<RefPtr<RegisterID>, 16> argv;
1088 for (ElementNode* n = elements; n; n = n->next()) {
1091 argv.append(newTemporary());
1092 emitNode(argv.last().get(), n->value());
1094 emitOpcode(op_new_array);
1095 instructions().append(dst->index());
1096 instructions().append(argv.size() ? argv[0]->index() : 0); // argv
1097 instructions().append(argv.size()); // argc
1101 RegisterID* CodeGenerator::emitNewFunction(RegisterID* dst, FuncDeclNode* n)
1103 emitOpcode(op_new_func);
1104 instructions().append(dst->index());
1105 instructions().append(addConstant(n));
1109 RegisterID* CodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
1111 emitOpcode(op_new_regexp);
1112 instructions().append(dst->index());
1113 instructions().append(addRegExp(regExp));
1118 RegisterID* CodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
1120 emitOpcode(op_new_func_exp);
1121 instructions().append(r0->index());
1122 instructions().append(addConstant(n));
1126 RegisterID* CodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
1128 return emitCall(op_call, dst, func, base, argumentsNode, divot, startOffset, endOffset);
1131 RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
1133 return emitCall(op_call_eval, dst, func, base, argumentsNode, divot, startOffset, endOffset);
1136 RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
1138 ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
1139 ASSERT(func->refCount());
1140 ASSERT(!base || base->refCount());
1142 // Generate code for arguments.
1143 Vector<RefPtr<RegisterID>, 16> argv;
1144 argv.append(newTemporary()); // reserve space for "this"
1145 for (ArgumentListNode* n = argumentsNode->m_listNode.get(); n; n = n->m_next.get()) {
1146 argv.append(newTemporary());
1147 emitNode(argv.last().get(), n);
1150 // Reserve space for call frame.
1151 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
1152 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
1153 callFrame.append(newTemporary());
1155 emitExpressionInfo(divot, startOffset, endOffset);
1156 emitOpcode(opcodeID);
1157 instructions().append(dst->index());
1158 instructions().append(func->index());
1159 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.
1160 instructions().append(argv[0]->index()); // argv
1161 instructions().append(argv.size()); // argc
1162 instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset
1166 RegisterID* CodeGenerator::emitReturn(RegisterID* src)
1168 if (m_codeBlock->needsFullScopeChain) {
1169 emitOpcode(op_tear_off_activation);
1170 instructions().append(m_activationRegisterIndex);
1171 } else if (m_codeBlock->usesArguments && m_codeBlock->numParameters > 1)
1172 emitOpcode(op_tear_off_arguments);
1174 return emitUnaryNoDstOp(op_ret, src);
1177 RegisterID* CodeGenerator::emitUnaryNoDstOp(OpcodeID opcode, RegisterID* src)
1180 instructions().append(src->index());
1184 RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
1186 ASSERT(func->refCount());
1189 emitExpressionInfo(divot, startOffset, endOffset);
1190 RefPtr<RegisterID> funcProto = newTemporary();
1191 emitGetById(funcProto.get(), func, globalData()->propertyNames->prototype);
1193 // Generate code for arguments.
1194 Vector<RefPtr<RegisterID>, 16> argv;
1195 argv.append(newTemporary()); // reserve space for "this"
1196 for (ArgumentListNode* n = argumentsNode ? argumentsNode->m_listNode.get() : 0; n; n = n->m_next.get()) {
1197 argv.append(newTemporary());
1198 emitNode(argv.last().get(), n);
1201 // Reserve space for call frame.
1202 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
1203 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
1204 callFrame.append(newTemporary());
1206 emitExpressionInfo(divot, startOffset, endOffset);
1207 emitOpcode(op_construct);
1208 instructions().append(dst->index());
1209 instructions().append(func->index());
1210 instructions().append(funcProto->index());
1211 instructions().append(argv[0]->index()); // argv
1212 instructions().append(argv.size()); // argc
1213 instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset
1215 emitOpcode(op_construct_verify);
1216 instructions().append(dst->index());
1217 instructions().append(argv[0]->index());
1222 RegisterID* CodeGenerator::emitPushScope(RegisterID* scope)
1224 ControlFlowContext context;
1225 context.isFinallyBlock = false;
1226 m_scopeContextStack.append(context);
1227 m_dynamicScopeDepth++;
1229 return emitUnaryNoDstOp(op_push_scope, scope);
1232 void CodeGenerator::emitPopScope()
1234 ASSERT(m_scopeContextStack.size());
1235 ASSERT(!m_scopeContextStack.last().isFinallyBlock);
1237 emitOpcode(op_pop_scope);
1239 m_scopeContextStack.removeLast();
1240 m_dynamicScopeDepth--;
1243 void CodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine)
1245 if (!m_shouldEmitDebugHooks)
1247 emitOpcode(op_debug);
1248 instructions().append(debugHookID);
1249 instructions().append(firstLine);
1250 instructions().append(lastLine);
1253 void CodeGenerator::pushFinallyContext(LabelID* target, RegisterID* retAddrDst)
1255 ControlFlowContext scope;
1256 scope.isFinallyBlock = true;
1257 FinallyContext context = { target, retAddrDst };
1258 scope.finallyContext = context;
1259 m_scopeContextStack.append(scope);
1263 void CodeGenerator::popFinallyContext()
1265 ASSERT(m_scopeContextStack.size());
1266 ASSERT(m_scopeContextStack.last().isFinallyBlock);
1267 ASSERT(m_finallyDepth > 0);
1268 m_scopeContextStack.removeLast();
1272 void CodeGenerator::pushJumpContext(LabelStack* labels, LabelID* continueTarget, LabelID* breakTarget, bool isValidUnlabeledBreakTarget)
1274 JumpContext context = { labels, continueTarget, breakTarget, scopeDepth(), isValidUnlabeledBreakTarget };
1275 m_jumpContextStack.append(context);
1280 void CodeGenerator::popJumpContext()
1282 ASSERT(m_jumpContextStack.size());
1283 if (m_jumpContextStack.last().continueTarget)
1285 m_jumpContextStack.removeLast();
1288 JumpContext* CodeGenerator::jumpContextForContinue(const Identifier& label)
1290 if(!m_jumpContextStack.size())
1293 if (label.isEmpty()) {
1294 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1295 JumpContext* scope = &m_jumpContextStack[i];
1296 if (scope->continueTarget)
1302 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1303 JumpContext* scope = &m_jumpContextStack[i];
1304 if (scope->labels->contains(label))
1310 JumpContext* CodeGenerator::jumpContextForBreak(const Identifier& label)
1312 if(!m_jumpContextStack.size())
1315 if (label.isEmpty()) {
1316 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1317 JumpContext* scope = &m_jumpContextStack[i];
1318 if (scope->isValidUnlabeledBreakTarget)
1324 for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1325 JumpContext* scope = &m_jumpContextStack[i];
1326 if (scope->labels->contains(label))
1332 PassRefPtr<LabelID> CodeGenerator::emitComplexJumpScopes(LabelID* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope)
1334 while (topScope > bottomScope) {
1335 // First we count the number of dynamic scopes we need to remove to get
1336 // to a finally block.
1337 int nNormalScopes = 0;
1338 while (topScope > bottomScope) {
1339 if (topScope->isFinallyBlock)
1345 if (nNormalScopes) {
1346 // We need to remove a number of dynamic scopes to get to the next
1348 emitOpcode(op_jmp_scopes);
1349 instructions().append(nNormalScopes);
1351 // If topScope == bottomScope then there isn't actually a finally block
1352 // left to emit, so make the jmp_scopes jump directly to the target label
1353 if (topScope == bottomScope) {
1354 instructions().append(target->offsetFrom(instructions().size()));
1358 // Otherwise we just use jmp_scopes to pop a group of scopes and go
1359 // to the next instruction
1360 RefPtr<LabelID> nextInsn = newLabel();
1361 instructions().append(nextInsn->offsetFrom(instructions().size()));
1362 emitLabel(nextInsn.get());
1365 // To get here there must be at least one finally block present
1367 ASSERT(topScope->isFinallyBlock);
1368 emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr);
1370 if (!topScope->isFinallyBlock)
1372 } while (topScope > bottomScope);
1374 return emitJump(target);
1377 PassRefPtr<LabelID> CodeGenerator::emitJumpScopes(LabelID* target, int targetScopeDepth)
1379 ASSERT(scopeDepth() - targetScopeDepth >= 0);
1380 ASSERT(target->isForwardLabel());
1382 size_t scopeDelta = scopeDepth() - targetScopeDepth;
1383 ASSERT(scopeDelta <= m_scopeContextStack.size());
1385 return emitJump(target);
1388 return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta);
1390 emitOpcode(op_jmp_scopes);
1391 instructions().append(scopeDelta);
1392 instructions().append(target->offsetFrom(instructions().size()));
1396 RegisterID* CodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* iter, LabelID* target)
1398 emitOpcode(op_next_pname);
1399 instructions().append(dst->index());
1400 instructions().append(iter->index());
1401 instructions().append(target->offsetFrom(instructions().size()));
1405 RegisterID* CodeGenerator::emitCatch(RegisterID* targetRegister, LabelID* start, LabelID* end)
1407 HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth, 0 };
1408 exceptionHandlers().append(info);
1409 emitOpcode(op_catch);
1410 instructions().append(targetRegister->index());
1411 return targetRegister;
1414 RegisterID* CodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValue* message)
1416 emitOpcode(op_new_error);
1417 instructions().append(dst->index());
1418 instructions().append(static_cast<int>(type));
1419 instructions().append(addUnexpectedConstant(message));
1423 PassRefPtr<LabelID> CodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, LabelID* finally)
1426 instructions().append(retAddrDst->index());
1427 instructions().append(finally->offsetFrom(instructions().size()));
1431 void CodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc)
1433 emitOpcode(op_sret);
1434 instructions().append(retAddrSrc->index());
1437 void CodeGenerator::emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value)
1439 ControlFlowContext context;
1440 context.isFinallyBlock = false;
1441 m_scopeContextStack.append(context);
1442 m_dynamicScopeDepth++;
1444 emitOpcode(op_push_new_scope);
1445 instructions().append(dst->index());
1446 instructions().append(addConstant(property));
1447 instructions().append(value->index());
1450 void CodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type)
1452 SwitchInfo info = { instructions().size(), type };
1454 case SwitchInfo::SwitchImmediate:
1455 emitOpcode(op_switch_imm);
1457 case SwitchInfo::SwitchCharacter:
1458 emitOpcode(op_switch_char);
1460 case SwitchInfo::SwitchString:
1461 emitOpcode(op_switch_string);
1464 ASSERT_NOT_REACHED();
1467 instructions().append(0); // place holder for table index
1468 instructions().append(0); // place holder for default target
1469 instructions().append(scrutineeRegister->index());
1470 m_switchContextStack.append(info);
1473 static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max)
1476 ASSERT(node->isNumber());
1477 double value = static_cast<NumberNode*>(node)->value();
1478 ASSERT(JSImmediate::from(value));
1479 int32_t key = static_cast<int32_t>(value);
1480 ASSERT(key == value);
1486 static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1488 jumpTable.min = min;
1489 jumpTable.branchOffsets.resize(max - min + 1);
1490 jumpTable.branchOffsets.fill(0);
1491 for (uint32_t i = 0; i < clauseCount; ++i) {
1492 // We're emitting this after the clause labels should have been fixed, so
1493 // the labels should not be "forward" references
1494 ASSERT(!labels[i]->isForwardLabel());
1495 jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress));
1499 static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max)
1502 ASSERT(node->isString());
1503 UString::Rep* clause = static_cast<StringNode*>(node)->value().ustring().rep();
1504 ASSERT(clause->size() == 1);
1506 int32_t key = clause->data()[0];
1512 static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1514 jumpTable.min = min;
1515 jumpTable.branchOffsets.resize(max - min + 1);
1516 jumpTable.branchOffsets.fill(0);
1517 for (uint32_t i = 0; i < clauseCount; ++i) {
1518 // We're emitting this after the clause labels should have been fixed, so
1519 // the labels should not be "forward" references
1520 ASSERT(!labels[i]->isForwardLabel());
1521 jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress));
1525 static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes)
1527 for (uint32_t i = 0; i < clauseCount; ++i) {
1528 // We're emitting this after the clause labels should have been fixed, so
1529 // the labels should not be "forward" references
1530 ASSERT(!labels[i]->isForwardLabel());
1532 ASSERT(nodes[i]->isString());
1533 UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().ustring().rep();
1534 OffsetLocation location;
1535 location.branchOffset = labels[i]->offsetFrom(switchAddress);
1537 location.ctiOffset = 0;
1539 jumpTable.offsetTable.add(clause, location);
1543 void CodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, LabelID* defaultLabel, int32_t min, int32_t max)
1545 SwitchInfo switchInfo = m_switchContextStack.last();
1546 m_switchContextStack.removeLast();
1547 if (switchInfo.switchType == SwitchInfo::SwitchImmediate) {
1548 instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->immediateSwitchJumpTables.size();
1549 instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1551 m_codeBlock->immediateSwitchJumpTables.append(SimpleJumpTable());
1552 SimpleJumpTable& jumpTable = m_codeBlock->immediateSwitchJumpTables.last();
1554 prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes, min, max);
1555 } else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) {
1556 instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->characterSwitchJumpTables.size();
1557 instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1559 m_codeBlock->characterSwitchJumpTables.append(SimpleJumpTable());
1560 SimpleJumpTable& jumpTable = m_codeBlock->characterSwitchJumpTables.last();
1562 prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes, min, max);
1564 ASSERT(switchInfo.switchType == SwitchInfo::SwitchString);
1565 instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->stringSwitchJumpTables.size();
1566 instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1568 m_codeBlock->stringSwitchJumpTables.append(StringJumpTable());
1569 StringJumpTable& jumpTable = m_codeBlock->stringSwitchJumpTables.last();
1571 prepareJumpTableForStringSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes);