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 #ifndef BytecodeGenerator_h 31 #define BytecodeGenerator_h 32 33 #include "CodeBlock.h" 34 #include "HashTraits.h" 35 #include "Instruction.h" 36 #include "Label.h" 37 #include "LabelScope.h" 38 #include "Interpreter.h" 39 #include "RegisterID.h" 40 #include "SymbolTable.h" 41 #include "Debugger.h" 42 #include "Nodes.h" 43 #include <wtf/PassRefPtr.h> 44 #include <wtf/SegmentedVector.h> 45 #include <wtf/Vector.h> 46 47 namespace JSC { 48 49 class Identifier; 50 class ScopeChainNode; 51 52 class CallArguments { 53 public: 54 CallArguments(BytecodeGenerator& generator, ArgumentsNode* argumentsNode); 55 thisRegister()56 RegisterID* thisRegister() { return m_argv[0].get(); } argumentRegister(unsigned i)57 RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); } callFrame()58 unsigned callFrame() { return thisRegister()->index() + count() + RegisterFile::CallFrameHeaderSize; } count()59 unsigned count() { return m_argv.size(); } profileHookRegister()60 RegisterID* profileHookRegister() { return m_profileHookRegister.get(); } argumentsNode()61 ArgumentsNode* argumentsNode() { return m_argumentsNode; } 62 63 private: 64 RefPtr<RegisterID> m_profileHookRegister; 65 ArgumentsNode* m_argumentsNode; 66 Vector<RefPtr<RegisterID>, 16> m_argv; 67 }; 68 69 struct FinallyContext { 70 Label* finallyAddr; 71 RegisterID* retAddrDst; 72 }; 73 74 struct ControlFlowContext { 75 bool isFinallyBlock; 76 FinallyContext finallyContext; 77 }; 78 79 struct ForInContext { 80 RefPtr<RegisterID> expectedSubscriptRegister; 81 RefPtr<RegisterID> iterRegister; 82 RefPtr<RegisterID> indexRegister; 83 RefPtr<RegisterID> propertyRegister; 84 }; 85 86 class BytecodeGenerator { 87 WTF_MAKE_FAST_ALLOCATED; 88 public: 89 typedef DeclarationStacks::VarStack VarStack; 90 typedef DeclarationStacks::FunctionStack FunctionStack; 91 92 static void setDumpsGeneratedCode(bool dumpsGeneratedCode); 93 static bool dumpsGeneratedCode(); 94 95 BytecodeGenerator(ProgramNode*, ScopeChainNode*, SymbolTable*, ProgramCodeBlock*); 96 BytecodeGenerator(FunctionBodyNode*, ScopeChainNode*, SymbolTable*, CodeBlock*); 97 BytecodeGenerator(EvalNode*, ScopeChainNode*, SymbolTable*, EvalCodeBlock*); 98 globalData()99 JSGlobalData* globalData() const { return m_globalData; } propertyNames()100 const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; } 101 isConstructor()102 bool isConstructor() { return m_codeBlock->m_isConstructor; } 103 104 JSObject* generate(); 105 106 // Returns the register corresponding to a local variable, or 0 if no 107 // such register exists. Registers returned by registerFor do not 108 // require explicit reference counting. 109 RegisterID* registerFor(const Identifier&); 110 111 // Returns the agument number if this is an argument, or 0 if not. 112 int argumentNumberFor(const Identifier&); 113 114 void setIsNumericCompareFunction(bool isNumericCompareFunction); 115 116 bool willResolveToArguments(const Identifier&); 117 RegisterID* uncheckedRegisterForArguments(); 118 119 // Behaves as registerFor does, but ignores dynamic scope as 120 // dynamic scope should not interfere with const initialisation 121 RegisterID* constRegisterFor(const Identifier&); 122 123 // Searches the scope chain in an attempt to statically locate the requested 124 // property. Returns false if for any reason the property cannot be safely 125 // optimised at all. Otherwise it will return the index and depth of the 126 // VariableObject that defines the property. If the property cannot be found 127 // statically, depth will contain the depth of the scope chain where dynamic 128 // lookup must begin. 129 bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, bool& includesDynamicScopes, JSObject*& globalObject); 130 131 // Returns the register storing "this" thisRegister()132 RegisterID* thisRegister() { return &m_thisRegister; } 133 134 bool isLocal(const Identifier&); 135 bool isLocalConstant(const Identifier&); 136 137 // Returns the next available temporary register. Registers returned by 138 // newTemporary require a modified form of reference counting: any 139 // register with a refcount of 0 is considered "available", meaning that 140 // the next instruction may overwrite it. 141 RegisterID* newTemporary(); 142 143 RegisterID* highestUsedRegister(); 144 145 // The same as newTemporary(), but this function returns "suggestion" if 146 // "suggestion" is a temporary. This function is helpful in situations 147 // where you've put "suggestion" in a RefPtr, but you'd like to allow 148 // the next instruction to overwrite it anyway. newTemporaryOr(RegisterID * suggestion)149 RegisterID* newTemporaryOr(RegisterID* suggestion) { return suggestion->isTemporary() ? suggestion : newTemporary(); } 150 151 // Functions for handling of dst register 152 ignoredResult()153 RegisterID* ignoredResult() { return &m_ignoredResultRegister; } 154 155 // Returns a place to write intermediate values of an operation 156 // which reuses dst if it is safe to do so. tempDestination(RegisterID * dst)157 RegisterID* tempDestination(RegisterID* dst) 158 { 159 return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary(); 160 } 161 162 // Returns the place to write the final output of an operation. 163 RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0) 164 { 165 if (originalDst && originalDst != ignoredResult()) 166 return originalDst; 167 ASSERT(tempDst != ignoredResult()); 168 if (tempDst && tempDst->isTemporary()) 169 return tempDst; 170 return newTemporary(); 171 } 172 173 // Returns the place to write the final output of an operation. 174 RegisterID* finalDestinationOrIgnored(RegisterID* originalDst, RegisterID* tempDst = 0) 175 { 176 if (originalDst) 177 return originalDst; 178 ASSERT(tempDst != ignoredResult()); 179 if (tempDst && tempDst->isTemporary()) 180 return tempDst; 181 return newTemporary(); 182 } 183 destinationForAssignResult(RegisterID * dst)184 RegisterID* destinationForAssignResult(RegisterID* dst) 185 { 186 if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain()) 187 return dst->isTemporary() ? dst : newTemporary(); 188 return 0; 189 } 190 191 // Moves src to dst if dst is not null and is different from src, otherwise just returns src. moveToDestinationIfNeeded(RegisterID * dst,RegisterID * src)192 RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src) 193 { 194 return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src; 195 } 196 197 PassRefPtr<LabelScope> newLabelScope(LabelScope::Type, const Identifier* = 0); 198 PassRefPtr<Label> newLabel(); 199 200 // The emitNode functions are just syntactic sugar for calling 201 // Node::emitCode. These functions accept a 0 for the register, 202 // meaning that the node should allocate a register, or ignoredResult(), 203 // meaning that the node need not put the result in a register. 204 // Other emit functions do not accept 0 or ignoredResult(). emitNode(RegisterID * dst,Node * n)205 RegisterID* emitNode(RegisterID* dst, Node* n) 206 { 207 // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. 208 ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); 209 addLineInfo(n->lineNo()); 210 return m_stack.recursionCheck() 211 ? n->emitBytecode(*this, dst) 212 : emitThrowExpressionTooDeepException(); 213 } 214 emitNode(Node * n)215 RegisterID* emitNode(Node* n) 216 { 217 return emitNode(0, n); 218 } 219 emitNodeInConditionContext(ExpressionNode * n,Label * trueTarget,Label * falseTarget,bool fallThroughMeansTrue)220 void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) 221 { 222 addLineInfo(n->lineNo()); 223 if (m_stack.recursionCheck()) 224 n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue); 225 else 226 emitThrowExpressionTooDeepException(); 227 } 228 emitExpressionInfo(unsigned divot,unsigned startOffset,unsigned endOffset)229 void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset) 230 { 231 if (!m_shouldEmitRichSourceInfo) 232 return; 233 234 divot -= m_codeBlock->sourceOffset(); 235 if (divot > ExpressionRangeInfo::MaxDivot) { 236 // Overflow has occurred, we can only give line number info for errors for this region 237 divot = 0; 238 startOffset = 0; 239 endOffset = 0; 240 } else if (startOffset > ExpressionRangeInfo::MaxOffset) { 241 // If the start offset is out of bounds we clear both offsets 242 // so we only get the divot marker. Error message will have to be reduced 243 // to line and column number. 244 startOffset = 0; 245 endOffset = 0; 246 } else if (endOffset > ExpressionRangeInfo::MaxOffset) { 247 // The end offset is only used for additional context, and is much more likely 248 // to overflow (eg. function call arguments) so we are willing to drop it without 249 // dropping the rest of the range. 250 endOffset = 0; 251 } 252 253 ExpressionRangeInfo info; 254 info.instructionOffset = instructions().size(); 255 info.divotPoint = divot; 256 info.startOffset = startOffset; 257 info.endOffset = endOffset; 258 m_codeBlock->addExpressionInfo(info); 259 } 260 leftHandSideNeedsCopy(bool rightHasAssignments,bool rightIsPure)261 ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) 262 { 263 return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; 264 } 265 emitNodeForLeftHandSide(ExpressionNode * n,bool rightHasAssignments,bool rightIsPure)266 ALWAYS_INLINE PassRefPtr<RegisterID> emitNodeForLeftHandSide(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure) 267 { 268 if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) { 269 PassRefPtr<RegisterID> dst = newTemporary(); 270 emitNode(dst.get(), n); 271 return dst; 272 } 273 274 return PassRefPtr<RegisterID>(emitNode(n)); 275 } 276 277 RegisterID* emitLoad(RegisterID* dst, bool); 278 RegisterID* emitLoad(RegisterID* dst, double); 279 RegisterID* emitLoad(RegisterID* dst, const Identifier&); 280 RegisterID* emitLoad(RegisterID* dst, JSValue); 281 282 RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src); 283 RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes); 284 RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2); 285 RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src); 286 287 RegisterID* emitNewObject(RegisterID* dst); 288 RegisterID* emitNewArray(RegisterID* dst, ElementNode*); // stops at first elision 289 290 RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode* body); 291 RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body); 292 RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index, bool shouldNullCheck); 293 RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func); 294 RegisterID* emitNewRegExp(RegisterID* dst, PassRefPtr<RegExp> regExp); 295 296 RegisterID* emitMove(RegisterID* dst, RegisterID* src); 297 emitToJSNumber(RegisterID * dst,RegisterID * src)298 RegisterID* emitToJSNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_jsnumber, dst, src); } 299 RegisterID* emitPreInc(RegisterID* srcDst); 300 RegisterID* emitPreDec(RegisterID* srcDst); 301 RegisterID* emitPostInc(RegisterID* dst, RegisterID* srcDst); 302 RegisterID* emitPostDec(RegisterID* dst, RegisterID* srcDst); 303 304 void emitCheckHasInstance(RegisterID* base); 305 RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype); emitTypeOf(RegisterID * dst,RegisterID * src)306 RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } emitIn(RegisterID * dst,RegisterID * property,RegisterID * base)307 RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } 308 309 RegisterID* emitResolve(RegisterID* dst, const Identifier& property); 310 RegisterID* emitGetScopedVar(RegisterID* dst, size_t skip, int index, JSValue globalObject); 311 RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValue globalObject); 312 313 RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property); 314 RegisterID* emitResolveBaseForPut(RegisterID* dst, const Identifier& property); 315 RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property); 316 317 void emitMethodCheck(); 318 319 RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property); 320 RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base); 321 RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value); 322 RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value); 323 RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&); 324 RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property); 325 RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property); 326 RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); 327 RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); 328 RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value); 329 RegisterID* emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value); 330 RegisterID* emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value); 331 332 RegisterID* emitCall(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); 333 RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); 334 RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* argCount, unsigned divot, unsigned startOffset, unsigned endOffset); 335 RegisterID* emitLoadVarargs(RegisterID* argCountDst, RegisterID* thisRegister, RegisterID* args); 336 337 RegisterID* emitReturn(RegisterID* src); emitEnd(RegisterID * src)338 RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); } 339 340 RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); 341 RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count); 342 void emitToPrimitive(RegisterID* dst, RegisterID* src); 343 344 PassRefPtr<Label> emitLabel(Label*); 345 PassRefPtr<Label> emitJump(Label* target); 346 PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target); 347 PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target); 348 PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target); 349 PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target); 350 PassRefPtr<Label> emitJumpScopes(Label* target, int targetScopeDepth); 351 352 PassRefPtr<Label> emitJumpSubroutine(RegisterID* retAddrDst, Label*); 353 void emitSubroutineReturn(RegisterID* retAddrSrc); 354 355 RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget); 356 RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target); 357 358 RegisterID* emitCatch(RegisterID*, Label* start, Label* end); emitThrow(RegisterID * exc)359 void emitThrow(RegisterID* exc) 360 { 361 m_usesExceptions = true; 362 emitUnaryNoDstOp(op_throw, exc); 363 } 364 365 void emitThrowReferenceError(const UString& message); 366 367 void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value); 368 369 RegisterID* emitPushScope(RegisterID* scope); 370 void emitPopScope(); 371 372 void emitDebugHook(DebugHookID, int firstLine, int lastLine); 373 scopeDepth()374 int scopeDepth() { return m_dynamicScopeDepth + m_finallyDepth; } hasFinaliser()375 bool hasFinaliser() { return m_finallyDepth != 0; } 376 377 void pushFinallyContext(Label* target, RegisterID* returnAddrDst); 378 void popFinallyContext(); 379 pushOptimisedForIn(RegisterID * expectedBase,RegisterID * iter,RegisterID * index,RegisterID * propertyRegister)380 void pushOptimisedForIn(RegisterID* expectedBase, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister) 381 { 382 ForInContext context = { expectedBase, iter, index, propertyRegister }; 383 m_forInContextStack.append(context); 384 } 385 popOptimisedForIn()386 void popOptimisedForIn() 387 { 388 m_forInContextStack.removeLast(); 389 } 390 391 LabelScope* breakTarget(const Identifier&); 392 LabelScope* continueTarget(const Identifier&); 393 394 void beginSwitch(RegisterID*, SwitchInfo::SwitchType); 395 void endSwitch(uint32_t clauseCount, RefPtr<Label>*, ExpressionNode**, Label* defaultLabel, int32_t min, int32_t range); 396 codeType()397 CodeType codeType() const { return m_codeType; } 398 shouldEmitProfileHooks()399 bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; } 400 isStrictMode()401 bool isStrictMode() const { return m_codeBlock->isStrictMode(); } 402 403 private: 404 void emitOpcode(OpcodeID); 405 void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); 406 void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); 407 ALWAYS_INLINE void rewindBinaryOp(); 408 ALWAYS_INLINE void rewindUnaryOp(); 409 410 PassRefPtr<Label> emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope); 411 412 typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap; 413 414 struct IdentifierMapIndexHashTraits { 415 typedef int TraitType; 416 typedef IdentifierMapIndexHashTraits StorageTraits; emptyValueIdentifierMapIndexHashTraits417 static int emptyValue() { return std::numeric_limits<int>::max(); } 418 static const bool emptyValueIsZero = false; 419 static const bool needsDestruction = false; 420 static const bool needsRef = false; 421 }; 422 423 typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, IdentifierMapIndexHashTraits> IdentifierMap; 424 typedef HashMap<double, JSValue> NumberMap; 425 typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; 426 427 RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, CallArguments&, unsigned divot, unsigned startOffset, unsigned endOffset); 428 429 RegisterID* newRegister(); 430 431 // Adds a var slot and maps it to the name ident in symbolTable(). addVar(const Identifier & ident,bool isConstant)432 RegisterID* addVar(const Identifier& ident, bool isConstant) 433 { 434 RegisterID* local; 435 addVar(ident, isConstant, local); 436 return local; 437 } 438 439 // Ditto. Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. 440 bool addVar(const Identifier&, bool isConstant, RegisterID*&); 441 442 // Adds an anonymous var slot. To give this slot a name, add it to symbolTable(). addVar()443 RegisterID* addVar() 444 { 445 ++m_codeBlock->m_numVars; 446 return newRegister(); 447 } 448 449 // Returns the RegisterID corresponding to ident. addGlobalVar(const Identifier & ident,bool isConstant)450 RegisterID* addGlobalVar(const Identifier& ident, bool isConstant) 451 { 452 RegisterID* local; 453 addGlobalVar(ident, isConstant, local); 454 return local; 455 } 456 // Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. 457 bool addGlobalVar(const Identifier&, bool isConstant, RegisterID*&); 458 459 void addParameter(const Identifier&, int parameterIndex); 460 461 void preserveLastVar(); 462 registerFor(int index)463 RegisterID& registerFor(int index) 464 { 465 if (index >= 0) 466 return m_calleeRegisters[index]; 467 468 if (m_parameters.size()) { 469 ASSERT(!m_globals.size()); 470 return m_parameters[index + m_parameters.size() + RegisterFile::CallFrameHeaderSize]; 471 } 472 473 return m_globals[-index - 1]; 474 } 475 476 unsigned addConstant(const Identifier&); 477 RegisterID* addConstantValue(JSValue); 478 unsigned addRegExp(PassRefPtr<RegExp>); 479 makeFunction(ExecState * exec,FunctionBodyNode * body)480 FunctionExecutable* makeFunction(ExecState* exec, FunctionBodyNode* body) 481 { 482 return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); 483 } 484 makeFunction(JSGlobalData * globalData,FunctionBodyNode * body)485 FunctionExecutable* makeFunction(JSGlobalData* globalData, FunctionBodyNode* body) 486 { 487 return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine()); 488 } 489 addLineInfo(unsigned lineNo)490 void addLineInfo(unsigned lineNo) 491 { 492 #if !ENABLE(OPCODE_SAMPLING) 493 if (m_shouldEmitRichSourceInfo) 494 #endif 495 m_codeBlock->addLineInfo(instructions().size(), lineNo); 496 } 497 498 RegisterID* emitInitLazyRegister(RegisterID*); 499 instructions()500 Vector<Instruction>& instructions() { return m_codeBlock->instructions(); } symbolTable()501 SymbolTable& symbolTable() { return *m_symbolTable; } 502 shouldOptimizeLocals()503 bool shouldOptimizeLocals() { return (m_codeType != EvalCode) && !m_dynamicScopeDepth; } canOptimizeNonLocals()504 bool canOptimizeNonLocals() { return (m_codeType == FunctionCode) && !m_dynamicScopeDepth && !m_codeBlock->usesEval(); } 505 506 RegisterID* emitThrowExpressionTooDeepException(); 507 508 void createArgumentsIfNecessary(); 509 void createActivationIfNecessary(); 510 RegisterID* createLazyRegisterIfNecessary(RegisterID*); 511 512 bool m_shouldEmitDebugHooks; 513 bool m_shouldEmitProfileHooks; 514 bool m_shouldEmitRichSourceInfo; 515 516 Strong<ScopeChainNode> m_scopeChain; 517 SymbolTable* m_symbolTable; 518 519 ScopeNode* m_scopeNode; 520 CodeBlock* m_codeBlock; 521 522 // Some of these objects keep pointers to one another. They are arranged 523 // to ensure a sane destruction order that avoids references to freed memory. 524 HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions; 525 RegisterID m_ignoredResultRegister; 526 RegisterID m_thisRegister; 527 RegisterID* m_activationRegister; 528 SegmentedVector<RegisterID, 32> m_constantPoolRegisters; 529 SegmentedVector<RegisterID, 32> m_calleeRegisters; 530 SegmentedVector<RegisterID, 32> m_parameters; 531 SegmentedVector<RegisterID, 32> m_globals; 532 SegmentedVector<Label, 32> m_labels; 533 SegmentedVector<LabelScope, 8> m_labelScopes; 534 RefPtr<RegisterID> m_lastVar; 535 int m_finallyDepth; 536 int m_dynamicScopeDepth; 537 int m_baseScopeDepth; 538 CodeType m_codeType; 539 540 Vector<ControlFlowContext> m_scopeContextStack; 541 Vector<SwitchInfo> m_switchContextStack; 542 Vector<ForInContext> m_forInContextStack; 543 544 int m_nextGlobalIndex; 545 int m_firstConstantIndex; 546 int m_nextConstantOffset; 547 unsigned m_globalConstantIndex; 548 549 int m_globalVarStorageOffset; 550 551 bool m_hasCreatedActivation; 552 int m_firstLazyFunction; 553 int m_lastLazyFunction; 554 HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int> > m_lazyFunctions; 555 typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap; 556 FunctionOffsetMap m_functionOffsets; 557 558 // Constant pool 559 IdentifierMap m_identifierMap; 560 JSValueMap m_jsValueMap; 561 NumberMap m_numberMap; 562 IdentifierStringMap m_stringMap; 563 564 JSGlobalData* m_globalData; 565 566 OpcodeID m_lastOpcodeID; 567 #ifndef NDEBUG 568 size_t m_lastOpcodePosition; 569 #endif 570 571 StackBounds m_stack; 572 573 bool m_usesExceptions; 574 bool m_expressionTooDeep; 575 }; 576 577 } 578 579 #endif // BytecodeGenerator_h 580