2008-08-06 Cameron Zwarich <cwzwarich@webkit.org>
[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->numConstants = programNode->neededConstants();
206     m_codeBlock->numVars = 1; // Allocate space for "this"
207
208     JSGlobalObject* globalObject = scopeChain.globalObject();
209     ExecState* exec = globalObject->globalExec();
210     RegisterFile* registerFile = &exec->globalData().machine->registerFile();
211     
212     // Shift register indexes in generated code to elide registers allocated by intermediate stack frames.
213     m_globalVarStorageOffset = -1 - RegisterFile::CallFrameHeaderSize - registerFile->size();
214
215     // Add previously defined symbols to bookkeeping.
216     m_locals.resize(symbolTable->size());
217     SymbolTable::iterator end = symbolTable->end();
218     for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
219         m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex() + m_globalVarStorageOffset);
220
221     bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();
222     if (canOptimizeNewGlobals) {
223         // Shift new symbols so they get stored prior to existing symbols.
224         m_nextVar -= symbolTable->size();
225
226         for (size_t i = 0; i < functionStack.size(); ++i) {
227             FuncDeclNode* funcDecl = functionStack[i].get();
228             globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property.
229             emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);
230         }
231
232         for (size_t i = 0; i < varStack.size(); ++i) {
233             if (!globalObject->hasProperty(exec, varStack[i].first))
234                 emitLoad(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant), jsUndefined());
235         }
236     } else {
237         for (size_t i = 0; i < functionStack.size(); ++i) {
238             FuncDeclNode* funcDecl = functionStack[i].get();
239             globalObject->putWithAttributes(exec, funcDecl->m_ident, funcDecl->makeFunction(exec, scopeChain.node()), DontDelete);
240         }
241         for (size_t i = 0; i < varStack.size(); ++i) {
242             if (globalObject->hasProperty(exec, varStack[i].first))
243                 continue;
244             int attributes = DontDelete;
245             if (varStack[i].second & DeclarationStacks::IsConstant)
246                 attributes |= ReadOnly;
247             globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes);
248         }
249     }
250 }
251
252 CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock)
253     : m_shouldEmitDebugHooks(!!debugger)
254     , m_scopeChain(&scopeChain)
255     , m_symbolTable(symbolTable)
256     , m_scopeNode(functionBody)
257     , m_codeBlock(codeBlock)
258     , m_finallyDepth(0)
259     , m_dynamicScopeDepth(0)
260     , m_codeType(FunctionCode)
261     , m_continueDepth(0)
262     , m_nextVar(-1)
263     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
264     , m_lastOpcodeID(op_end)
265 {
266     m_codeBlock->numConstants = functionBody->neededConstants();
267
268     const Node::FunctionStack& functionStack = functionBody->functionStack();
269     for (size_t i = 0; i < functionStack.size(); ++i) {
270         FuncDeclNode* funcDecl = functionStack[i].get();
271         const Identifier& ident = funcDecl->m_ident;
272
273         m_functions.add(ident.ustring().rep());
274         emitNewFunction(addVar(ident, false), funcDecl);
275     }
276
277     const Node::VarStack& varStack = functionBody->varStack();
278     for (size_t i = 0; i < varStack.size(); ++i) {
279         const Identifier& ident = varStack[i].first;
280         if (ident == propertyNames().arguments)
281             continue;
282         addVar(ident, varStack[i].second & DeclarationStacks::IsConstant);
283     }
284
285     Vector<Identifier>& parameters = functionBody->parameters();
286     m_nextParameter = m_nextVar - parameters.size(); // parameters are allocated prior to vars
287     m_locals.resize(localsIndex(m_nextParameter) + 1); // localsIndex of 0 => m_locals size of 1
288
289     // Add "this" as a parameter
290     m_thisRegister.setIndex(m_nextParameter);
291     ++m_nextParameter;
292     ++m_codeBlock->numParameters;
293     
294     for (size_t i = 0; i < parameters.size(); ++i)
295         addParameter(parameters[i]);
296 }
297
298 CodeGenerator::CodeGenerator(EvalNode* evalNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock)
299     : m_shouldEmitDebugHooks(!!debugger)
300     , m_scopeChain(&scopeChain)
301     , m_symbolTable(symbolTable)
302     , m_scopeNode(evalNode)
303     , m_codeBlock(codeBlock)
304     , m_thisRegister(RegisterFile::ProgramCodeThisRegister)
305     , m_finallyDepth(0)
306     , m_dynamicScopeDepth(0)
307     , m_codeType(EvalCode)
308     , m_continueDepth(0)
309     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
310     , m_lastOpcodeID(op_end)
311 {
312     m_codeBlock->numConstants = evalNode->neededConstants();
313     m_codeBlock->numVars = 1; // Allocate space for "this"
314 }
315
316 CodeGenerator::~CodeGenerator()
317 {
318 }
319
320 RegisterID* CodeGenerator::addParameter(const Identifier& ident)
321 {
322     // Parameters overwrite var declarations, but not function declarations,
323     // in the symbol table.
324     RegisterID* result = 0;
325     UString::Rep* rep = ident.ustring().rep();
326     if (!m_functions.contains(rep)) {
327         symbolTable().set(rep, m_nextParameter);
328         m_locals[localsIndex(m_nextParameter)].setIndex(m_nextParameter);
329         result = &(m_locals[localsIndex(m_nextParameter)]);
330     }
331
332     // To maintain the calling convention, we have to allocate unique space for
333     // each parameter, even if the parameter doesn't make it into the symbol table.
334     ++m_nextParameter;
335     ++m_codeBlock->numParameters;
336     return result;
337 }
338
339 RegisterID* CodeGenerator::registerForLocal(const Identifier& ident)
340 {
341     if (m_codeType == FunctionCode && ident == propertyNames().arguments)
342         m_codeBlock->needsFullScopeChain = true;
343
344     if (ident == propertyNames().thisIdentifier)
345         return &m_thisRegister;
346
347     if (!shouldOptimizeLocals())
348         return 0;
349
350     SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
351     if (entry.isNull())
352         return 0;
353
354     return &m_locals[localsIndex(entry.getIndex())];
355 }
356
357 RegisterID* CodeGenerator::registerForLocalConstInit(const Identifier& ident)
358 {
359     if (m_codeType == EvalCode)
360         return 0;
361
362     SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
363     ASSERT(!entry.isNull());
364
365     return &m_locals[localsIndex(entry.getIndex())];
366 }
367
368 bool CodeGenerator::isLocal(const Identifier& ident)
369 {
370     if (ident == propertyNames().thisIdentifier)
371         return true;
372     
373     return shouldOptimizeLocals() && symbolTable().contains(ident.ustring().rep());
374 }
375
376 bool CodeGenerator::isLocalConstant(const Identifier& ident)
377 {
378     return symbolTable().get(ident.ustring().rep()).isReadOnly();
379 }
380
381 RegisterID* CodeGenerator::newTemporary()
382 {
383     // Reclaim free register IDs.
384     while (m_temporaries.size() && !m_temporaries.last().refCount())
385         m_temporaries.removeLast();
386
387     // Allocate new register ID.
388     m_temporaries.append(m_temporaries.size() + m_codeBlock->numConstants);
389     m_codeBlock->numTemporaries = max<int>(m_codeBlock->numTemporaries, m_temporaries.size());
390     return &m_temporaries.last();
391 }
392
393 RegisterID* CodeGenerator::highestUsedRegister()
394 {
395     while (m_temporaries.size() < static_cast<unsigned>(m_codeBlock->numTemporaries))
396         m_temporaries.append(m_temporaries.size());
397     return &m_temporaries.last();
398 }
399
400 PassRefPtr<LabelID> CodeGenerator::newLabel()
401 {
402     // Reclaim free label IDs.
403     while (m_labels.size() && !m_labels.last().refCount())
404         m_labels.removeLast();
405
406     // Allocate new label ID.
407     m_labels.append(m_codeBlock);
408     return &m_labels.last();
409 }
410
411 PassRefPtr<LabelID> CodeGenerator::emitLabel(LabelID* l0)
412 {
413     l0->setLocation(instructions().size());
414     
415     // This disables peephole optimizations when an instruction is a jump target
416     m_lastOpcodeID = op_end;
417     
418     return l0;
419 }
420
421 void CodeGenerator::emitOpcode(OpcodeID opcodeID)
422 {
423     instructions().append(globalData()->machine->getOpcode(opcodeID));
424     m_lastOpcodeID = opcodeID;
425 }
426
427 void CodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
428 {
429     ASSERT(instructions().size() >= 4);
430     size_t size = instructions().size();
431     dstIndex = instructions().at(size - 3).u.operand;
432     src1Index = instructions().at(size - 2).u.operand;
433     src2Index = instructions().at(size - 1).u.operand;
434 }
435
436 void ALWAYS_INLINE CodeGenerator::rewindBinaryOp()
437 {
438     ASSERT(instructions().size() >= 4);
439     instructions().shrink(instructions().size() - 4);
440 }
441
442 PassRefPtr<LabelID> CodeGenerator::emitJump(LabelID* target)
443 {
444     emitOpcode(target->isForwardLabel() ? op_jmp : op_loop);
445     instructions().append(target->offsetFrom(instructions().size()));
446     return target;
447 }
448
449 PassRefPtr<LabelID> CodeGenerator::emitJumpIfTrue(RegisterID* cond, LabelID* target)
450 {
451     if (m_lastOpcodeID == op_less) {
452         int dstIndex;
453         int src1Index;
454         int src2Index;
455
456         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
457
458         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
459             rewindBinaryOp();
460             emitOpcode(target->isForwardLabel() ? op_jless : op_loop_if_less);
461             instructions().append(src1Index);
462             instructions().append(src2Index);
463             instructions().append(target->offsetFrom(instructions().size()));
464             return target;
465         }
466     }
467
468     emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true);
469     instructions().append(cond->index());
470     instructions().append(target->offsetFrom(instructions().size()));
471     return target;
472 }
473
474 PassRefPtr<LabelID> CodeGenerator::emitJumpIfFalse(RegisterID* cond, LabelID* target)
475 {
476     ASSERT(target->isForwardLabel());
477
478     if (m_lastOpcodeID == op_less) {
479         int dstIndex;
480         int src1Index;
481         int src2Index;
482
483         retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
484
485         if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
486             rewindBinaryOp();
487             emitOpcode(op_jnless);
488             instructions().append(src1Index);
489             instructions().append(src2Index);
490             instructions().append(target->offsetFrom(instructions().size()));
491             return target;
492         }
493     }
494
495     emitOpcode(op_jfalse);
496     instructions().append(cond->index());
497     instructions().append(target->offsetFrom(instructions().size()));
498     return target;
499 }
500
501 unsigned CodeGenerator::addConstant(FuncDeclNode* n)
502 {
503     // No need to explicitly unique function body nodes -- they're unique already.
504     int index = m_codeBlock->functions.size();
505     m_codeBlock->functions.append(n);
506     return index;
507 }
508
509 unsigned CodeGenerator::addConstant(FuncExprNode* n)
510 {
511     // No need to explicitly unique function expression nodes -- they're unique already.
512     int index = m_codeBlock->functionExpressions.size();
513     m_codeBlock->functionExpressions.append(n);
514     return index;
515 }
516
517 unsigned CodeGenerator::addConstant(const Identifier& ident)
518 {
519     UString::Rep* rep = ident.ustring().rep();
520     pair<IdentifierMap::iterator, bool> result = m_identifierMap.add(rep, m_codeBlock->identifiers.size());
521     if (result.second) // new entry
522         m_codeBlock->identifiers.append(Identifier(m_globalData, rep));
523
524     return result.first->second;
525 }
526
527 RegisterID* CodeGenerator::addConstant(JSValue* v)
528 {
529     pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(v, m_codeBlock->constantRegisters.size());
530     if (result.second) {
531         m_constants.append(m_codeBlock->constantRegisters.size());
532         m_constants.last().makeConstant();
533         m_codeBlock->constantRegisters.append(v);
534         ASSERT(m_codeBlock->constantRegisters.size() <= (unsigned) m_codeBlock->numConstants);
535         return &m_constants.last();
536     }
537
538     return &m_constants[result.first->second];
539 }
540
541 unsigned CodeGenerator::addUnexpectedConstant(JSValue* v)
542 {
543     int index = m_codeBlock->regexps.size();
544     m_codeBlock->unexpectedConstants.append(v);
545     return index;
546 }
547
548 unsigned CodeGenerator::addRegExp(RegExp* r)
549 {
550     int index = m_codeBlock->regexps.size();
551     m_codeBlock->regexps.append(r);
552     return index;
553 }
554
555 RegisterID* CodeGenerator::emitMove(RegisterID* dst, RegisterID* src)
556 {
557     emitOpcode(op_mov);
558     instructions().append(dst->index());
559     instructions().append(src->index());
560     return dst;
561 }
562
563 RegisterID* CodeGenerator::emitUnaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src)
564 {
565     emitOpcode(opcode);
566     instructions().append(dst->index());
567     instructions().append(src->index());
568     return dst;
569 }
570
571 RegisterID* CodeGenerator::emitPreInc(RegisterID* srcDst)
572 {
573     emitOpcode(op_pre_inc);
574     instructions().append(srcDst->index());
575     return srcDst;
576 }
577
578 RegisterID* CodeGenerator::emitPreDec(RegisterID* srcDst)
579 {
580     emitOpcode(op_pre_dec);
581     instructions().append(srcDst->index());
582     return srcDst;
583 }
584
585 RegisterID* CodeGenerator::emitPostInc(RegisterID* dst, RegisterID* srcDst)
586 {
587     emitOpcode(op_post_inc);
588     instructions().append(dst->index());
589     instructions().append(srcDst->index());
590     return dst;
591 }
592
593 RegisterID* CodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst)
594 {
595     emitOpcode(op_post_dec);
596     instructions().append(dst->index());
597     instructions().append(srcDst->index());
598     return dst;
599 }
600
601 RegisterID* CodeGenerator::emitBinaryOp(OpcodeID opcode, RegisterID* dst, RegisterID* src1, RegisterID* src2)
602 {
603     emitOpcode(opcode);
604     instructions().append(dst->index());
605     instructions().append(src1->index());
606     instructions().append(src2->index());
607     return dst;
608 }
609
610 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, bool b)
611 {
612     return emitLoad(dst, jsBoolean(b));
613 }
614
615 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, double d)
616 {
617     return emitLoad(dst, jsNumber(globalExec(), d));
618 }
619
620 RegisterID* CodeGenerator::emitLoad(RegisterID* dst, JSValue* v)
621 {
622     RegisterID* constantID = addConstant(v);
623     if (dst)
624         return emitMove(dst, constantID);
625     return constantID;
626 }
627
628 RegisterID* CodeGenerator::emitUnexpectedLoad(RegisterID* dst, bool b)
629 {
630     emitOpcode(op_unexpected_load);
631     instructions().append(dst->index());
632     instructions().append(addUnexpectedConstant(jsBoolean(b)));
633     return dst;
634 }
635
636 RegisterID* CodeGenerator::emitNullaryOp(OpcodeID opcode, RegisterID* dst)
637 {
638     emitOpcode(opcode);
639     instructions().append(dst->index());
640     return dst;
641 }
642
643 bool CodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting)
644 {
645     // Cases where we cannot optimise the lookup
646     if (property == propertyNames().arguments || !canOptimizeNonLocals()) {
647         stackDepth = 0;
648         index = missingSymbolMarker();
649         return false;
650     }
651
652     ScopeChainIterator iter = m_scopeChain->begin();
653     ScopeChainIterator end = m_scopeChain->end();
654     size_t depth = 0;
655
656     for (; iter != end; ++iter, ++depth) {
657         JSObject* currentScope = *iter;
658         if (!currentScope->isVariableObject())
659             break;
660         JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope);
661         SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.ustring().rep());
662
663         // Found the property
664         if (!entry.isNull()) {
665             if (entry.isReadOnly() && forWriting) {
666                 stackDepth = 0;
667                 index = missingSymbolMarker();
668                 return false;
669             }
670             stackDepth = depth;
671             index = entry.getIndex();
672             return true;
673         }
674         if (currentVariableObject->isDynamicScope())
675             break;
676     }
677
678     // Can't locate the property but we're able to avoid a few lookups
679     stackDepth = depth;
680     index = missingSymbolMarker();
681     return true;
682 }
683
684 RegisterID* CodeGenerator::emitResolve(RegisterID* dst, const Identifier& property)
685 {
686     size_t depth = 0;
687     int index = 0;
688     if (!findScopedProperty(property, index, depth, false)) {
689         // We can't optimise at all :-(
690         emitOpcode(op_resolve);
691         instructions().append(dst->index());
692         instructions().append(addConstant(property));
693         return dst;
694     }
695
696     if (index == missingSymbolMarker()) {
697         // In this case we are at least able to drop a few scope chains from the
698         // lookup chain, although we still need to hash from then on.
699         emitOpcode(op_resolve_skip);
700         instructions().append(dst->index());
701         instructions().append(addConstant(property));
702         instructions().append(depth);
703         return dst;
704     }
705
706     // Directly index the property lookup across multiple scopes.  Yay!
707     return emitGetScopedVar(dst, depth, index);
708 }
709
710 RegisterID* CodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index)
711 {
712     emitOpcode(op_get_scoped_var);
713     instructions().append(dst->index());
714     instructions().append(index);
715     instructions().append(depth);
716     return dst;
717 }
718
719 RegisterID* CodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value)
720 {
721     emitOpcode(op_put_scoped_var);
722     instructions().append(index);
723     instructions().append(depth);
724     instructions().append(value->index());
725     return value;
726 }
727
728 RegisterID* CodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property)
729 {
730     emitOpcode(op_resolve_base);
731     instructions().append(dst->index());
732     instructions().append(addConstant(property));
733     return dst;
734 }
735
736 RegisterID* CodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property)
737 {
738     emitOpcode(op_resolve_with_base);
739     instructions().append(baseDst->index());
740     instructions().append(propDst->index());
741     instructions().append(addConstant(property));
742     return baseDst;
743 }
744
745 RegisterID* CodeGenerator::emitResolveFunction(RegisterID* baseDst, RegisterID* funcDst, const Identifier& property)
746 {
747     emitOpcode(op_resolve_func);
748     instructions().append(baseDst->index());
749     instructions().append(funcDst->index());
750     instructions().append(addConstant(property));
751     return baseDst;
752 }
753
754 RegisterID* CodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property)
755 {
756     emitOpcode(op_get_by_id);
757     instructions().append(dst->index());
758     instructions().append(base->index());
759     instructions().append(addConstant(property));
760     return dst;
761 }
762
763 RegisterID* CodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value)
764 {
765     emitOpcode(op_put_by_id);
766     instructions().append(base->index());
767     instructions().append(addConstant(property));
768     instructions().append(value->index());
769     return value;
770 }
771
772 RegisterID* CodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value)
773 {
774     emitOpcode(op_put_getter);
775     instructions().append(base->index());
776     instructions().append(addConstant(property));
777     instructions().append(value->index());
778     return value;
779 }
780
781 RegisterID* CodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value)
782 {
783     emitOpcode(op_put_setter);
784     instructions().append(base->index());
785     instructions().append(addConstant(property));
786     instructions().append(value->index());
787     return value;
788 }
789
790 RegisterID* CodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property)
791 {
792     emitOpcode(op_del_by_id);
793     instructions().append(dst->index());
794     instructions().append(base->index());
795     instructions().append(addConstant(property));
796     return dst;
797 }
798
799 RegisterID* CodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
800 {
801     emitOpcode(op_get_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::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
809 {
810     emitOpcode(op_put_by_val);
811     instructions().append(base->index());
812     instructions().append(property->index());
813     instructions().append(value->index());
814     return value;
815 }
816
817 RegisterID* CodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
818 {
819     emitOpcode(op_del_by_val);
820     instructions().append(dst->index());
821     instructions().append(base->index());
822     instructions().append(property->index());
823     return dst;
824 }
825
826 RegisterID* CodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value)
827 {
828     emitOpcode(op_put_by_index);
829     instructions().append(base->index());
830     instructions().append(index);
831     instructions().append(value->index());
832     return value;
833 }
834
835 RegisterID* CodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements)
836 {
837     Vector<RefPtr<RegisterID>, 16> argv;
838     for (ElementNode* n = elements; n; n = n->next()) {
839         if (n->elision())
840             break;
841         argv.append(newTemporary());
842         emitNode(argv.last().get(), n->value());
843     }
844     emitOpcode(op_new_array);
845     instructions().append(dst->index());
846     instructions().append(argv.size() ? argv[0]->index() : 0); // argv
847     instructions().append(argv.size()); // argc
848     return dst;
849 }
850
851 RegisterID* CodeGenerator::emitNewFunction(RegisterID* dst, FuncDeclNode* n)
852 {
853     emitOpcode(op_new_func);
854     instructions().append(dst->index());
855     instructions().append(addConstant(n));
856     return dst;
857 }
858
859 RegisterID* CodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp)
860 {
861     emitOpcode(op_new_regexp);
862     instructions().append(dst->index());
863     instructions().append(addRegExp(regExp));
864     return dst;
865 }
866
867
868 RegisterID* CodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n)
869 {
870     emitOpcode(op_new_func_exp);
871     instructions().append(r0->index());
872     instructions().append(addConstant(n));
873     return r0;
874 }
875
876 RegisterID* CodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
877 {
878     return emitCall(op_call, dst, func, base, argumentsNode, divot, startOffset, endOffset);
879 }
880
881 RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
882 {
883     return emitCall(op_call_eval, dst, func, base, argumentsNode, divot, startOffset, endOffset);
884 }
885
886 RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
887 {
888     ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
889     
890     // Ordinarily, we might ref "func" and "base", to avoid allocating new
891     // temporaries in the same registers. In this case, though, we actually
892     // want the call frame we allocate to overlap "func" and "base", if they're
893     // not otherwise referenced. op_call will read "func" and "base" before
894     // writing out the call frame, so this is safe.
895
896     // Reserve space for call frame.
897     Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
898     for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
899         callFrame.append(newTemporary());
900
901     // Generate code for arguments.
902     Vector<RefPtr<RegisterID>, 16> argv;
903     argv.append(newTemporary()); // reserve space for "this"
904     for (ArgumentListNode* n = argumentsNode->m_listNode.get(); n; n = n->m_next.get()) {
905         argv.append(newTemporary());
906         emitNode(argv.last().get(), n);
907     }
908
909     emitExpressionInfo(divot, startOffset, endOffset);
910     emitOpcode(opcodeID);
911     instructions().append(dst->index());
912     instructions().append(func->index());
913     instructions().append(base ? base->index() : missingThisObjectMarker()); // We encode the "this" value in the instruction stream, to avoid an explicit instruction for copying or loading it.
914     instructions().append(argv.size() ? argv[0]->index() : m_temporaries.size()); // argv
915     instructions().append(argv.size()); // argc
916     return dst;
917 }
918
919 RegisterID* CodeGenerator::emitUnaryNoDstOp(OpcodeID opcode, RegisterID* src)
920 {
921     emitOpcode(opcode);
922     instructions().append(src->index());
923     return src;
924 }
925
926 RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode* argumentsNode)
927 {
928     // Ordinarily, we might ref "func", to avoid allocating a new temporary in
929     // the same register. In this case, though, we actually want the call
930     // frame we allocate to overlap "func", if it's not otherwise referenced.
931     // op_construct will read "func" before writing out the call frame, so this
932     // is safe.
933
934     // Reserve space for call frame.
935     Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
936     for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
937         callFrame.append(newTemporary());
938
939     // Generate code for arguments.
940     Vector<RefPtr<RegisterID>, 16> argv;
941     argv.append(newTemporary()); // reserve space for "this"
942     for (ArgumentListNode* n = argumentsNode ? argumentsNode->m_listNode.get() : 0; n; n = n->m_next.get()) {
943         argv.append(newTemporary());
944         emitNode(argv.last().get(), n);
945     }
946
947     emitOpcode(op_construct);
948     instructions().append(dst->index());
949     instructions().append(func->index());
950     instructions().append(argv.size() ? argv[0]->index() : m_temporaries.size()); // argv
951     instructions().append(argv.size()); // argc
952     return dst;
953 }
954
955 RegisterID* CodeGenerator::emitPushScope(RegisterID* scope)
956 {
957     m_codeBlock->needsFullScopeChain = true;
958     ControlFlowContext context;
959     context.isFinallyBlock = false;
960     m_scopeContextStack.append(context);
961     m_dynamicScopeDepth++;
962
963     return emitUnaryNoDstOp(op_push_scope, scope);
964 }
965
966 void CodeGenerator::emitPopScope()
967 {
968     ASSERT(m_scopeContextStack.size());
969     ASSERT(!m_scopeContextStack.last().isFinallyBlock);
970
971     emitOpcode(op_pop_scope);
972
973     m_scopeContextStack.removeLast();
974     m_dynamicScopeDepth--;
975 }
976
977 void CodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine)
978 {
979     if (!m_shouldEmitDebugHooks)
980         return;
981     emitOpcode(op_debug);
982     instructions().append(debugHookID);
983     instructions().append(firstLine);
984     instructions().append(lastLine);
985 }
986
987 void CodeGenerator::pushFinallyContext(LabelID* target, RegisterID* retAddrDst)
988 {
989     ControlFlowContext scope;
990     scope.isFinallyBlock = true;
991     FinallyContext context = { target, retAddrDst };
992     scope.finallyContext = context;
993     m_scopeContextStack.append(scope);
994     m_finallyDepth++;
995 }
996
997 void CodeGenerator::popFinallyContext()
998 {
999     ASSERT(m_scopeContextStack.size());
1000     ASSERT(m_scopeContextStack.last().isFinallyBlock);
1001     ASSERT(m_finallyDepth > 0);
1002     m_scopeContextStack.removeLast();
1003     m_finallyDepth--;
1004 }
1005
1006 void CodeGenerator::pushJumpContext(LabelStack* labels, LabelID* continueTarget, LabelID* breakTarget, bool isValidUnlabeledBreakTarget)
1007 {
1008     JumpContext context = { labels, continueTarget, breakTarget, scopeDepth(), isValidUnlabeledBreakTarget };
1009     m_jumpContextStack.append(context);
1010     if (continueTarget)
1011         m_continueDepth++;
1012 }
1013
1014 void CodeGenerator::popJumpContext()
1015 {
1016     ASSERT(m_jumpContextStack.size());
1017     if (m_jumpContextStack.last().continueTarget)
1018         m_continueDepth--;
1019     m_jumpContextStack.removeLast();
1020 }
1021
1022 JumpContext* CodeGenerator::jumpContextForContinue(const Identifier& label)
1023 {
1024     if(!m_jumpContextStack.size())
1025         return 0;
1026
1027     if (label.isEmpty()) {
1028         for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1029             JumpContext* scope = &m_jumpContextStack[i];
1030             if (scope->continueTarget)
1031                 return scope;
1032         }
1033         return 0;
1034     }
1035
1036     for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1037         JumpContext* scope = &m_jumpContextStack[i];
1038         if (scope->labels->contains(label))
1039             return scope;
1040     }
1041     return 0;
1042 }
1043
1044 JumpContext* CodeGenerator::jumpContextForBreak(const Identifier& label)
1045 {
1046     if(!m_jumpContextStack.size())
1047         return 0;
1048
1049     if (label.isEmpty()) {
1050         for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1051             JumpContext* scope = &m_jumpContextStack[i];
1052             if (scope->isValidUnlabeledBreakTarget)
1053                 return scope;
1054         }
1055         return 0;
1056     }
1057
1058     for (int i = m_jumpContextStack.size() - 1; i >= 0; i--) {
1059         JumpContext* scope = &m_jumpContextStack[i];
1060         if (scope->labels->contains(label))
1061             return scope;
1062     }
1063     return 0;
1064 }
1065
1066 PassRefPtr<LabelID> CodeGenerator::emitComplexJumpScopes(LabelID* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope)
1067 {
1068     while (topScope > bottomScope) {
1069         // First we count the number of dynamic scopes we need to remove to get
1070         // to a finally block.
1071         int nNormalScopes = 0;
1072         while (topScope > bottomScope) {
1073             if (topScope->isFinallyBlock)
1074                 break;
1075             ++nNormalScopes;
1076             --topScope;
1077         }
1078
1079         if (nNormalScopes) {
1080             // We need to remove a number of dynamic scopes to get to the next
1081             // finally block
1082             emitOpcode(op_jmp_scopes);
1083             instructions().append(nNormalScopes);
1084
1085             // If topScope == bottomScope then there isn't actually a finally block
1086             // left to emit, so make the jmp_scopes jump directly to the target label
1087             if (topScope == bottomScope) {
1088                 instructions().append(target->offsetFrom(instructions().size()));
1089                 return target;
1090             }
1091
1092             // Otherwise we just use jmp_scopes to pop a group of scopes and go
1093             // to the next instruction
1094             RefPtr<LabelID> nextInsn = newLabel();
1095             instructions().append(nextInsn->offsetFrom(instructions().size()));
1096             emitLabel(nextInsn.get());
1097         }
1098
1099         // To get here there must be at least one finally block present
1100         do {
1101             ASSERT(topScope->isFinallyBlock);
1102             emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr);
1103             --topScope;
1104             if (!topScope->isFinallyBlock)
1105                 break;
1106         } while (topScope > bottomScope);
1107     }
1108     return emitJump(target);
1109 }
1110
1111 PassRefPtr<LabelID> CodeGenerator::emitJumpScopes(LabelID* target, int targetScopeDepth)
1112 {
1113     ASSERT(scopeDepth() - targetScopeDepth >= 0);
1114     ASSERT(target->isForwardLabel());
1115
1116     size_t scopeDelta = scopeDepth() - targetScopeDepth;
1117     ASSERT(scopeDelta <= m_scopeContextStack.size());
1118     if (!scopeDelta)
1119         return emitJump(target);
1120
1121     if (m_finallyDepth)
1122         return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta);
1123
1124     emitOpcode(op_jmp_scopes);
1125     instructions().append(scopeDelta);
1126     instructions().append(target->offsetFrom(instructions().size()));
1127     return target;
1128 }
1129
1130 RegisterID* CodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* iter, LabelID* target)
1131 {
1132     emitOpcode(op_next_pname);
1133     instructions().append(dst->index());
1134     instructions().append(iter->index());
1135     instructions().append(target->offsetFrom(instructions().size()));
1136     return dst;
1137 }
1138
1139 RegisterID* CodeGenerator::emitCatch(RegisterID* targetRegister, LabelID* start, LabelID* end)
1140 {
1141     HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth };
1142     exceptionHandlers().append(info);
1143     emitOpcode(op_catch);
1144     instructions().append(targetRegister->index());
1145     return targetRegister;
1146 }
1147
1148 RegisterID* CodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValue* message)
1149 {
1150     emitOpcode(op_new_error);
1151     instructions().append(dst->index());
1152     instructions().append(static_cast<int>(type));
1153     instructions().append(addUnexpectedConstant(message));
1154     return dst;
1155 }
1156
1157 PassRefPtr<LabelID> CodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, LabelID* finally)
1158 {
1159     emitOpcode(op_jsr);
1160     instructions().append(retAddrDst->index());
1161     instructions().append(finally->offsetFrom(instructions().size()));
1162     return finally;
1163 }
1164
1165 void CodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc)
1166 {
1167     emitOpcode(op_sret);
1168     instructions().append(retAddrSrc->index());
1169 }
1170
1171 void CodeGenerator::emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value)
1172 {
1173     m_codeBlock->needsFullScopeChain = true;
1174     ControlFlowContext context;
1175     context.isFinallyBlock = false;
1176     m_scopeContextStack.append(context);
1177     m_dynamicScopeDepth++;
1178     
1179     emitOpcode(op_push_new_scope);
1180     instructions().append(dst->index());
1181     instructions().append(addConstant(property));
1182     instructions().append(value->index());
1183 }
1184
1185 void CodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type)
1186 {
1187     SwitchInfo info = { instructions().size(), type };
1188     switch (type) {
1189         case SwitchInfo::SwitchImmediate:
1190             emitOpcode(op_switch_imm);
1191             break;
1192         case SwitchInfo::SwitchCharacter:
1193             emitOpcode(op_switch_char);
1194             break;
1195         case SwitchInfo::SwitchString:
1196             emitOpcode(op_switch_string);
1197             break;
1198         default:
1199             ASSERT_NOT_REACHED();
1200     }
1201
1202     instructions().append(0); // place holder for table index
1203     instructions().append(0); // place holder for default target    
1204     instructions().append(scrutineeRegister->index());
1205     m_switchContextStack.append(info);
1206 }
1207
1208 static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max)
1209 {
1210     UNUSED_PARAM(max);
1211     ASSERT(node->isNumber());
1212     double value = static_cast<NumberNode*>(node)->value();
1213     ASSERT(JSImmediate::from(value));
1214     int32_t key = static_cast<int32_t>(value);
1215     ASSERT(key == value);
1216     ASSERT(key >= min);
1217     ASSERT(key <= max);
1218     return key - min;
1219 }
1220
1221 static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1222 {
1223     jumpTable.min = min;
1224     jumpTable.branchOffsets.resize(max - min + 1);
1225     jumpTable.branchOffsets.fill(0);
1226     for (uint32_t i = 0; i < clauseCount; ++i) {
1227         // We're emitting this after the clause labels should have been fixed, so 
1228         // the labels should not be "forward" references
1229         ASSERT(!labels[i]->isForwardLabel());
1230         jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress)); 
1231     }
1232 }
1233
1234 static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max)
1235 {
1236     UNUSED_PARAM(max);
1237     ASSERT(node->isString());
1238     UString::Rep* clause = static_cast<StringNode*>(node)->value().rep();
1239     ASSERT(clause->size() == 1);
1240     
1241     int32_t key = clause->data()[0];
1242     ASSERT(key >= min);
1243     ASSERT(key <= max);
1244     return key - min;
1245 }
1246
1247 static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, int32_t min, int32_t max)
1248 {
1249     jumpTable.min = min;
1250     jumpTable.branchOffsets.resize(max - min + 1);
1251     jumpTable.branchOffsets.fill(0);
1252     for (uint32_t i = 0; i < clauseCount; ++i) {
1253         // We're emitting this after the clause labels should have been fixed, so 
1254         // the labels should not be "forward" references
1255         ASSERT(!labels[i]->isForwardLabel());
1256         jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress)); 
1257     }
1258 }
1259
1260 static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes)
1261 {
1262     for (uint32_t i = 0; i < clauseCount; ++i) {
1263         // We're emitting this after the clause labels should have been fixed, so 
1264         // the labels should not be "forward" references
1265         ASSERT(!labels[i]->isForwardLabel());
1266         
1267         ASSERT(nodes[i]->isString());
1268         UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().rep();
1269         jumpTable.add(clause, labels[i]->offsetFrom(switchAddress)); 
1270     }
1271 }
1272
1273 void CodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<LabelID>* labels, ExpressionNode** nodes, LabelID* defaultLabel, int32_t min, int32_t max)
1274 {
1275     SwitchInfo switchInfo = m_switchContextStack.last();
1276     m_switchContextStack.removeLast();
1277     if (switchInfo.switchType == SwitchInfo::SwitchImmediate) {
1278         instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->immediateSwitchJumpTables.size();
1279         instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1280
1281         m_codeBlock->immediateSwitchJumpTables.append(SimpleJumpTable());
1282         SimpleJumpTable& jumpTable = m_codeBlock->immediateSwitchJumpTables.last();
1283
1284         prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes, min, max);
1285     } else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) {
1286         instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->characterSwitchJumpTables.size();
1287         instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1288         
1289         m_codeBlock->characterSwitchJumpTables.append(SimpleJumpTable());
1290         SimpleJumpTable& jumpTable = m_codeBlock->characterSwitchJumpTables.last();
1291
1292         prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes, min, max);
1293     } else {
1294         ASSERT(switchInfo.switchType == SwitchInfo::SwitchString);
1295         instructions()[switchInfo.opcodeOffset + 1] = m_codeBlock->stringSwitchJumpTables.size();
1296         instructions()[switchInfo.opcodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.opcodeOffset + 3);
1297
1298         m_codeBlock->stringSwitchJumpTables.append(StringJumpTable());
1299         StringJumpTable& jumpTable = m_codeBlock->stringSwitchJumpTables.last();
1300
1301         prepareJumpTableForStringSwitch(jumpTable, switchInfo.opcodeOffset + 3, clauseCount, labels, nodes);
1302     }
1303 }
1304
1305 } // namespace KJS