1/* 2 * Copyright (C) 2008, 2009 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 "BytecodeGenerator.h" 32 33#include "BatchedTransitionOptimizer.h" 34#include "PrototypeFunction.h" 35#include "JSFunction.h" 36#include "Interpreter.h" 37#include "UString.h" 38 39using namespace std; 40 41namespace JSC { 42 43/* 44 The layout of a register frame looks like this: 45 46 For 47 48 function f(x, y) { 49 var v1; 50 function g() { } 51 var v2; 52 return (x) * (y); 53 } 54 55 assuming (x) and (y) generated temporaries t1 and t2, you would have 56 57 ------------------------------------ 58 | x | y | g | v2 | v1 | t1 | t2 | <-- value held 59 ------------------------------------ 60 | -5 | -4 | -3 | -2 | -1 | +0 | +1 | <-- register index 61 ------------------------------------ 62 | params->|<-locals | temps-> 63 64 Because temporary registers are allocated in a stack-like fashion, we 65 can reclaim them with a simple popping algorithm. The same goes for labels. 66 (We never reclaim parameter or local registers, because parameters and 67 locals are DontDelete.) 68 69 The register layout before a function call looks like this: 70 71 For 72 73 function f(x, y) 74 { 75 } 76 77 f(1); 78 79 > <------------------------------ 80 < > reserved: call frame | 1 | <-- value held 81 > >snip< <------------------------------ 82 < > +0 | +1 | +2 | +3 | +4 | +5 | <-- register index 83 > <------------------------------ 84 | params->|<-locals | temps-> 85 86 The call instruction fills in the "call frame" registers. It also pads 87 missing arguments at the end of the call: 88 89 > <----------------------------------- 90 < > reserved: call frame | 1 | ? | <-- value held ("?" stands for "undefined") 91 > >snip< <----------------------------------- 92 < > +0 | +1 | +2 | +3 | +4 | +5 | +6 | <-- register index 93 > <----------------------------------- 94 | params->|<-locals | temps-> 95 96 After filling in missing arguments, the call instruction sets up the new 97 stack frame to overlap the end of the old stack frame: 98 99 |----------------------------------> < 100 | reserved: call frame | 1 | ? < > <-- value held ("?" stands for "undefined") 101 |----------------------------------> >snip< < 102 | -7 | -6 | -5 | -4 | -3 | -2 | -1 < > <-- register index 103 |----------------------------------> < 104 | | params->|<-locals | temps-> 105 106 That way, arguments are "copied" into the callee's stack frame for free. 107 108 If the caller supplies too many arguments, this trick doesn't work. The 109 extra arguments protrude into space reserved for locals and temporaries. 110 In that case, the call instruction makes a real copy of the call frame header, 111 along with just the arguments expected by the callee, leaving the original 112 call frame header and arguments behind. (The call instruction can't just discard 113 extra arguments, because the "arguments" object may access them later.) 114 This copying strategy ensures that all named values will be at the indices 115 expected by the callee. 116*/ 117 118#ifndef NDEBUG 119static bool s_dumpsGeneratedCode = false; 120#endif 121 122void BytecodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode) 123{ 124#ifndef NDEBUG 125 s_dumpsGeneratedCode = dumpsGeneratedCode; 126#else 127 UNUSED_PARAM(dumpsGeneratedCode); 128#endif 129} 130 131bool BytecodeGenerator::dumpsGeneratedCode() 132{ 133#ifndef NDEBUG 134 return s_dumpsGeneratedCode; 135#else 136 return false; 137#endif 138} 139 140void BytecodeGenerator::generate() 141{ 142 m_codeBlock->setThisRegister(m_thisRegister.index()); 143 144 m_scopeNode->emitBytecode(*this); 145 146#ifndef NDEBUG 147 m_codeBlock->setInstructionCount(m_codeBlock->instructions().size()); 148 149 if (s_dumpsGeneratedCode) 150 m_codeBlock->dump(m_scopeChain->globalObject()->globalExec()); 151#endif 152 153 if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode) 154 symbolTable().clear(); 155 156 m_codeBlock->setIsNumericCompareFunction(instructions() == m_globalData->numericCompareFunction(m_scopeChain->globalObject()->globalExec())); 157 158#if !ENABLE(OPCODE_SAMPLING) 159 if (!m_regeneratingForExceptionInfo && (m_codeType == FunctionCode || m_codeType == EvalCode)) 160 m_codeBlock->clearExceptionInfo(); 161#endif 162 163 m_codeBlock->shrinkToFit(); 164} 165 166bool BytecodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0) 167{ 168 int index = m_calleeRegisters.size(); 169 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); 170 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry); 171 172 if (!result.second) { 173 r0 = ®isterFor(result.first->second.getIndex()); 174 return false; 175 } 176 177 ++m_codeBlock->m_numVars; 178 r0 = newRegister(); 179 return true; 180} 181 182bool BytecodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0) 183{ 184 int index = m_nextGlobalIndex; 185 SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0); 186 pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry); 187 188 if (!result.second) 189 index = result.first->second.getIndex(); 190 else { 191 --m_nextGlobalIndex; 192 m_globals.append(index + m_globalVarStorageOffset); 193 } 194 195 r0 = ®isterFor(index); 196 return result.second; 197} 198 199void BytecodeGenerator::preserveLastVar() 200{ 201 if ((m_firstConstantIndex = m_calleeRegisters.size()) != 0) 202 m_lastVar = &m_calleeRegisters.last(); 203} 204 205BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, ProgramCodeBlock* codeBlock) 206 : m_shouldEmitDebugHooks(!!debugger) 207 , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling()) 208 , m_scopeChain(&scopeChain) 209 , m_symbolTable(symbolTable) 210 , m_scopeNode(programNode) 211 , m_codeBlock(codeBlock) 212 , m_thisRegister(RegisterFile::ProgramCodeThisRegister) 213 , m_finallyDepth(0) 214 , m_dynamicScopeDepth(0) 215 , m_baseScopeDepth(0) 216 , m_codeType(GlobalCode) 217 , m_nextGlobalIndex(-1) 218 , m_nextConstantOffset(0) 219 , m_globalConstantIndex(0) 220 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) 221 , m_lastOpcodeID(op_end) 222 , m_emitNodeDepth(0) 223 , m_regeneratingForExceptionInfo(false) 224 , m_codeBlockBeingRegeneratedFrom(0) 225{ 226 if (m_shouldEmitDebugHooks) 227 m_codeBlock->setNeedsFullScopeChain(true); 228 229 emitOpcode(op_enter); 230 codeBlock->setGlobalData(m_globalData); 231 232 // FIXME: Move code that modifies the global object to Interpreter::execute. 233 234 m_codeBlock->m_numParameters = 1; // Allocate space for "this" 235 236 JSGlobalObject* globalObject = scopeChain.globalObject(); 237 ExecState* exec = globalObject->globalExec(); 238 RegisterFile* registerFile = &exec->globalData().interpreter->registerFile(); 239 240 // Shift register indexes in generated code to elide registers allocated by intermediate stack frames. 241 m_globalVarStorageOffset = -RegisterFile::CallFrameHeaderSize - m_codeBlock->m_numParameters - registerFile->size(); 242 243 // Add previously defined symbols to bookkeeping. 244 m_globals.grow(symbolTable->size()); 245 SymbolTable::iterator end = symbolTable->end(); 246 for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it) 247 registerFor(it->second.getIndex()).setIndex(it->second.getIndex() + m_globalVarStorageOffset); 248 249 BatchedTransitionOptimizer optimizer(globalObject); 250 251 const VarStack& varStack = programNode->varStack(); 252 const FunctionStack& functionStack = programNode->functionStack(); 253 bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals(); 254 if (canOptimizeNewGlobals) { 255 // Shift new symbols so they get stored prior to existing symbols. 256 m_nextGlobalIndex -= symbolTable->size(); 257 258 for (size_t i = 0; i < functionStack.size(); ++i) { 259 FunctionBodyNode* function = functionStack[i]; 260 globalObject->removeDirect(function->ident()); // Make sure our new function is not shadowed by an old property. 261 emitNewFunction(addGlobalVar(function->ident(), false), function); 262 } 263 264 Vector<RegisterID*, 32> newVars; 265 for (size_t i = 0; i < varStack.size(); ++i) 266 if (!globalObject->hasProperty(exec, *varStack[i].first)) 267 newVars.append(addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant)); 268 269 preserveLastVar(); 270 271 for (size_t i = 0; i < newVars.size(); ++i) 272 emitLoad(newVars[i], jsUndefined()); 273 } else { 274 for (size_t i = 0; i < functionStack.size(); ++i) { 275 FunctionBodyNode* function = functionStack[i]; 276 globalObject->putWithAttributes(exec, function->ident(), new (exec) JSFunction(exec, makeFunction(exec, function), scopeChain.node()), DontDelete); 277 } 278 for (size_t i = 0; i < varStack.size(); ++i) { 279 if (globalObject->hasProperty(exec, *varStack[i].first)) 280 continue; 281 int attributes = DontDelete; 282 if (varStack[i].second & DeclarationStacks::IsConstant) 283 attributes |= ReadOnly; 284 globalObject->putWithAttributes(exec, *varStack[i].first, jsUndefined(), attributes); 285 } 286 287 preserveLastVar(); 288 } 289} 290 291BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock) 292 : m_shouldEmitDebugHooks(!!debugger) 293 , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling()) 294 , m_scopeChain(&scopeChain) 295 , m_symbolTable(symbolTable) 296 , m_scopeNode(functionBody) 297 , m_codeBlock(codeBlock) 298 , m_finallyDepth(0) 299 , m_dynamicScopeDepth(0) 300 , m_baseScopeDepth(0) 301 , m_codeType(FunctionCode) 302 , m_nextConstantOffset(0) 303 , m_globalConstantIndex(0) 304 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) 305 , m_lastOpcodeID(op_end) 306 , m_emitNodeDepth(0) 307 , m_regeneratingForExceptionInfo(false) 308 , m_codeBlockBeingRegeneratedFrom(0) 309{ 310 if (m_shouldEmitDebugHooks) 311 m_codeBlock->setNeedsFullScopeChain(true); 312 313 codeBlock->setGlobalData(m_globalData); 314 315 bool usesArguments = functionBody->usesArguments(); 316 codeBlock->setUsesArguments(usesArguments); 317 if (usesArguments) { 318 m_argumentsRegister.setIndex(RegisterFile::OptionalCalleeArguments); 319 addVar(propertyNames().arguments, false); 320 } 321 322 if (m_codeBlock->needsFullScopeChain()) { 323 ++m_codeBlock->m_numVars; 324 m_activationRegisterIndex = newRegister()->index(); 325 emitOpcode(op_enter_with_activation); 326 instructions().append(m_activationRegisterIndex); 327 } else 328 emitOpcode(op_enter); 329 330 if (usesArguments) { 331 emitOpcode(op_init_arguments); 332 333 // The debugger currently retrieves the arguments object from an activation rather than pulling 334 // it from a call frame. In the long-term it should stop doing that (<rdar://problem/6911886>), 335 // but for now we force eager creation of the arguments object when debugging. 336 if (m_shouldEmitDebugHooks) 337 emitOpcode(op_create_arguments); 338 } 339 340 const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack(); 341 for (size_t i = 0; i < functionStack.size(); ++i) { 342 FunctionBodyNode* function = functionStack[i]; 343 const Identifier& ident = function->ident(); 344 m_functions.add(ident.ustring().rep()); 345 emitNewFunction(addVar(ident, false), function); 346 } 347 348 const DeclarationStacks::VarStack& varStack = functionBody->varStack(); 349 for (size_t i = 0; i < varStack.size(); ++i) 350 addVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant); 351 352 FunctionParameters& parameters = *functionBody->parameters(); 353 size_t parameterCount = parameters.size(); 354 m_nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1; 355 m_parameters.grow(1 + parameterCount); // reserve space for "this" 356 357 // Add "this" as a parameter 358 m_thisRegister.setIndex(m_nextParameterIndex); 359 ++m_nextParameterIndex; 360 ++m_codeBlock->m_numParameters; 361 362 if (functionBody->usesThis() || m_shouldEmitDebugHooks) { 363 emitOpcode(op_convert_this); 364 instructions().append(m_thisRegister.index()); 365 } 366 367 for (size_t i = 0; i < parameterCount; ++i) 368 addParameter(parameters[i]); 369 370 preserveLastVar(); 371} 372 373BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock) 374 : m_shouldEmitDebugHooks(!!debugger) 375 , m_shouldEmitProfileHooks(scopeChain.globalObject()->supportsProfiling()) 376 , m_scopeChain(&scopeChain) 377 , m_symbolTable(symbolTable) 378 , m_scopeNode(evalNode) 379 , m_codeBlock(codeBlock) 380 , m_thisRegister(RegisterFile::ProgramCodeThisRegister) 381 , m_finallyDepth(0) 382 , m_dynamicScopeDepth(0) 383 , m_baseScopeDepth(codeBlock->baseScopeDepth()) 384 , m_codeType(EvalCode) 385 , m_nextConstantOffset(0) 386 , m_globalConstantIndex(0) 387 , m_globalData(&scopeChain.globalObject()->globalExec()->globalData()) 388 , m_lastOpcodeID(op_end) 389 , m_emitNodeDepth(0) 390 , m_regeneratingForExceptionInfo(false) 391 , m_codeBlockBeingRegeneratedFrom(0) 392{ 393 if (m_shouldEmitDebugHooks || m_baseScopeDepth) 394 m_codeBlock->setNeedsFullScopeChain(true); 395 396 emitOpcode(op_enter); 397 codeBlock->setGlobalData(m_globalData); 398 m_codeBlock->m_numParameters = 1; // Allocate space for "this" 399 400 const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack(); 401 for (size_t i = 0; i < functionStack.size(); ++i) 402 m_codeBlock->addFunctionDecl(makeFunction(m_globalData, functionStack[i])); 403 404 const DeclarationStacks::VarStack& varStack = evalNode->varStack(); 405 unsigned numVariables = varStack.size(); 406 Vector<Identifier> variables; 407 variables.reserveCapacity(numVariables); 408 for (size_t i = 0; i < numVariables; ++i) 409 variables.append(*varStack[i].first); 410 codeBlock->adoptVariables(variables); 411 412 preserveLastVar(); 413} 414 415RegisterID* BytecodeGenerator::addParameter(const Identifier& ident) 416{ 417 // Parameters overwrite var declarations, but not function declarations. 418 RegisterID* result = 0; 419 UString::Rep* rep = ident.ustring().rep(); 420 if (!m_functions.contains(rep)) { 421 symbolTable().set(rep, m_nextParameterIndex); 422 RegisterID& parameter = registerFor(m_nextParameterIndex); 423 parameter.setIndex(m_nextParameterIndex); 424 result = ¶meter; 425 } 426 427 // To maintain the calling convention, we have to allocate unique space for 428 // each parameter, even if the parameter doesn't make it into the symbol table. 429 ++m_nextParameterIndex; 430 ++m_codeBlock->m_numParameters; 431 return result; 432} 433 434RegisterID* BytecodeGenerator::registerFor(const Identifier& ident) 435{ 436 if (ident == propertyNames().thisIdentifier) 437 return &m_thisRegister; 438 439 if (!shouldOptimizeLocals()) 440 return 0; 441 442 SymbolTableEntry entry = symbolTable().get(ident.ustring().rep()); 443 if (entry.isNull()) 444 return 0; 445 446 if (ident == propertyNames().arguments) 447 createArgumentsIfNecessary(); 448 449 return ®isterFor(entry.getIndex()); 450} 451 452bool BytecodeGenerator::willResolveToArguments(const Identifier& ident) 453{ 454 if (ident != propertyNames().arguments) 455 return false; 456 457 if (!shouldOptimizeLocals()) 458 return false; 459 460 SymbolTableEntry entry = symbolTable().get(ident.ustring().rep()); 461 if (entry.isNull()) 462 return false; 463 464 if (m_codeBlock->usesArguments() && m_codeType == FunctionCode) 465 return true; 466 467 return false; 468} 469 470RegisterID* BytecodeGenerator::uncheckedRegisterForArguments() 471{ 472 ASSERT(willResolveToArguments(propertyNames().arguments)); 473 474 SymbolTableEntry entry = symbolTable().get(propertyNames().arguments.ustring().rep()); 475 ASSERT(!entry.isNull()); 476 return ®isterFor(entry.getIndex()); 477} 478 479RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident) 480{ 481 if (m_codeType == EvalCode) 482 return 0; 483 484 SymbolTableEntry entry = symbolTable().get(ident.ustring().rep()); 485 if (entry.isNull()) 486 return 0; 487 488 return ®isterFor(entry.getIndex()); 489} 490 491bool BytecodeGenerator::isLocal(const Identifier& ident) 492{ 493 if (ident == propertyNames().thisIdentifier) 494 return true; 495 496 return shouldOptimizeLocals() && symbolTable().contains(ident.ustring().rep()); 497} 498 499bool BytecodeGenerator::isLocalConstant(const Identifier& ident) 500{ 501 return symbolTable().get(ident.ustring().rep()).isReadOnly(); 502} 503 504RegisterID* BytecodeGenerator::newRegister() 505{ 506 m_calleeRegisters.append(m_calleeRegisters.size()); 507 m_codeBlock->m_numCalleeRegisters = max<int>(m_codeBlock->m_numCalleeRegisters, m_calleeRegisters.size()); 508 return &m_calleeRegisters.last(); 509} 510 511RegisterID* BytecodeGenerator::newTemporary() 512{ 513 // Reclaim free register IDs. 514 while (m_calleeRegisters.size() && !m_calleeRegisters.last().refCount()) 515 m_calleeRegisters.removeLast(); 516 517 RegisterID* result = newRegister(); 518 result->setTemporary(); 519 return result; 520} 521 522RegisterID* BytecodeGenerator::highestUsedRegister() 523{ 524 size_t count = m_codeBlock->m_numCalleeRegisters; 525 while (m_calleeRegisters.size() < count) 526 newRegister(); 527 return &m_calleeRegisters.last(); 528} 529 530PassRefPtr<LabelScope> BytecodeGenerator::newLabelScope(LabelScope::Type type, const Identifier* name) 531{ 532 // Reclaim free label scopes. 533 while (m_labelScopes.size() && !m_labelScopes.last().refCount()) 534 m_labelScopes.removeLast(); 535 536 // Allocate new label scope. 537 LabelScope scope(type, name, scopeDepth(), newLabel(), type == LabelScope::Loop ? newLabel() : PassRefPtr<Label>()); // Only loops have continue targets. 538 m_labelScopes.append(scope); 539 return &m_labelScopes.last(); 540} 541 542PassRefPtr<Label> BytecodeGenerator::newLabel() 543{ 544 // Reclaim free label IDs. 545 while (m_labels.size() && !m_labels.last().refCount()) 546 m_labels.removeLast(); 547 548 // Allocate new label ID. 549 m_labels.append(m_codeBlock); 550 return &m_labels.last(); 551} 552 553PassRefPtr<Label> BytecodeGenerator::emitLabel(Label* l0) 554{ 555 unsigned newLabelIndex = instructions().size(); 556 l0->setLocation(newLabelIndex); 557 558 if (m_codeBlock->numberOfJumpTargets()) { 559 unsigned lastLabelIndex = m_codeBlock->lastJumpTarget(); 560 ASSERT(lastLabelIndex <= newLabelIndex); 561 if (newLabelIndex == lastLabelIndex) { 562 // Peephole optimizations have already been disabled by emitting the last label 563 return l0; 564 } 565 } 566 567 m_codeBlock->addJumpTarget(newLabelIndex); 568 569 // This disables peephole optimizations when an instruction is a jump target 570 m_lastOpcodeID = op_end; 571 return l0; 572} 573 574void BytecodeGenerator::emitOpcode(OpcodeID opcodeID) 575{ 576 instructions().append(globalData()->interpreter->getOpcode(opcodeID)); 577 m_lastOpcodeID = opcodeID; 578} 579 580void BytecodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index) 581{ 582 ASSERT(instructions().size() >= 4); 583 size_t size = instructions().size(); 584 dstIndex = instructions().at(size - 3).u.operand; 585 src1Index = instructions().at(size - 2).u.operand; 586 src2Index = instructions().at(size - 1).u.operand; 587} 588 589void BytecodeGenerator::retrieveLastUnaryOp(int& dstIndex, int& srcIndex) 590{ 591 ASSERT(instructions().size() >= 3); 592 size_t size = instructions().size(); 593 dstIndex = instructions().at(size - 2).u.operand; 594 srcIndex = instructions().at(size - 1).u.operand; 595} 596 597void ALWAYS_INLINE BytecodeGenerator::rewindBinaryOp() 598{ 599 ASSERT(instructions().size() >= 4); 600 instructions().shrink(instructions().size() - 4); 601} 602 603void ALWAYS_INLINE BytecodeGenerator::rewindUnaryOp() 604{ 605 ASSERT(instructions().size() >= 3); 606 instructions().shrink(instructions().size() - 3); 607} 608 609PassRefPtr<Label> BytecodeGenerator::emitJump(Label* target) 610{ 611 size_t begin = instructions().size(); 612 emitOpcode(target->isForward() ? op_jmp : op_loop); 613 instructions().append(target->bind(begin, instructions().size())); 614 return target; 615} 616 617PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* target) 618{ 619 if (m_lastOpcodeID == op_less) { 620 int dstIndex; 621 int src1Index; 622 int src2Index; 623 624 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 625 626 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 627 rewindBinaryOp(); 628 629 size_t begin = instructions().size(); 630 emitOpcode(target->isForward() ? op_jless : op_loop_if_less); 631 instructions().append(src1Index); 632 instructions().append(src2Index); 633 instructions().append(target->bind(begin, instructions().size())); 634 return target; 635 } 636 } else if (m_lastOpcodeID == op_lesseq && !target->isForward()) { 637 int dstIndex; 638 int src1Index; 639 int src2Index; 640 641 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 642 643 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 644 rewindBinaryOp(); 645 646 size_t begin = instructions().size(); 647 emitOpcode(op_loop_if_lesseq); 648 instructions().append(src1Index); 649 instructions().append(src2Index); 650 instructions().append(target->bind(begin, instructions().size())); 651 return target; 652 } 653 } else if (m_lastOpcodeID == op_eq_null && target->isForward()) { 654 int dstIndex; 655 int srcIndex; 656 657 retrieveLastUnaryOp(dstIndex, srcIndex); 658 659 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 660 rewindUnaryOp(); 661 662 size_t begin = instructions().size(); 663 emitOpcode(op_jeq_null); 664 instructions().append(srcIndex); 665 instructions().append(target->bind(begin, instructions().size())); 666 return target; 667 } 668 } else if (m_lastOpcodeID == op_neq_null && target->isForward()) { 669 int dstIndex; 670 int srcIndex; 671 672 retrieveLastUnaryOp(dstIndex, srcIndex); 673 674 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 675 rewindUnaryOp(); 676 677 size_t begin = instructions().size(); 678 emitOpcode(op_jneq_null); 679 instructions().append(srcIndex); 680 instructions().append(target->bind(begin, instructions().size())); 681 return target; 682 } 683 } 684 685 size_t begin = instructions().size(); 686 687 emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true); 688 instructions().append(cond->index()); 689 instructions().append(target->bind(begin, instructions().size())); 690 return target; 691} 692 693PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* target) 694{ 695 if (m_lastOpcodeID == op_less && target->isForward()) { 696 int dstIndex; 697 int src1Index; 698 int src2Index; 699 700 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 701 702 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 703 rewindBinaryOp(); 704 705 size_t begin = instructions().size(); 706 emitOpcode(op_jnless); 707 instructions().append(src1Index); 708 instructions().append(src2Index); 709 instructions().append(target->bind(begin, instructions().size())); 710 return target; 711 } 712 } else if (m_lastOpcodeID == op_lesseq && target->isForward()) { 713 int dstIndex; 714 int src1Index; 715 int src2Index; 716 717 retrieveLastBinaryOp(dstIndex, src1Index, src2Index); 718 719 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 720 rewindBinaryOp(); 721 722 size_t begin = instructions().size(); 723 emitOpcode(op_jnlesseq); 724 instructions().append(src1Index); 725 instructions().append(src2Index); 726 instructions().append(target->bind(begin, instructions().size())); 727 return target; 728 } 729 } else if (m_lastOpcodeID == op_not) { 730 int dstIndex; 731 int srcIndex; 732 733 retrieveLastUnaryOp(dstIndex, srcIndex); 734 735 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 736 rewindUnaryOp(); 737 738 size_t begin = instructions().size(); 739 emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true); 740 instructions().append(srcIndex); 741 instructions().append(target->bind(begin, instructions().size())); 742 return target; 743 } 744 } else if (m_lastOpcodeID == op_eq_null && target->isForward()) { 745 int dstIndex; 746 int srcIndex; 747 748 retrieveLastUnaryOp(dstIndex, srcIndex); 749 750 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 751 rewindUnaryOp(); 752 753 size_t begin = instructions().size(); 754 emitOpcode(op_jneq_null); 755 instructions().append(srcIndex); 756 instructions().append(target->bind(begin, instructions().size())); 757 return target; 758 } 759 } else if (m_lastOpcodeID == op_neq_null && target->isForward()) { 760 int dstIndex; 761 int srcIndex; 762 763 retrieveLastUnaryOp(dstIndex, srcIndex); 764 765 if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { 766 rewindUnaryOp(); 767 768 size_t begin = instructions().size(); 769 emitOpcode(op_jeq_null); 770 instructions().append(srcIndex); 771 instructions().append(target->bind(begin, instructions().size())); 772 return target; 773 } 774 } 775 776 size_t begin = instructions().size(); 777 emitOpcode(target->isForward() ? op_jfalse : op_loop_if_false); 778 instructions().append(cond->index()); 779 instructions().append(target->bind(begin, instructions().size())); 780 return target; 781} 782 783PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(RegisterID* cond, Label* target) 784{ 785 size_t begin = instructions().size(); 786 787 emitOpcode(op_jneq_ptr); 788 instructions().append(cond->index()); 789 instructions().append(m_scopeChain->globalObject()->d()->callFunction); 790 instructions().append(target->bind(begin, instructions().size())); 791 return target; 792} 793 794PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond, Label* target) 795{ 796 size_t begin = instructions().size(); 797 798 emitOpcode(op_jneq_ptr); 799 instructions().append(cond->index()); 800 instructions().append(m_scopeChain->globalObject()->d()->applyFunction); 801 instructions().append(target->bind(begin, instructions().size())); 802 return target; 803} 804 805unsigned BytecodeGenerator::addConstant(const Identifier& ident) 806{ 807 UString::Rep* rep = ident.ustring().rep(); 808 pair<IdentifierMap::iterator, bool> result = m_identifierMap.add(rep, m_codeBlock->numberOfIdentifiers()); 809 if (result.second) // new entry 810 m_codeBlock->addIdentifier(Identifier(m_globalData, rep)); 811 812 return result.first->second; 813} 814 815RegisterID* BytecodeGenerator::addConstantValue(JSValue v) 816{ 817 int index = m_nextConstantOffset; 818 819 pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(JSValue::encode(v), m_nextConstantOffset); 820 if (result.second) { 821 m_constantPoolRegisters.append(FirstConstantRegisterIndex + m_nextConstantOffset); 822 ++m_nextConstantOffset; 823 m_codeBlock->addConstantRegister(JSValue(v)); 824 } else 825 index = result.first->second; 826 827 return &m_constantPoolRegisters[index]; 828} 829 830unsigned BytecodeGenerator::addRegExp(RegExp* r) 831{ 832 return m_codeBlock->addRegExp(r); 833} 834 835RegisterID* BytecodeGenerator::emitMove(RegisterID* dst, RegisterID* src) 836{ 837 emitOpcode(op_mov); 838 instructions().append(dst->index()); 839 instructions().append(src->index()); 840 return dst; 841} 842 843RegisterID* BytecodeGenerator::emitUnaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src) 844{ 845 emitOpcode(opcodeID); 846 instructions().append(dst->index()); 847 instructions().append(src->index()); 848 return dst; 849} 850 851RegisterID* BytecodeGenerator::emitPreInc(RegisterID* srcDst) 852{ 853 emitOpcode(op_pre_inc); 854 instructions().append(srcDst->index()); 855 return srcDst; 856} 857 858RegisterID* BytecodeGenerator::emitPreDec(RegisterID* srcDst) 859{ 860 emitOpcode(op_pre_dec); 861 instructions().append(srcDst->index()); 862 return srcDst; 863} 864 865RegisterID* BytecodeGenerator::emitPostInc(RegisterID* dst, RegisterID* srcDst) 866{ 867 emitOpcode(op_post_inc); 868 instructions().append(dst->index()); 869 instructions().append(srcDst->index()); 870 return dst; 871} 872 873RegisterID* BytecodeGenerator::emitPostDec(RegisterID* dst, RegisterID* srcDst) 874{ 875 emitOpcode(op_post_dec); 876 instructions().append(dst->index()); 877 instructions().append(srcDst->index()); 878 return dst; 879} 880 881RegisterID* BytecodeGenerator::emitBinaryOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes types) 882{ 883 emitOpcode(opcodeID); 884 instructions().append(dst->index()); 885 instructions().append(src1->index()); 886 instructions().append(src2->index()); 887 888 if (opcodeID == op_bitor || opcodeID == op_bitand || opcodeID == op_bitxor || 889 opcodeID == op_add || opcodeID == op_mul || opcodeID == op_sub || opcodeID == op_div) 890 instructions().append(types.toInt()); 891 892 return dst; 893} 894 895RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2) 896{ 897 if (m_lastOpcodeID == op_typeof) { 898 int dstIndex; 899 int srcIndex; 900 901 retrieveLastUnaryOp(dstIndex, srcIndex); 902 903 if (src1->index() == dstIndex 904 && src1->isTemporary() 905 && m_codeBlock->isConstantRegisterIndex(src2->index()) 906 && m_codeBlock->constantRegister(src2->index()).jsValue().isString()) { 907 const UString& value = asString(m_codeBlock->constantRegister(src2->index()).jsValue())->tryGetValue(); 908 if (value == "undefined") { 909 rewindUnaryOp(); 910 emitOpcode(op_is_undefined); 911 instructions().append(dst->index()); 912 instructions().append(srcIndex); 913 return dst; 914 } 915 if (value == "boolean") { 916 rewindUnaryOp(); 917 emitOpcode(op_is_boolean); 918 instructions().append(dst->index()); 919 instructions().append(srcIndex); 920 return dst; 921 } 922 if (value == "number") { 923 rewindUnaryOp(); 924 emitOpcode(op_is_number); 925 instructions().append(dst->index()); 926 instructions().append(srcIndex); 927 return dst; 928 } 929 if (value == "string") { 930 rewindUnaryOp(); 931 emitOpcode(op_is_string); 932 instructions().append(dst->index()); 933 instructions().append(srcIndex); 934 return dst; 935 } 936 if (value == "object") { 937 rewindUnaryOp(); 938 emitOpcode(op_is_object); 939 instructions().append(dst->index()); 940 instructions().append(srcIndex); 941 return dst; 942 } 943 if (value == "function") { 944 rewindUnaryOp(); 945 emitOpcode(op_is_function); 946 instructions().append(dst->index()); 947 instructions().append(srcIndex); 948 return dst; 949 } 950 } 951 } 952 953 emitOpcode(opcodeID); 954 instructions().append(dst->index()); 955 instructions().append(src1->index()); 956 instructions().append(src2->index()); 957 return dst; 958} 959 960RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, bool b) 961{ 962 return emitLoad(dst, jsBoolean(b)); 963} 964 965RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, double number) 966{ 967 // FIXME: Our hash tables won't hold infinity, so we make a new JSNumberCell each time. 968 // Later we can do the extra work to handle that like the other cases. 969 if (number == HashTraits<double>::emptyValue() || HashTraits<double>::isDeletedValue(number)) 970 return emitLoad(dst, jsNumber(globalData(), number)); 971 JSValue& valueInMap = m_numberMap.add(number, JSValue()).first->second; 972 if (!valueInMap) 973 valueInMap = jsNumber(globalData(), number); 974 return emitLoad(dst, valueInMap); 975} 976 977RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, const Identifier& identifier) 978{ 979 JSString*& stringInMap = m_stringMap.add(identifier.ustring().rep(), 0).first->second; 980 if (!stringInMap) 981 stringInMap = jsOwnedString(globalData(), identifier.ustring()); 982 return emitLoad(dst, JSValue(stringInMap)); 983} 984 985RegisterID* BytecodeGenerator::emitLoad(RegisterID* dst, JSValue v) 986{ 987 RegisterID* constantID = addConstantValue(v); 988 if (dst) 989 return emitMove(dst, constantID); 990 return constantID; 991} 992 993bool BytecodeGenerator::findScopedProperty(const Identifier& property, int& index, size_t& stackDepth, bool forWriting, JSObject*& globalObject) 994{ 995 // Cases where we cannot statically optimize the lookup. 996 if (property == propertyNames().arguments || !canOptimizeNonLocals()) { 997 stackDepth = 0; 998 index = missingSymbolMarker(); 999 1000 if (shouldOptimizeLocals() && m_codeType == GlobalCode) { 1001 ScopeChainIterator iter = m_scopeChain->begin(); 1002 globalObject = *iter; 1003 ASSERT((++iter) == m_scopeChain->end()); 1004 } 1005 return false; 1006 } 1007 1008 size_t depth = 0; 1009 1010 ScopeChainIterator iter = m_scopeChain->begin(); 1011 ScopeChainIterator end = m_scopeChain->end(); 1012 for (; iter != end; ++iter, ++depth) { 1013 JSObject* currentScope = *iter; 1014 if (!currentScope->isVariableObject()) 1015 break; 1016 JSVariableObject* currentVariableObject = static_cast<JSVariableObject*>(currentScope); 1017 SymbolTableEntry entry = currentVariableObject->symbolTable().get(property.ustring().rep()); 1018 1019 // Found the property 1020 if (!entry.isNull()) { 1021 if (entry.isReadOnly() && forWriting) { 1022 stackDepth = 0; 1023 index = missingSymbolMarker(); 1024 if (++iter == end) 1025 globalObject = currentVariableObject; 1026 return false; 1027 } 1028 stackDepth = depth; 1029 index = entry.getIndex(); 1030 if (++iter == end) 1031 globalObject = currentVariableObject; 1032 return true; 1033 } 1034 if (currentVariableObject->isDynamicScope()) 1035 break; 1036 } 1037 1038 // Can't locate the property but we're able to avoid a few lookups. 1039 stackDepth = depth; 1040 index = missingSymbolMarker(); 1041 JSObject* scope = *iter; 1042 if (++iter == end) 1043 globalObject = scope; 1044 return true; 1045} 1046 1047RegisterID* BytecodeGenerator::emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype) 1048{ 1049 emitOpcode(op_instanceof); 1050 instructions().append(dst->index()); 1051 instructions().append(value->index()); 1052 instructions().append(base->index()); 1053 instructions().append(basePrototype->index()); 1054 return dst; 1055} 1056 1057RegisterID* BytecodeGenerator::emitResolve(RegisterID* dst, const Identifier& property) 1058{ 1059 size_t depth = 0; 1060 int index = 0; 1061 JSObject* globalObject = 0; 1062 if (!findScopedProperty(property, index, depth, false, globalObject) && !globalObject) { 1063 // We can't optimise at all :-( 1064 emitOpcode(op_resolve); 1065 instructions().append(dst->index()); 1066 instructions().append(addConstant(property)); 1067 return dst; 1068 } 1069 1070 if (globalObject) { 1071 bool forceGlobalResolve = false; 1072 if (m_regeneratingForExceptionInfo) { 1073#if ENABLE(JIT) 1074 forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInfoAtBytecodeOffset(instructions().size()); 1075#else 1076 forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInstructionAtBytecodeOffset(instructions().size()); 1077#endif 1078 } 1079 1080 if (index != missingSymbolMarker() && !forceGlobalResolve) { 1081 // Directly index the property lookup across multiple scopes. 1082 return emitGetScopedVar(dst, depth, index, globalObject); 1083 } 1084 1085#if ENABLE(JIT) 1086 m_codeBlock->addGlobalResolveInfo(instructions().size()); 1087#else 1088 m_codeBlock->addGlobalResolveInstruction(instructions().size()); 1089#endif 1090 emitOpcode(op_resolve_global); 1091 instructions().append(dst->index()); 1092 instructions().append(globalObject); 1093 instructions().append(addConstant(property)); 1094 instructions().append(0); 1095 instructions().append(0); 1096 return dst; 1097 } 1098 1099 if (index != missingSymbolMarker()) { 1100 // Directly index the property lookup across multiple scopes. 1101 return emitGetScopedVar(dst, depth, index, globalObject); 1102 } 1103 1104 // In this case we are at least able to drop a few scope chains from the 1105 // lookup chain, although we still need to hash from then on. 1106 emitOpcode(op_resolve_skip); 1107 instructions().append(dst->index()); 1108 instructions().append(addConstant(property)); 1109 instructions().append(depth); 1110 return dst; 1111} 1112 1113RegisterID* BytecodeGenerator::emitGetScopedVar(RegisterID* dst, size_t depth, int index, JSValue globalObject) 1114{ 1115 if (globalObject) { 1116 emitOpcode(op_get_global_var); 1117 instructions().append(dst->index()); 1118 instructions().append(asCell(globalObject)); 1119 instructions().append(index); 1120 return dst; 1121 } 1122 1123 emitOpcode(op_get_scoped_var); 1124 instructions().append(dst->index()); 1125 instructions().append(index); 1126 instructions().append(depth); 1127 return dst; 1128} 1129 1130RegisterID* BytecodeGenerator::emitPutScopedVar(size_t depth, int index, RegisterID* value, JSValue globalObject) 1131{ 1132 if (globalObject) { 1133 emitOpcode(op_put_global_var); 1134 instructions().append(asCell(globalObject)); 1135 instructions().append(index); 1136 instructions().append(value->index()); 1137 return value; 1138 } 1139 emitOpcode(op_put_scoped_var); 1140 instructions().append(index); 1141 instructions().append(depth); 1142 instructions().append(value->index()); 1143 return value; 1144} 1145 1146RegisterID* BytecodeGenerator::emitResolveBase(RegisterID* dst, const Identifier& property) 1147{ 1148 size_t depth = 0; 1149 int index = 0; 1150 JSObject* globalObject = 0; 1151 findScopedProperty(property, index, depth, false, globalObject); 1152 if (!globalObject) { 1153 // We can't optimise at all :-( 1154 emitOpcode(op_resolve_base); 1155 instructions().append(dst->index()); 1156 instructions().append(addConstant(property)); 1157 return dst; 1158 } 1159 1160 // Global object is the base 1161 return emitLoad(dst, JSValue(globalObject)); 1162} 1163 1164RegisterID* BytecodeGenerator::emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property) 1165{ 1166 size_t depth = 0; 1167 int index = 0; 1168 JSObject* globalObject = 0; 1169 if (!findScopedProperty(property, index, depth, false, globalObject) || !globalObject) { 1170 // We can't optimise at all :-( 1171 emitOpcode(op_resolve_with_base); 1172 instructions().append(baseDst->index()); 1173 instructions().append(propDst->index()); 1174 instructions().append(addConstant(property)); 1175 return baseDst; 1176 } 1177 1178 bool forceGlobalResolve = false; 1179 if (m_regeneratingForExceptionInfo) { 1180#if ENABLE(JIT) 1181 forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInfoAtBytecodeOffset(instructions().size()); 1182#else 1183 forceGlobalResolve = m_codeBlockBeingRegeneratedFrom->hasGlobalResolveInstructionAtBytecodeOffset(instructions().size()); 1184#endif 1185 } 1186 1187 // Global object is the base 1188 emitLoad(baseDst, JSValue(globalObject)); 1189 1190 if (index != missingSymbolMarker() && !forceGlobalResolve) { 1191 // Directly index the property lookup across multiple scopes. 1192 emitGetScopedVar(propDst, depth, index, globalObject); 1193 return baseDst; 1194 } 1195 1196#if ENABLE(JIT) 1197 m_codeBlock->addGlobalResolveInfo(instructions().size()); 1198#else 1199 m_codeBlock->addGlobalResolveInstruction(instructions().size()); 1200#endif 1201 emitOpcode(op_resolve_global); 1202 instructions().append(propDst->index()); 1203 instructions().append(globalObject); 1204 instructions().append(addConstant(property)); 1205 instructions().append(0); 1206 instructions().append(0); 1207 return baseDst; 1208} 1209 1210void BytecodeGenerator::emitMethodCheck() 1211{ 1212 emitOpcode(op_method_check); 1213} 1214 1215RegisterID* BytecodeGenerator::emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property) 1216{ 1217#if ENABLE(JIT) 1218 m_codeBlock->addStructureStubInfo(StructureStubInfo(access_get_by_id)); 1219#else 1220 m_codeBlock->addPropertyAccessInstruction(instructions().size()); 1221#endif 1222 1223 emitOpcode(op_get_by_id); 1224 instructions().append(dst->index()); 1225 instructions().append(base->index()); 1226 instructions().append(addConstant(property)); 1227 instructions().append(0); 1228 instructions().append(0); 1229 instructions().append(0); 1230 instructions().append(0); 1231 return dst; 1232} 1233 1234RegisterID* BytecodeGenerator::emitPutById(RegisterID* base, const Identifier& property, RegisterID* value) 1235{ 1236#if ENABLE(JIT) 1237 m_codeBlock->addStructureStubInfo(StructureStubInfo(access_put_by_id)); 1238#else 1239 m_codeBlock->addPropertyAccessInstruction(instructions().size()); 1240#endif 1241 1242 emitOpcode(op_put_by_id); 1243 instructions().append(base->index()); 1244 instructions().append(addConstant(property)); 1245 instructions().append(value->index()); 1246 instructions().append(0); 1247 instructions().append(0); 1248 instructions().append(0); 1249 instructions().append(0); 1250 return value; 1251} 1252 1253RegisterID* BytecodeGenerator::emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value) 1254{ 1255 emitOpcode(op_put_getter); 1256 instructions().append(base->index()); 1257 instructions().append(addConstant(property)); 1258 instructions().append(value->index()); 1259 return value; 1260} 1261 1262RegisterID* BytecodeGenerator::emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value) 1263{ 1264 emitOpcode(op_put_setter); 1265 instructions().append(base->index()); 1266 instructions().append(addConstant(property)); 1267 instructions().append(value->index()); 1268 return value; 1269} 1270 1271RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier& property) 1272{ 1273 emitOpcode(op_del_by_id); 1274 instructions().append(dst->index()); 1275 instructions().append(base->index()); 1276 instructions().append(addConstant(property)); 1277 return dst; 1278} 1279 1280RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property) 1281{ 1282 for (size_t i = m_forInContextStack.size(); i > 0; i--) { 1283 ForInContext& context = m_forInContextStack[i - 1]; 1284 if (context.propertyRegister == property) { 1285 emitOpcode(op_get_by_pname); 1286 instructions().append(dst->index()); 1287 instructions().append(base->index()); 1288 instructions().append(property->index()); 1289 instructions().append(context.expectedSubscriptRegister->index()); 1290 instructions().append(context.iterRegister->index()); 1291 instructions().append(context.indexRegister->index()); 1292 return dst; 1293 } 1294 } 1295 emitOpcode(op_get_by_val); 1296 instructions().append(dst->index()); 1297 instructions().append(base->index()); 1298 instructions().append(property->index()); 1299 return dst; 1300} 1301 1302RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value) 1303{ 1304 emitOpcode(op_put_by_val); 1305 instructions().append(base->index()); 1306 instructions().append(property->index()); 1307 instructions().append(value->index()); 1308 return value; 1309} 1310 1311RegisterID* BytecodeGenerator::emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property) 1312{ 1313 emitOpcode(op_del_by_val); 1314 instructions().append(dst->index()); 1315 instructions().append(base->index()); 1316 instructions().append(property->index()); 1317 return dst; 1318} 1319 1320RegisterID* BytecodeGenerator::emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value) 1321{ 1322 emitOpcode(op_put_by_index); 1323 instructions().append(base->index()); 1324 instructions().append(index); 1325 instructions().append(value->index()); 1326 return value; 1327} 1328 1329RegisterID* BytecodeGenerator::emitNewObject(RegisterID* dst) 1330{ 1331 emitOpcode(op_new_object); 1332 instructions().append(dst->index()); 1333 return dst; 1334} 1335 1336RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elements) 1337{ 1338 Vector<RefPtr<RegisterID>, 16> argv; 1339 for (ElementNode* n = elements; n; n = n->next()) { 1340 if (n->elision()) 1341 break; 1342 argv.append(newTemporary()); 1343 // op_new_array requires the initial values to be a sequential range of registers 1344 ASSERT(argv.size() == 1 || argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1); 1345 emitNode(argv.last().get(), n->value()); 1346 } 1347 emitOpcode(op_new_array); 1348 instructions().append(dst->index()); 1349 instructions().append(argv.size() ? argv[0]->index() : 0); // argv 1350 instructions().append(argv.size()); // argc 1351 return dst; 1352} 1353 1354RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function) 1355{ 1356 unsigned index = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)); 1357 1358 emitOpcode(op_new_func); 1359 instructions().append(dst->index()); 1360 instructions().append(index); 1361 return dst; 1362} 1363 1364RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp) 1365{ 1366 emitOpcode(op_new_regexp); 1367 instructions().append(dst->index()); 1368 instructions().append(addRegExp(regExp)); 1369 return dst; 1370} 1371 1372 1373RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n) 1374{ 1375 FunctionBodyNode* function = n->body(); 1376 unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function)); 1377 1378 emitOpcode(op_new_func_exp); 1379 instructions().append(r0->index()); 1380 instructions().append(index); 1381 return r0; 1382} 1383 1384RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset) 1385{ 1386 return emitCall(op_call, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset); 1387} 1388 1389void BytecodeGenerator::createArgumentsIfNecessary() 1390{ 1391 if (m_codeBlock->usesArguments() && m_codeType == FunctionCode) 1392 emitOpcode(op_create_arguments); 1393} 1394 1395RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset) 1396{ 1397 createArgumentsIfNecessary(); 1398 return emitCall(op_call_eval, dst, func, thisRegister, argumentsNode, divot, startOffset, endOffset); 1399} 1400 1401RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset) 1402{ 1403 ASSERT(opcodeID == op_call || opcodeID == op_call_eval); 1404 ASSERT(func->refCount()); 1405 ASSERT(thisRegister->refCount()); 1406 1407 RegisterID* originalFunc = func; 1408 if (m_shouldEmitProfileHooks) { 1409 // If codegen decided to recycle func as this call's destination register, 1410 // we need to undo that optimization here so that func will still be around 1411 // for the sake of op_profile_did_call. 1412 if (dst == func) { 1413 RefPtr<RegisterID> movedThisRegister = emitMove(newTemporary(), thisRegister); 1414 RefPtr<RegisterID> movedFunc = emitMove(thisRegister, func); 1415 1416 thisRegister = movedThisRegister.release().releaseRef(); 1417 func = movedFunc.release().releaseRef(); 1418 } 1419 } 1420 1421 // Generate code for arguments. 1422 Vector<RefPtr<RegisterID>, 16> argv; 1423 argv.append(thisRegister); 1424 for (ArgumentListNode* n = argumentsNode->m_listNode; n; n = n->m_next) { 1425 argv.append(newTemporary()); 1426 // op_call requires the arguments to be a sequential range of registers 1427 ASSERT(argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1); 1428 emitNode(argv.last().get(), n); 1429 } 1430 1431 // Reserve space for call frame. 1432 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame; 1433 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i) 1434 callFrame.append(newTemporary()); 1435 1436 if (m_shouldEmitProfileHooks) { 1437 emitOpcode(op_profile_will_call); 1438 instructions().append(func->index()); 1439 1440#if ENABLE(JIT) 1441 m_codeBlock->addFunctionRegisterInfo(instructions().size(), func->index()); 1442#endif 1443 } 1444 1445 emitExpressionInfo(divot, startOffset, endOffset); 1446 1447#if ENABLE(JIT) 1448 m_codeBlock->addCallLinkInfo(); 1449#endif 1450 1451 // Emit call. 1452 emitOpcode(opcodeID); 1453 instructions().append(dst->index()); // dst 1454 instructions().append(func->index()); // func 1455 instructions().append(argv.size()); // argCount 1456 instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset 1457 1458 if (m_shouldEmitProfileHooks) { 1459 emitOpcode(op_profile_did_call); 1460 instructions().append(func->index()); 1461 1462 if (dst == originalFunc) { 1463 thisRegister->deref(); 1464 func->deref(); 1465 } 1466 } 1467 1468 return dst; 1469} 1470 1471RegisterID* BytecodeGenerator::emitLoadVarargs(RegisterID* argCountDst, RegisterID* arguments) 1472{ 1473 ASSERT(argCountDst->index() < arguments->index()); 1474 emitOpcode(op_load_varargs); 1475 instructions().append(argCountDst->index()); 1476 instructions().append(arguments->index()); 1477 return argCountDst; 1478} 1479 1480RegisterID* BytecodeGenerator::emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* argCountRegister, unsigned divot, unsigned startOffset, unsigned endOffset) 1481{ 1482 ASSERT(func->refCount()); 1483 ASSERT(thisRegister->refCount()); 1484 ASSERT(dst != func); 1485 if (m_shouldEmitProfileHooks) { 1486 emitOpcode(op_profile_will_call); 1487 instructions().append(func->index()); 1488 1489#if ENABLE(JIT) 1490 m_codeBlock->addFunctionRegisterInfo(instructions().size(), func->index()); 1491#endif 1492 } 1493 1494 emitExpressionInfo(divot, startOffset, endOffset); 1495 1496 // Emit call. 1497 emitOpcode(op_call_varargs); 1498 instructions().append(dst->index()); // dst 1499 instructions().append(func->index()); // func 1500 instructions().append(argCountRegister->index()); // arg count 1501 instructions().append(thisRegister->index() + RegisterFile::CallFrameHeaderSize); // initial registerOffset 1502 if (m_shouldEmitProfileHooks) { 1503 emitOpcode(op_profile_did_call); 1504 instructions().append(func->index()); 1505 } 1506 return dst; 1507} 1508 1509RegisterID* BytecodeGenerator::emitReturn(RegisterID* src) 1510{ 1511 if (m_codeBlock->needsFullScopeChain()) { 1512 emitOpcode(op_tear_off_activation); 1513 instructions().append(m_activationRegisterIndex); 1514 } else if (m_codeBlock->usesArguments() && m_codeBlock->m_numParameters > 1) 1515 emitOpcode(op_tear_off_arguments); 1516 1517 return emitUnaryNoDstOp(op_ret, src); 1518} 1519 1520RegisterID* BytecodeGenerator::emitUnaryNoDstOp(OpcodeID opcodeID, RegisterID* src) 1521{ 1522 emitOpcode(opcodeID); 1523 instructions().append(src->index()); 1524 return src; 1525} 1526 1527RegisterID* BytecodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset) 1528{ 1529 ASSERT(func->refCount()); 1530 1531 RegisterID* originalFunc = func; 1532 if (m_shouldEmitProfileHooks) { 1533 // If codegen decided to recycle func as this call's destination register, 1534 // we need to undo that optimization here so that func will still be around 1535 // for the sake of op_profile_did_call. 1536 if (dst == func) { 1537 RefPtr<RegisterID> movedFunc = emitMove(newTemporary(), func); 1538 func = movedFunc.release().releaseRef(); 1539 } 1540 } 1541 1542 RefPtr<RegisterID> funcProto = newTemporary(); 1543 1544 // Generate code for arguments. 1545 Vector<RefPtr<RegisterID>, 16> argv; 1546 argv.append(newTemporary()); // reserve space for "this" 1547 for (ArgumentListNode* n = argumentsNode ? argumentsNode->m_listNode : 0; n; n = n->m_next) { 1548 argv.append(newTemporary()); 1549 // op_construct requires the arguments to be a sequential range of registers 1550 ASSERT(argv[argv.size() - 1]->index() == argv[argv.size() - 2]->index() + 1); 1551 emitNode(argv.last().get(), n); 1552 } 1553 1554 if (m_shouldEmitProfileHooks) { 1555 emitOpcode(op_profile_will_call); 1556 instructions().append(func->index()); 1557 } 1558 1559 // Load prototype. 1560 emitExpressionInfo(divot, startOffset, endOffset); 1561 emitGetByIdExceptionInfo(op_construct); 1562 emitGetById(funcProto.get(), func, globalData()->propertyNames->prototype); 1563 1564 // Reserve space for call frame. 1565 Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame; 1566 for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i) 1567 callFrame.append(newTemporary()); 1568 1569 emitExpressionInfo(divot, startOffset, endOffset); 1570 1571#if ENABLE(JIT) 1572 m_codeBlock->addCallLinkInfo(); 1573#endif 1574 1575 emitOpcode(op_construct); 1576 instructions().append(dst->index()); // dst 1577 instructions().append(func->index()); // func 1578 instructions().append(argv.size()); // argCount 1579 instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset 1580 instructions().append(funcProto->index()); // proto 1581 instructions().append(argv[0]->index()); // thisRegister 1582 1583 emitOpcode(op_construct_verify); 1584 instructions().append(dst->index()); 1585 instructions().append(argv[0]->index()); 1586 1587 if (m_shouldEmitProfileHooks) { 1588 emitOpcode(op_profile_did_call); 1589 instructions().append(func->index()); 1590 1591 if (dst == originalFunc) 1592 func->deref(); 1593 } 1594 1595 return dst; 1596} 1597 1598RegisterID* BytecodeGenerator::emitStrcat(RegisterID* dst, RegisterID* src, int count) 1599{ 1600 emitOpcode(op_strcat); 1601 instructions().append(dst->index()); 1602 instructions().append(src->index()); 1603 instructions().append(count); 1604 1605 return dst; 1606} 1607 1608void BytecodeGenerator::emitToPrimitive(RegisterID* dst, RegisterID* src) 1609{ 1610 emitOpcode(op_to_primitive); 1611 instructions().append(dst->index()); 1612 instructions().append(src->index()); 1613} 1614 1615RegisterID* BytecodeGenerator::emitPushScope(RegisterID* scope) 1616{ 1617 ASSERT(scope->isTemporary()); 1618 ControlFlowContext context; 1619 context.isFinallyBlock = false; 1620 m_scopeContextStack.append(context); 1621 m_dynamicScopeDepth++; 1622 createArgumentsIfNecessary(); 1623 1624 return emitUnaryNoDstOp(op_push_scope, scope); 1625} 1626 1627void BytecodeGenerator::emitPopScope() 1628{ 1629 ASSERT(m_scopeContextStack.size()); 1630 ASSERT(!m_scopeContextStack.last().isFinallyBlock); 1631 1632 emitOpcode(op_pop_scope); 1633 1634 m_scopeContextStack.removeLast(); 1635 m_dynamicScopeDepth--; 1636} 1637 1638void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, int lastLine) 1639{ 1640 if (!m_shouldEmitDebugHooks) 1641 return; 1642 emitOpcode(op_debug); 1643 instructions().append(debugHookID); 1644 instructions().append(firstLine); 1645 instructions().append(lastLine); 1646} 1647 1648void BytecodeGenerator::pushFinallyContext(Label* target, RegisterID* retAddrDst) 1649{ 1650 ControlFlowContext scope; 1651 scope.isFinallyBlock = true; 1652 FinallyContext context = { target, retAddrDst }; 1653 scope.finallyContext = context; 1654 m_scopeContextStack.append(scope); 1655 m_finallyDepth++; 1656} 1657 1658void BytecodeGenerator::popFinallyContext() 1659{ 1660 ASSERT(m_scopeContextStack.size()); 1661 ASSERT(m_scopeContextStack.last().isFinallyBlock); 1662 ASSERT(m_finallyDepth > 0); 1663 m_scopeContextStack.removeLast(); 1664 m_finallyDepth--; 1665} 1666 1667LabelScope* BytecodeGenerator::breakTarget(const Identifier& name) 1668{ 1669 // Reclaim free label scopes. 1670 // 1671 // The condition was previously coded as 'm_labelScopes.size() && !m_labelScopes.last().refCount()', 1672 // however sometimes this appears to lead to GCC going a little haywire and entering the loop with 1673 // size 0, leading to segfaulty badness. We are yet to identify a valid cause within our code to 1674 // cause the GCC codegen to misbehave in this fashion, and as such the following refactoring of the 1675 // loop condition is a workaround. 1676 while (m_labelScopes.size()) { 1677 if (m_labelScopes.last().refCount()) 1678 break; 1679 m_labelScopes.removeLast(); 1680 } 1681 1682 if (!m_labelScopes.size()) 1683 return 0; 1684 1685 // We special-case the following, which is a syntax error in Firefox: 1686 // label: 1687 // break; 1688 if (name.isEmpty()) { 1689 for (int i = m_labelScopes.size() - 1; i >= 0; --i) { 1690 LabelScope* scope = &m_labelScopes[i]; 1691 if (scope->type() != LabelScope::NamedLabel) { 1692 ASSERT(scope->breakTarget()); 1693 return scope; 1694 } 1695 } 1696 return 0; 1697 } 1698 1699 for (int i = m_labelScopes.size() - 1; i >= 0; --i) { 1700 LabelScope* scope = &m_labelScopes[i]; 1701 if (scope->name() && *scope->name() == name) { 1702 ASSERT(scope->breakTarget()); 1703 return scope; 1704 } 1705 } 1706 return 0; 1707} 1708 1709LabelScope* BytecodeGenerator::continueTarget(const Identifier& name) 1710{ 1711 // Reclaim free label scopes. 1712 while (m_labelScopes.size() && !m_labelScopes.last().refCount()) 1713 m_labelScopes.removeLast(); 1714 1715 if (!m_labelScopes.size()) 1716 return 0; 1717 1718 if (name.isEmpty()) { 1719 for (int i = m_labelScopes.size() - 1; i >= 0; --i) { 1720 LabelScope* scope = &m_labelScopes[i]; 1721 if (scope->type() == LabelScope::Loop) { 1722 ASSERT(scope->continueTarget()); 1723 return scope; 1724 } 1725 } 1726 return 0; 1727 } 1728 1729 // Continue to the loop nested nearest to the label scope that matches 1730 // 'name'. 1731 LabelScope* result = 0; 1732 for (int i = m_labelScopes.size() - 1; i >= 0; --i) { 1733 LabelScope* scope = &m_labelScopes[i]; 1734 if (scope->type() == LabelScope::Loop) { 1735 ASSERT(scope->continueTarget()); 1736 result = scope; 1737 } 1738 if (scope->name() && *scope->name() == name) 1739 return result; // may be 0 1740 } 1741 return 0; 1742} 1743 1744PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope) 1745{ 1746 while (topScope > bottomScope) { 1747 // First we count the number of dynamic scopes we need to remove to get 1748 // to a finally block. 1749 int nNormalScopes = 0; 1750 while (topScope > bottomScope) { 1751 if (topScope->isFinallyBlock) 1752 break; 1753 ++nNormalScopes; 1754 --topScope; 1755 } 1756 1757 if (nNormalScopes) { 1758 size_t begin = instructions().size(); 1759 1760 // We need to remove a number of dynamic scopes to get to the next 1761 // finally block 1762 emitOpcode(op_jmp_scopes); 1763 instructions().append(nNormalScopes); 1764 1765 // If topScope == bottomScope then there isn't actually a finally block 1766 // left to emit, so make the jmp_scopes jump directly to the target label 1767 if (topScope == bottomScope) { 1768 instructions().append(target->bind(begin, instructions().size())); 1769 return target; 1770 } 1771 1772 // Otherwise we just use jmp_scopes to pop a group of scopes and go 1773 // to the next instruction 1774 RefPtr<Label> nextInsn = newLabel(); 1775 instructions().append(nextInsn->bind(begin, instructions().size())); 1776 emitLabel(nextInsn.get()); 1777 } 1778 1779 while (topScope > bottomScope && topScope->isFinallyBlock) { 1780 emitJumpSubroutine(topScope->finallyContext.retAddrDst, topScope->finallyContext.finallyAddr); 1781 --topScope; 1782 } 1783 } 1784 return emitJump(target); 1785} 1786 1787PassRefPtr<Label> BytecodeGenerator::emitJumpScopes(Label* target, int targetScopeDepth) 1788{ 1789 ASSERT(scopeDepth() - targetScopeDepth >= 0); 1790 ASSERT(target->isForward()); 1791 1792 size_t scopeDelta = scopeDepth() - targetScopeDepth; 1793 ASSERT(scopeDelta <= m_scopeContextStack.size()); 1794 if (!scopeDelta) 1795 return emitJump(target); 1796 1797 if (m_finallyDepth) 1798 return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta); 1799 1800 size_t begin = instructions().size(); 1801 1802 emitOpcode(op_jmp_scopes); 1803 instructions().append(scopeDelta); 1804 instructions().append(target->bind(begin, instructions().size())); 1805 return target; 1806} 1807 1808RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget) 1809{ 1810 size_t begin = instructions().size(); 1811 1812 emitOpcode(op_get_pnames); 1813 instructions().append(dst->index()); 1814 instructions().append(base->index()); 1815 instructions().append(i->index()); 1816 instructions().append(size->index()); 1817 instructions().append(breakTarget->bind(begin, instructions().size())); 1818 return dst; 1819} 1820 1821RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target) 1822{ 1823 size_t begin = instructions().size(); 1824 1825 emitOpcode(op_next_pname); 1826 instructions().append(dst->index()); 1827 instructions().append(base->index()); 1828 instructions().append(i->index()); 1829 instructions().append(size->index()); 1830 instructions().append(iter->index()); 1831 instructions().append(target->bind(begin, instructions().size())); 1832 return dst; 1833} 1834 1835RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* start, Label* end) 1836{ 1837#if ENABLE(JIT) 1838 HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() }; 1839#else 1840 HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth }; 1841#endif 1842 1843 m_codeBlock->addExceptionHandler(info); 1844 emitOpcode(op_catch); 1845 instructions().append(targetRegister->index()); 1846 return targetRegister; 1847} 1848 1849RegisterID* BytecodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSValue message) 1850{ 1851 emitOpcode(op_new_error); 1852 instructions().append(dst->index()); 1853 instructions().append(static_cast<int>(type)); 1854 instructions().append(addConstantValue(message)->index()); 1855 return dst; 1856} 1857 1858PassRefPtr<Label> BytecodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, Label* finally) 1859{ 1860 size_t begin = instructions().size(); 1861 1862 emitOpcode(op_jsr); 1863 instructions().append(retAddrDst->index()); 1864 instructions().append(finally->bind(begin, instructions().size())); 1865 emitLabel(newLabel().get()); // Record the fact that the next instruction is implicitly labeled, because op_sret will return to it. 1866 return finally; 1867} 1868 1869void BytecodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc) 1870{ 1871 emitOpcode(op_sret); 1872 instructions().append(retAddrSrc->index()); 1873} 1874 1875void BytecodeGenerator::emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value) 1876{ 1877 ControlFlowContext context; 1878 context.isFinallyBlock = false; 1879 m_scopeContextStack.append(context); 1880 m_dynamicScopeDepth++; 1881 1882 createArgumentsIfNecessary(); 1883 1884 emitOpcode(op_push_new_scope); 1885 instructions().append(dst->index()); 1886 instructions().append(addConstant(property)); 1887 instructions().append(value->index()); 1888} 1889 1890void BytecodeGenerator::beginSwitch(RegisterID* scrutineeRegister, SwitchInfo::SwitchType type) 1891{ 1892 SwitchInfo info = { instructions().size(), type }; 1893 switch (type) { 1894 case SwitchInfo::SwitchImmediate: 1895 emitOpcode(op_switch_imm); 1896 break; 1897 case SwitchInfo::SwitchCharacter: 1898 emitOpcode(op_switch_char); 1899 break; 1900 case SwitchInfo::SwitchString: 1901 emitOpcode(op_switch_string); 1902 break; 1903 default: 1904 ASSERT_NOT_REACHED(); 1905 } 1906 1907 instructions().append(0); // place holder for table index 1908 instructions().append(0); // place holder for default target 1909 instructions().append(scrutineeRegister->index()); 1910 m_switchContextStack.append(info); 1911} 1912 1913static int32_t keyForImmediateSwitch(ExpressionNode* node, int32_t min, int32_t max) 1914{ 1915 UNUSED_PARAM(max); 1916 ASSERT(node->isNumber()); 1917 double value = static_cast<NumberNode*>(node)->value(); 1918 int32_t key = static_cast<int32_t>(value); 1919 ASSERT(key == value); 1920 ASSERT(key >= min); 1921 ASSERT(key <= max); 1922 return key - min; 1923} 1924 1925static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, int32_t min, int32_t max) 1926{ 1927 jumpTable.min = min; 1928 jumpTable.branchOffsets.resize(max - min + 1); 1929 jumpTable.branchOffsets.fill(0); 1930 for (uint32_t i = 0; i < clauseCount; ++i) { 1931 // We're emitting this after the clause labels should have been fixed, so 1932 // the labels should not be "forward" references 1933 ASSERT(!labels[i]->isForward()); 1934 jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3)); 1935 } 1936} 1937 1938static int32_t keyForCharacterSwitch(ExpressionNode* node, int32_t min, int32_t max) 1939{ 1940 UNUSED_PARAM(max); 1941 ASSERT(node->isString()); 1942 UString::Rep* clause = static_cast<StringNode*>(node)->value().ustring().rep(); 1943 ASSERT(clause->size() == 1); 1944 1945 int32_t key = clause->data()[0]; 1946 ASSERT(key >= min); 1947 ASSERT(key <= max); 1948 return key - min; 1949} 1950 1951static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, int32_t min, int32_t max) 1952{ 1953 jumpTable.min = min; 1954 jumpTable.branchOffsets.resize(max - min + 1); 1955 jumpTable.branchOffsets.fill(0); 1956 for (uint32_t i = 0; i < clauseCount; ++i) { 1957 // We're emitting this after the clause labels should have been fixed, so 1958 // the labels should not be "forward" references 1959 ASSERT(!labels[i]->isForward()); 1960 jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3)); 1961 } 1962} 1963 1964static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t switchAddress, uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes) 1965{ 1966 for (uint32_t i = 0; i < clauseCount; ++i) { 1967 // We're emitting this after the clause labels should have been fixed, so 1968 // the labels should not be "forward" references 1969 ASSERT(!labels[i]->isForward()); 1970 1971 ASSERT(nodes[i]->isString()); 1972 UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().ustring().rep(); 1973 OffsetLocation location; 1974 location.branchOffset = labels[i]->bind(switchAddress, switchAddress + 3); 1975 jumpTable.offsetTable.add(clause, location); 1976 } 1977} 1978 1979void BytecodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<Label>* labels, ExpressionNode** nodes, Label* defaultLabel, int32_t min, int32_t max) 1980{ 1981 SwitchInfo switchInfo = m_switchContextStack.last(); 1982 m_switchContextStack.removeLast(); 1983 if (switchInfo.switchType == SwitchInfo::SwitchImmediate) { 1984 instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfImmediateSwitchJumpTables(); 1985 instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); 1986 1987 SimpleJumpTable& jumpTable = m_codeBlock->addImmediateSwitchJumpTable(); 1988 prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max); 1989 } else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) { 1990 instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfCharacterSwitchJumpTables(); 1991 instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); 1992 1993 SimpleJumpTable& jumpTable = m_codeBlock->addCharacterSwitchJumpTable(); 1994 prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max); 1995 } else { 1996 ASSERT(switchInfo.switchType == SwitchInfo::SwitchString); 1997 instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfStringSwitchJumpTables(); 1998 instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); 1999 2000 StringJumpTable& jumpTable = m_codeBlock->addStringSwitchJumpTable(); 2001 prepareJumpTableForStringSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes); 2002 } 2003} 2004 2005RegisterID* BytecodeGenerator::emitThrowExpressionTooDeepException() 2006{ 2007 // It would be nice to do an even better job of identifying exactly where the expression is. 2008 // And we could make the caller pass the node pointer in, if there was some way of getting 2009 // that from an arbitrary node. However, calling emitExpressionInfo without any useful data 2010 // is still good enough to get us an accurate line number. 2011 emitExpressionInfo(0, 0, 0); 2012 RegisterID* exception = emitNewError(newTemporary(), SyntaxError, jsString(globalData(), "Expression too deep")); 2013 emitThrow(exception); 2014 return exception; 2015} 2016 2017} // namespace JSC 2018