f14e493989627e52590b103611aa60fff4ba67f3
[WebKit-https.git] / JavaScriptCore / VM / CodeGenerator.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
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.
17  *
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.
28  */
29
30 #include "config.h"
31 #include "CodeGenerator.h"
32
33 #include "JSFunction.h"
34 #include "Machine.h"
35 #include "ustring.h"
36
37 using namespace std;
38
39 namespace KJS {
40
41 /*
42     The layout of a register frame looks like this:
43
44     For
45
46     function f(x, y) {
47         var v1;
48         function g() { }
49         var v2;
50         return (x) * (y);
51     }
52
53     assuming (x) and (y) generated temporaries t1 and t2, you would have
54
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->
61
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.)
66
67     The register layout before a function call looks like this:
68
69     For
70
71     function f(x, y)
72     {
73     }
74
75     f(1);
76
77     >                        <------------------------------
78     <                        >  reserved: call frame  |  1 | <-- value held
79     >         >snip<         <------------------------------
80     <                        > +0 | +1 | +2 | +3 | +4 | +5 | <-- register index
81     >                        <------------------------------
82     | params->|<-locals      | temps->
83
84     The call instruction fills in the "call frame" registers. It also pads
85     missing arguments at the end of the call:
86
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->
93
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:
96
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->
103
104     That way, arguments are "copied" into the callee's stack frame for free.
105
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.
114 */
115
116 #ifndef NDEBUG
117 bool CodeGenerator::s_dumpsGeneratedCode = false;
118 #endif
119
120 void CodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode)
121 {
122 #ifndef NDEBUG
123     s_dumpsGeneratedCode = dumpsGeneratedCode;
124 #else
125     UNUSED_PARAM(dumpsGeneratedCode);
126 #endif
127 }
128
129 void CodeGenerator::generate()
130 {
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;
135
136     m_scopeNode->emitCode(*this);
137
138 #ifndef NDEBUG
139     if (s_dumpsGeneratedCode) {
140         JSGlobalObject* globalObject = m_scopeChain->globalObject();
141         m_codeBlock->dump(globalObject->globalExec());
142     }
143 #endif
144
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);
149     }
150 }
151
152 bool CodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
153 {
154     int index = m_nextVar;
155     SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
156     pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
157
158     if (!result.second)
159         index = result.first->second.getIndex();
160     else {
161         --m_nextVar;
162         ++m_codeBlock->numVars;
163
164         m_locals.append(index);
165     }
166
167     r0 = &m_locals[localsIndex(index)];
168     return result.second;
169 }
170
171 bool CodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
172 {
173     int index = m_nextVar;
174     SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
175     pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
176
177     if (!result.second)
178         index = result.first->second.getIndex();
179     else {
180         --m_nextVar;
181         m_locals.append(index + m_globalVarStorageOffset);
182     }
183
184     r0 = &m_locals[localsIndex(index)];
185     return result.second;
186 }
187
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)
195     , m_finallyDepth(0)
196     , m_dynamicScopeDepth(0)
197     , m_codeType(GlobalCode)
198     , m_continueDepth(0)
199     , m_nextVar(-1)
200     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
201     , m_lastOpcodeID(op_end)
202 {
203     // FIXME: Move code that modifies the global object to Machine::execute.
204     
205     m_codeBlock->numVars = 1; // Allocate space for "this"
206
207     JSGlobalObject* globalObject = scopeChain.globalObject();
208     ExecState* exec = globalObject->globalExec();
209     RegisterFile* registerFile = &exec->globalData().machine->registerFile();
210     
211     // Shift register indexes in generated code to elide registers allocated by intermediate stack frames.
212     m_globalVarStorageOffset = -1 - RegisterFile::CallFrameHeaderSize - registerFile->size();
213
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);
219
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();
224
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);
229         }
230
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());
234         }
235     } else {
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);
239         }
240         for (size_t i = 0; i < varStack.size(); ++i) {
241             if (globalObject->hasProperty(exec, varStack[i].first))
242                 continue;
243             int attributes = DontDelete;
244             if (varStack[i].second & DeclarationStacks::IsConstant)
245                 attributes |= ReadOnly;
246             globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes);
247         }
248     }
249 }
250
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)
257     , m_finallyDepth(0)
258     , m_dynamicScopeDepth(0)
259     , m_codeType(FunctionCode)
260     , m_continueDepth(0)
261     , m_nextVar(-1)
262     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
263     , m_lastOpcodeID(op_end)
264 {
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;
269
270         m_functions.add(ident.ustring().rep());
271         emitNewFunction(addVar(ident, false), funcDecl);
272     }
273
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)
278             continue;
279         addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
280     }
281
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
285
286     // Add "this" as a parameter
287     m_thisRegister.setIndex(m_nextParameter);
288     ++m_nextParameter;
289     ++m_codeBlock->numParameters;
290     
291     for (size_t i = 0; i < parameters.size(); ++i)
292         addParameter(parameters[i]);
293 }
294
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)
302     , m_finallyDepth(0)
303     , m_dynamicScopeDepth(0)
304     , m_codeType(EvalCode)
305     , m_continueDepth(0)
306     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
307     , m_lastOpcodeID(op_end)
308 {
309     m_codeBlock->numVars = 1; // Allocate space for "this"
310 }
311
312 CodeGenerator::~CodeGenerator()
313 {
314 }
315
316 RegisterID* CodeGenerator::addParameter(const Identifier& ident)
317 {
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)]);
326     }
327
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.
330     ++m_nextParameter;
331     ++m_codeBlock->numParameters;
332     return result;
333 }
334
335 RegisterID* CodeGenerator::registerForLocal(const Identifier& ident)
336 {
337     if (m_codeType == FunctionCode && ident == propertyNames().arguments)
338         m_codeBlock->needsFullScopeChain = true;
339
340     if (ident == propertyNames().thisIdentifier)
341         return &m_thisRegister;
342
343     if (!shouldOptimizeLocals())
344         return 0;
345
346     SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
347     if (entry.isNull())
348         return 0;
349
350     return &m_locals[localsIndex(entry.getIndex())];
351 }
352
353 RegisterID* CodeGenerator::registerForLocalConstInit(const Identifier& ident)
354 {
355     if (m_codeType == EvalCode)
356         return 0;
357
358     SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
359     ASSERT(!entry.isNull());
360
361     return &m_locals[localsIndex(entry.getIndex())];
362 }
363
364 bool CodeGenerator::isLocal(const Identifier& ident)
365 {
366     if (ident == propertyNames().thisIdentifier)
367         return true;
368     
369     return shouldOptimizeLocals() && symbolTable().contains(ident.ustring().rep());
370 }
371
372 bool CodeGenerator::isLocalConstant(const Identifier& ident)
373 {
374     return symbolTable().get(ident.ustring().rep()).isReadOnly();
375 }
376
377 RegisterID* CodeGenerator::newTemporary()
378 {
379     // Reclaim free register IDs.
380     while (m_temporaries.size() && !m_temporaries.last().refCount())
381         m_temporaries.removeLast();
382
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();
387 }
388
389 RegisterID* CodeGenerator::highestUsedRegister()
390 {
391     while (m_temporaries.size() < static_cast<unsigned>(m_codeBlock->numTemporaries))
392         m_temporaries.append(m_temporaries.size());
393     return &m_temporaries.last();
394 }
395
396 PassRefPtr<LabelID> CodeGenerator::newLabel()
397 {
398     // Reclaim free label IDs.
399     while (m_labels.size() && !m_labels.last().refCount())
400         m_labels.removeLast();
401
402     // Allocate new label ID.
403     m_labels.append(m_codeBlock);
404     return &m_labels.last();
405 }
406
407 PassRefPtr<LabelID> CodeGenerator::emitLabel(LabelID* l0)
408 {
409     l0->setLocation(instructions().size());
410     
411     // This disables peephole optimizations when an instruction is a jump target
412     m_lastOpcodeID = op_end;
413     
414     return l0;
415 }
416
417 void CodeGenerator::emitOpcode(OpcodeID opcodeID)
418 {
419     instructions().append(globalData()->machine->getOpcode(opcodeID));
420     m_lastOpcodeID = opcodeID;
421 }
422
423 void CodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
424 {
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;
430 }
431
432 void ALWAYS_INLINE CodeGenerator::rewindBinaryOp()
433 {
434     ASSERT(instructions().size() >= 4);
435     instructions().shrink(instructions().size() - 4);
436 }
437
438 PassRefPtr<LabelID> CodeGenerator::emitJump(LabelID* target)
439 {
440     emitOpcode(target->isForwardLabel() ? op_jmp : op_loop);
441     instructions().append(target->offsetFrom(instructions().size()));
442     return target;
443 }
444
445 PassRefPtr<LabelID> CodeGenerator::emitJumpIfTrue(RegisterID* cond, LabelID* target)
446 {
447     if (m_lastOpcodeID == op_less) {
448         int dstIndex;
449         int src1Index;
450         int src2Index;
451
452         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
453
454         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
455             rewindBinaryOp();
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()));
460             return target;
461         }
462     }
463
464     emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true);
465     instructions().append(cond->index());
466     instructions().append(target->offsetFrom(instructions().size()));
467     return target;
468 }
469
470 PassRefPtr<LabelID> CodeGenerator::emitJumpIfFalse(RegisterID* cond, LabelID* target)
471 {
472     ASSERT(target->isForwardLabel());
473
474     if (m_lastOpcodeID == op_less) {
475         int dstIndex;
476         int src1Index;
477         int src2Index;
478
479         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
480
481         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
482             rewindBinaryOp();
483             emitOpcode(op_jnless);
484             instructions().append(src1Index);
485             instructions().append(src2Index);
486             instructions().append(target->offsetFrom(instructions().size()));
487             return target;
488         }
489     }
490
491     emitOpcode(op_jfalse);
492     instructions().append(cond->index());
493     instructions().append(target->offsetFrom(instructions().size()));
494     return target;
495 }
496
497 unsigned CodeGenerator::addConstant(FuncDeclNode* n)
498 {
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);
502     return index;
503 }
504
505 unsigned CodeGenerator::addConstant(FuncExprNode* n)
506 {
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);
510     return index;
511 }
512
513 unsigned CodeGenerator::addConstant(const Identifier& ident)
514 {
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));
519
520     return result.first->second;
521 }
522
523 unsigned CodeGenerator::addConstant(JSValue* v)
524 {
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);
528
529     return result.first->second;
530 }
531
532 unsigned CodeGenerator::addRegExp(RegExp* r)
533 {
534     int index = m_codeBlock->regexps.size();
535     m_codeBlock->regexps.append(r);
536     return index;
537 }
538
539 RegisterID* CodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
540 {
541     emitOpcode(op_mov);
542     instructions().append(dst->index());
543     instructions().append(src->index());
544     return dst;
545 }
546
547 RegisterID* CodeGenerator::emitUnaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src)
548 {
549     emitOpcode(opcode);
550     instructions().append(dst->index());
551     instructions().append(src->index());
552     return dst;
553 }
554
555 RegisterID* CodeGenerator::emitPreInc(RegisterID* srcDst)
556 {
557     emitOpcode(op_pre_inc);
558     instructions().append(srcDst->index());
559     return srcDst;
560 }
561
562 RegisterID* CodeGenerator::emitPreDec(RegisterID* srcDst)
563 {
564     emitOpcode(op_pre_dec);
565     instructions().append(srcDst->index());
566     return srcDst;
567 }
568
569 RegisterID* CodeGenerator::emitPostInc(RegisterID* dst, RegisterID* srcDst)
570 {
571     emitOpcode(op_post_inc);
572     instructions().append(dst->index());
573     instructions().append(srcDst->index());
574     return dst;
575 }
576
577 RegisterID* CodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst)
578 {
579     emitOpcode(op_post_dec);
580     instructions().append(dst->index());
581     instructions().append(srcDst->index());
582     return dst;
583 }
584
585 RegisterID* CodeGenerator::emitBinaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src1, RegisterID* src2)
586 {
587     emitOpcode(opcode);
588     instructions().append(dst->index());
589     instructions().append(src1->index());
590     instructions().append(src2->index());
591     return dst;
592 }
593
594 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, bool b)
595 {
596     emitOpcode(op_load);
597     instructions().append(dst->index());
598     instructions().append(addConstant(jsBoolean(b)));
599     return dst;
600 }
601
602 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, double d)
603 {
604     emitOpcode(op_load);
605     instructions().append(dst->index());
606     instructions().append(addConstant(jsNumber(globalExec(), d)));
607     return dst;
608 }
609
610 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, JSValue* v)
611 {
612     emitOpcode(op_load);
613     instructions().append(dst->index());
614     instructions().append(addConstant(v));
615     return dst;
616 }
617
618 RegisterID* CodeGenerator::emitNullaryOp(OpcodeID opcode, RegisterID* dst)
619 {
620     emitOpcode(opcode);
621     instructions().append(dst->index());
622     return dst;
623 }
624
625 bool CodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting)
626 {
627     // Cases where we cannot optimise the lookup
628     if (property == propertyNames().arguments || !canOptimizeNonLocals()) {
629         stackDepth = 0;
630         index = missingSymbolMarker();
631         return false;
632     }
633
634     ScopeChainIterator iter = m_scopeChain->begin();
635     ScopeChainIterator end = m_scopeChain->end();
636     size_t depth = 0;
637
638     for (; iter != end; ++iter, ++depth) {
639         JSObject* currentScope = *iter;
640         if (!currentScope->isVariableObject())
641             break;
642         JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
643         SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.ustring().rep());
644
645         // Found the property
646         if (!entry.isNull()) {
647             if (entry.isReadOnly() && forWriting) {
648                 stackDepth = 0;
649                 index = missingSymbolMarker();
650                 return false;
651             }
652             stackDepth = depth;
653             index = entry.getIndex();
654             return true;
655         }
656         if (currentVariableObject->isDynamicScope())
657             break;
658     }
659
660     // Can't locate the property but we're able to avoid a few lookups
661     stackDepth = depth;
662     index = missingSymbolMarker();
663     return true;
664 }
665
666 RegisterID* CodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
667 {
668     size_t depth = 0;
669     int index = 0;
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));
675         return dst;
676     }
677
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);
685         return dst;
686     }
687
688     // Directly index the property lookup across multiple scopes.  Yay!
689     return emitGetScopedVar(dst, depth, index);
690 }
691
692 RegisterID* CodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index)
693 {
694     emitOpcode(op_get_scoped_var);
695     instructions().append(dst->index());
696     instructions().append(index);
697     instructions().append(depth);
698     return dst;
699 }
700
701 RegisterID* CodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value)
702 {
703     emitOpcode(op_put_scoped_var);
704     instructions().append(index);
705     instructions().append(depth);
706     instructions().append(value->index());
707     return value;
708 }
709
710 RegisterID* CodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property)
711 {
712     emitOpcode(op_resolve_base);
713     instructions().append(dst->index());
714     instructions().append(addConstant(property));
715     return dst;
716 }
717
718 RegisterID* CodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
719 {
720     emitOpcode(op_resolve_with_base);
721     instructions().append(baseDst->index());
722     instructions().append(propDst->index());
723     instructions().append(addConstant(property));
724     return baseDst;
725 }
726
727 RegisterID* CodeGenerator::emitResolveFunction(RegisterID* baseDst, RegisterID* funcDst, const Identifier& property)
728 {
729     emitOpcode(op_resolve_func);
730     instructions().append(baseDst->index());
731     instructions().append(funcDst->index());
732     instructions().append(addConstant(property));
733     return baseDst;
734 }
735
736 RegisterID* CodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
737 {
738     emitOpcode(op_get_by_id);
739     instructions().append(dst->index());
740     instructions().append(base->index());
741     instructions().append(addConstant(property));
742     return dst;
743 }
744
745 RegisterID* CodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
746 {
747     emitOpcode(op_put_by_id);
748     instructions().append(base->index());
749     instructions().append(addConstant(property));
750     instructions().append(value->index());
751     return value;
752 }
753
754 RegisterID* CodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
755 {
756     emitOpcode(op_put_getter);
757     instructions().append(base->index());
758     instructions().append(addConstant(property));
759     instructions().append(value->index());
760     return value;
761 }
762
763 RegisterID* CodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
764 {
765     emitOpcode(op_put_setter);
766     instructions().append(base->index());
767     instructions().append(addConstant(property));
768     instructions().append(value->index());
769     return value;
770 }
771
772 RegisterID* CodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
773 {
774     emitOpcode(op_del_by_id);
775     instructions().append(dst->index());
776     instructions().append(base->index());
777     instructions().append(addConstant(property));
778     return dst;
779 }
780
781 RegisterID* CodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
782 {
783     emitOpcode(op_get_by_val);
784     instructions().append(dst->index());
785     instructions().append(base->index());
786     instructions().append(property->index());
787     return dst;
788 }
789
790 RegisterID* CodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
791 {
792     emitOpcode(op_put_by_val);
793     instructions().append(base->index());
794     instructions().append(property->index());
795     instructions().append(value->index());
796     return value;
797 }
798
799 RegisterID* CodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
800 {
801     emitOpcode(op_del_by_val);
802     instructions().append(dst->index());
803     instructions().append(base->index());
804     instructions().append(property->index());
805     return dst;
806 }
807
808 RegisterID* CodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value)
809 {
810     emitOpcode(op_put_by_index);
811     instructions().append(base->index());
812     instructions().append(index);
813     instructions().append(value->index());
814     return value;
815 }
816
817 RegisterID* CodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements)
818 {
819     Vector<RefPtr<RegisterID>, 16> argv;
820     for (ElementNode* n = elements; n; n = n->next()) {
821         if (n->elision())
822             break;
823         argv.append(newTemporary());
824         emitNode(argv.last().get(), n->value());
825     }
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
830     return dst;
831 }
832
833 RegisterID* CodeGenerator::emitNewFunction(RegisterID* dst, FuncDeclNode* n)
834 {
835     emitOpcode(op_new_func);
836     instructions().append(dst->index());
837     instructions().append(addConstant(n));
838     return dst;
839 }
840
841 RegisterID* CodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
842 {
843     emitOpcode(op_new_regexp);
844     instructions().append(dst->index());
845     instructions().append(addRegExp(regExp));
846     return dst;
847 }
848
849
850 RegisterID* CodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
851 {
852     emitOpcode(op_new_func_exp);
853     instructions().append(r0->index());
854     instructions().append(addConstant(n));
855     return r0;
856 }
857
858 RegisterID* CodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
859 {
860     return emitCall(op_call, dst, func, base, argumentsNode, divot, startOffset, endOffset);
861 }
862
863 RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
864 {
865     return emitCall(op_call_eval, dst, func, base, argumentsNode, divot, startOffset, endOffset);
866 }
867
868 RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
869 {
870     ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
871     
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.
877
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());
882
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);
889     }
890
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
898     return dst;
899 }
900
901 RegisterID* CodeGenerator::emitUnaryNoDstOp(OpcodeID opcode, RegisterID* src)
902 {
903     emitOpcode(opcode);
904     instructions().append(src->index());
905     return src;
906 }
907
908 RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode* argumentsNode)
909 {
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
914     // is safe.
915
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());
920
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);
927     }
928
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
934     return dst;
935 }
936
937 RegisterID* CodeGenerator::emitPushScope(RegisterID* scope)
938 {
939     m_codeBlock->needsFullScopeChain = true;
940     ControlFlowContext context;
941     context.isFinallyBlock = false;
942     m_scopeContextStack.append(context);
943     m_dynamicScopeDepth++;
944
945     return emitUnaryNoDstOp(op_push_scope, scope);
946 }
947
948 void CodeGenerator::emitPopScope()
949 {
950     ASSERT(m_scopeContextStack.size());
951     ASSERT(!m_scopeContextStack.last().isFinallyBlock);
952
953     emitOpcode(op_pop_scope);
954
955     m_scopeContextStack.removeLast();
956     m_dynamicScopeDepth--;
957 }
958
959 void CodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine)
960 {
961     if (!m_shouldEmitDebugHooks)
962         return;
963     emitOpcode(op_debug);
964     instructions().append(debugHookID);
965     instructions().append(firstLine);
966     instructions().append(lastLine);
967 }
968
969 void CodeGenerator::pushFinallyContext(LabelID* target, RegisterID* retAddrDst)
970 {
971     ControlFlowContext scope;
972     scope.isFinallyBlock = true;
973     FinallyContext context = { target, retAddrDst };
974     scope.finallyContext = context;
975     m_scopeContextStack.append(scope);
976     m_finallyDepth++;
977 }
978
979 void CodeGenerator::popFinallyContext()
980 {
981     ASSERT(m_scopeContextStack.size());
982     ASSERT(m_scopeContextStack.last().isFinallyBlock);
983     ASSERT(m_finallyDepth > 0);
984     m_scopeContextStack.removeLast();
985     m_finallyDepth--;
986 }
987
988 void CodeGenerator::pushJumpContext(LabelStack* labels, LabelID* continueTarget, LabelID* breakTarget, bool isValidUnlabeledBreakTarget)
989 {
990     JumpContext context = { labels, continueTarget, breakTarget, scopeDepth(), isValidUnlabeledBreakTarget };
991     m_jumpContextStack.append(context);
992     if (continueTarget)
993         m_continueDepth++;
994 }
995
996 void CodeGenerator::popJumpContext()
997 {
998     ASSERT(m_jumpContextStack.size());
999     if (m_jumpContextStack.last().continueTarget)
1000         m_continueDepth--;
1001     m_jumpContextStack.removeLast();
1002 }
1003
1004 JumpContext* CodeGenerator::jumpContextForContinue(const Identifier& label)
1005 {
1006     if(!m_jumpContextStack.size())
1007         return 0;
1008
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)
1013                 return scope;
1014         }
1015         return 0;
1016     }
1017
1018     for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1019         JumpContext* scope = &m_jumpContextStack[i];
1020         if (scope->labels->contains(label))
1021             return scope;
1022     }
1023     return 0;
1024 }
1025
1026 JumpContext* CodeGenerator::jumpContextForBreak(const Identifier& label)
1027 {
1028     if(!m_jumpContextStack.size())
1029         return 0;
1030
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)
1035                 return scope;
1036         }
1037         return 0;
1038     }
1039
1040     for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1041         JumpContext* scope = &m_jumpContextStack[i];
1042         if (scope->labels->contains(label))
1043             return scope;
1044     }
1045     return 0;
1046 }
1047
1048 PassRefPtr<LabelID> CodeGenerator::emitComplexJumpScopes(LabelID* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope)
1049 {
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)
1056                 break;
1057             ++nNormalScopes;
1058             --topScope;
1059         }
1060
1061         if (nNormalScopes) {
1062             // We need to remove a number of dynamic scopes to get to the next
1063             // finally block
1064             emitOpcode(op_jmp_scopes);
1065             instructions().append(nNormalScopes);
1066
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()));
1071                 return target;
1072             }
1073
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());
1079         }
1080
1081         // To get here there must be at least one finally block present
1082         do {
1083             ASSERT(topScope->isFinallyBlock);
1084             emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr);
1085             --topScope;
1086             if (!topScope->isFinallyBlock)
1087                 break;
1088         } while (topScope > bottomScope);
1089     }
1090     return emitJump(target);
1091 }
1092
1093 PassRefPtr<LabelID> CodeGenerator::emitJumpScopes(LabelID* target, int targetScopeDepth)
1094 {
1095     ASSERT(scopeDepth() - targetScopeDepth >= 0);
1096     ASSERT(target->isForwardLabel());
1097
1098     size_t scopeDelta = scopeDepth() - targetScopeDepth;
1099     ASSERT(scopeDelta <= m_scopeContextStack.size());
1100     if (!scopeDelta)
1101         return emitJump(target);
1102
1103     if (m_finallyDepth)
1104         return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta);
1105
1106     emitOpcode(op_jmp_scopes);
1107     instructions().append(scopeDelta);
1108     instructions().append(target->offsetFrom(instructions().size()));
1109     return target;
1110 }
1111
1112 RegisterID* CodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* iter, LabelID* target)
1113 {
1114     emitOpcode(op_next_pname);
1115     instructions().append(dst->index());
1116     instructions().append(iter->index());
1117     instructions().append(target->offsetFrom(instructions().size()));
1118     return dst;
1119 }
1120
1121 RegisterID* CodeGenerator::emitCatch(RegisterID* targetRegister, LabelID* start, LabelID* end)
1122 {
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;
1128 }
1129
1130 RegisterID* CodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValue* message)
1131 {
1132     emitOpcode(op_new_error);
1133     instructions().append(dst->index());
1134     instructions().append(static_cast<int>(type));
1135     instructions().append(addConstant(message));
1136     return dst;
1137 }
1138
1139 PassRefPtr<LabelID> CodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, LabelID* finally)
1140 {
1141     emitOpcode(op_jsr);
1142     instructions().append(retAddrDst->index());
1143     instructions().append(finally->offsetFrom(instructions().size()));
1144     return finally;
1145 }
1146
1147 void CodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc)
1148 {
1149     emitOpcode(op_sret);
1150     instructions().append(retAddrSrc->index());
1151 }
1152
1153 void CodeGenerator::emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value)
1154 {
1155     m_codeBlock->needsFullScopeChain = true;
1156     ControlFlowContext context;
1157     context.isFinallyBlock = false;
1158     m_scopeContextStack.append(context);
1159     m_dynamicScopeDepth++;
1160     
1161     emitOpcode(op_push_new_scope);
1162     instructions().append(dst->index());
1163     instructions().append(addConstant(property));
1164     instructions().append(value->index());
1165 }
1166
1167 void CodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type)
1168 {
1169     SwitchInfo info = { instructions().size(), type };
1170     switch (type) {
1171         case SwitchInfo::SwitchImmediate:
1172             emitOpcode(op_switch_imm);
1173             break;
1174         case SwitchInfo::SwitchCharacter:
1175             emitOpcode(op_switch_char);
1176             break;
1177         case SwitchInfo::SwitchString:
1178             emitOpcode(op_switch_string);
1179             break;
1180         default:
1181             ASSERT_NOT_REACHED();
1182     }
1183
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);
1188 }
1189
1190 static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max)
1191 {
1192     UNUSED_PARAM(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);
1198     ASSERT(key >= min);
1199     ASSERT(key <= max);
1200     return key - min;
1201 }
1202
1203 static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1204 {
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)); 
1213     }
1214 }
1215
1216 static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max)
1217 {
1218     UNUSED_PARAM(max);
1219     ASSERT(node->isString());
1220     UString::Rep* clause = static_cast<StringNode*>(node)->value().rep();
1221     ASSERT(clause->size() == 1);
1222     
1223     int32_t key = clause->data()[0];
1224     ASSERT(key >= min);
1225     ASSERT(key <= max);
1226     return key - min;
1227 }
1228
1229 static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1230 {
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)); 
1239     }
1240 }
1241
1242 static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes)
1243 {
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());
1248         
1249         ASSERT(nodes[i]->isString());
1250         UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().rep();
1251         jumpTable.add(clause, labels[i]->offsetFrom(switchAddress)); 
1252     }
1253 }
1254
1255 void CodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, LabelID* defaultLabel, int32_t min, int32_t max)
1256 {
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);
1262
1263         m_codeBlock->immediateSwitchJumpTables.append(SimpleJumpTable());
1264         SimpleJumpTable& jumpTable = m_codeBlock->immediateSwitchJumpTables.last();
1265
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);
1270         
1271         m_codeBlock->characterSwitchJumpTables.append(SimpleJumpTable());
1272         SimpleJumpTable& jumpTable = m_codeBlock->characterSwitchJumpTables.last();
1273
1274         prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes, min, max);
1275     } else {
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);
1279
1280         m_codeBlock->stringSwitchJumpTables.append(StringJumpTable());
1281         StringJumpTable& jumpTable = m_codeBlock->stringSwitchJumpTables.last();
1282
1283         prepareJumpTableForStringSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes);
1284     }
1285 }
1286
1287 } // namespace KJS