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 "SegmentedVector.h" 41 #include "SymbolTable.h" 42 #include "Debugger.h" 43 #include "Nodes.h" 44 #include <wtf/PassRefPtr.h> 45 #include <wtf/Vector.h> 46 47 namespace JSC { 48 49 class Identifier; 50 class ScopeChain; 51 class ScopeNode; 52 53 struct FinallyContext { 54 Label* finallyAddr; 55 RegisterID* retAddrDst; 56 }; 57 58 struct ControlFlowContext { 59 bool isFinallyBlock; 60 FinallyContext finallyContext; 61 }; 62 63 class BytecodeGenerator { 64 public: 65 typedef DeclarationStacks::VarStack VarStack; 66 typedef DeclarationStacks::FunctionStack FunctionStack; 67 68 static void setDumpsGeneratedCode(bool dumpsGeneratedCode); 69 static bool dumpsGeneratedCode(); 70 71 BytecodeGenerator(ProgramNode*, const Debugger*, const ScopeChain&, SymbolTable*, ProgramCodeBlock*); 72 BytecodeGenerator(FunctionBodyNode*, const Debugger*, const ScopeChain&, SymbolTable*, CodeBlock*); 73 BytecodeGenerator(EvalNode*, const Debugger*, const ScopeChain&, SymbolTable*, EvalCodeBlock*); 74 globalData()75 JSGlobalData* globalData() const { return m_globalData; } propertyNames()76 const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; } 77 78 void generate(); 79 80 // Returns the register corresponding to a local variable, or 0 if no 81 // such register exists. Registers returned by registerFor do not 82 // require explicit reference counting. 83 RegisterID* registerFor(const Identifier&); 84 85 // Behaves as registerFor does, but ignores dynamic scope as 86 // dynamic scope should not interfere with const initialisation 87 RegisterID* constRegisterFor(const Identifier&); 88 89 // Searches the scope chain in an attempt to statically locate the requested 90 // property. Returns false if for any reason the property cannot be safely 91 // optimised at all. Otherwise it will return the index and depth of the 92 // VariableObject that defines the property. If the property cannot be found 93 // statically, depth will contain the depth of the scope chain where dynamic 94 // lookup must begin. 95 // 96 // NB: depth does _not_ include the local scope. eg. a depth of 0 refers 97 // to the scope containing this codeblock. 98 bool findScopedProperty(const Identifier&, int& index, size_t& depth, bool forWriting, JSObject*& globalObject); 99 100 // Returns the register storing "this" thisRegister()101 RegisterID* thisRegister() { return &m_thisRegister; } 102 103 bool isLocal(const Identifier&); 104 bool isLocalConstant(const Identifier&); 105 106 // Returns the next available temporary register. Registers returned by 107 // newTemporary require a modified form of reference counting: any 108 // register with a refcount of 0 is considered "available", meaning that 109 // the next instruction may overwrite it. 110 RegisterID* newTemporary(); 111 112 RegisterID* highestUsedRegister(); 113 114 // The same as newTemporary(), but this function returns "suggestion" if 115 // "suggestion" is a temporary. This function is helpful in situations 116 // where you've put "suggestion" in a RefPtr, but you'd like to allow 117 // the next instruction to overwrite it anyway. newTemporaryOr(RegisterID * suggestion)118 RegisterID* newTemporaryOr(RegisterID* suggestion) { return suggestion->isTemporary() ? suggestion : newTemporary(); } 119 120 // Functions for handling of dst register 121 ignoredResult()122 RegisterID* ignoredResult() { return &m_ignoredResultRegister; } 123 124 // Returns a place to write intermediate values of an operation 125 // which reuses dst if it is safe to do so. tempDestination(RegisterID * dst)126 RegisterID* tempDestination(RegisterID* dst) 127 { 128 return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary(); 129 } 130 131 // Returns the place to write the final output of an operation. 132 RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0) 133 { 134 if (originalDst && originalDst != ignoredResult()) 135 return originalDst; 136 ASSERT(tempDst != ignoredResult()); 137 if (tempDst && tempDst->isTemporary()) 138 return tempDst; 139 return newTemporary(); 140 } 141 destinationForAssignResult(RegisterID * dst)142 RegisterID* destinationForAssignResult(RegisterID* dst) 143 { 144 if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain()) 145 return dst->isTemporary() ? dst : newTemporary(); 146 return 0; 147 } 148 149 // Moves src to dst if dst is not null and is different from src, otherwise just returns src. moveToDestinationIfNeeded(RegisterID * dst,RegisterID * src)150 RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src) 151 { 152 return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src; 153 } 154 155 PassRefPtr<LabelScope> newLabelScope(LabelScope::Type, const Identifier* = 0); 156 PassRefPtr<Label> newLabel(); 157 158 // The emitNode functions are just syntactic sugar for calling 159 // Node::emitCode. These functions accept a 0 for the register, 160 // meaning that the node should allocate a register, or ignoredResult(), 161 // meaning that the node need not put the result in a register. 162 // Other emit functions do not accept 0 or ignoredResult(). emitNode(RegisterID * dst,Node * n)163 RegisterID* emitNode(RegisterID* dst, Node* n) 164 { 165 // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. 166 ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); 167 if (!m_codeBlock->numberOfLineInfos() || m_codeBlock->lastLineInfo().lineNumber != n->lineNo()) { 168 LineInfo info = { instructions().size(), n->lineNo() }; 169 m_codeBlock->addLineInfo(info); 170 } 171 if (m_emitNodeDepth >= s_maxEmitNodeDepth) 172 return emitThrowExpressionTooDeepException(); 173 ++m_emitNodeDepth; 174 RegisterID* r = n->emitBytecode(*this, dst); 175 --m_emitNodeDepth; 176 return r; 177 } 178 emitNode(Node * n)179 RegisterID* emitNode(Node* n) 180 { 181 return emitNode(0, n); 182 } 183 emitExpressionInfo(unsigned divot,unsigned startOffset,unsigned endOffset)184 void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset) 185 { 186 divot -= m_codeBlock->sourceOffset(); 187 if (divot > ExpressionRangeInfo::MaxDivot) { 188 // Overflow has occurred, we can only give line number info for errors for this region 189 divot = 0; 190 startOffset = 0; 191 endOffset = 0; 192 } else if (startOffset > ExpressionRangeInfo::MaxOffset) { 193 // If the start offset is out of bounds we clear both offsets 194 // so we only get the divot marker. Error message will have to be reduced 195 // to line and column number. 196 startOffset = 0; 197 endOffset = 0; 198 } else if (endOffset > ExpressionRangeInfo::MaxOffset) { 199 // The end offset is only used for additional context, and is much more likely 200 // to overflow (eg. function call arguments) so we are willing to drop it without 201 // dropping the rest of the range. 202 endOffset = 0; 203 } 204 205 ExpressionRangeInfo info; 206 info.instructionOffset = instructions().size(); 207 info.divotPoint = divot; 208 info.startOffset = startOffset; 209 info.endOffset = endOffset; 210 m_codeBlock->addExpressionInfo(info); 211 } 212 emitGetByIdExceptionInfo(OpcodeID opcodeID)213 void emitGetByIdExceptionInfo(OpcodeID opcodeID) 214 { 215 // Only op_construct and op_instanceof need exception info for 216 // a preceding op_get_by_id. 217 ASSERT(opcodeID == op_construct || opcodeID == op_instanceof); 218 GetByIdExceptionInfo info; 219 info.bytecodeOffset = instructions().size(); 220 info.isOpConstruct = (opcodeID == op_construct); 221 m_codeBlock->addGetByIdExceptionInfo(info); 222 } 223 leftHandSideNeedsCopy(bool rightHasAssignments,bool rightIsPure)224 ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) 225 { 226 return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; 227 } 228 emitNodeForLeftHandSide(ExpressionNode * n,bool rightHasAssignments,bool rightIsPure)229 ALWAYS_INLINE PassRefPtr<RegisterID> emitNodeForLeftHandSide(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure) 230 { 231 if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) { 232 PassRefPtr<RegisterID> dst = newTemporary(); 233 emitNode(dst.get(), n); 234 return dst; 235 } 236 237 return PassRefPtr<RegisterID>(emitNode(n)); 238 } 239 240 RegisterID* emitLoad(RegisterID* dst, bool); 241 RegisterID* emitLoad(RegisterID* dst, double); 242 RegisterID* emitLoad(RegisterID* dst, const Identifier&); 243 RegisterID* emitLoad(RegisterID* dst, JSValuePtr); 244 RegisterID* emitUnexpectedLoad(RegisterID* dst, bool); 245 RegisterID* emitUnexpectedLoad(RegisterID* dst, double); 246 247 RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src); 248 RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes); 249 RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2); 250 RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src); 251 252 RegisterID* emitNewObject(RegisterID* dst); 253 RegisterID* emitNewArray(RegisterID* dst, ElementNode*); // stops at first elision 254 255 RegisterID* emitNewFunction(RegisterID* dst, FuncDeclNode* func); 256 RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func); 257 RegisterID* emitNewRegExp(RegisterID* dst, RegExp* regExp); 258 259 RegisterID* emitMove(RegisterID* dst, RegisterID* src); 260 emitToJSNumber(RegisterID * dst,RegisterID * src)261 RegisterID* emitToJSNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_jsnumber, dst, src); } 262 RegisterID* emitPreInc(RegisterID* srcDst); 263 RegisterID* emitPreDec(RegisterID* srcDst); 264 RegisterID* emitPostInc(RegisterID* dst, RegisterID* srcDst); 265 RegisterID* emitPostDec(RegisterID* dst, RegisterID* srcDst); 266 267 RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* base, RegisterID* basePrototype); emitTypeOf(RegisterID * dst,RegisterID * src)268 RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } emitIn(RegisterID * dst,RegisterID * property,RegisterID * base)269 RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } 270 271 RegisterID* emitResolve(RegisterID* dst, const Identifier& property); 272 RegisterID* emitGetScopedVar(RegisterID* dst, size_t skip, int index, JSValuePtr globalObject); 273 RegisterID* emitPutScopedVar(size_t skip, int index, RegisterID* value, JSValuePtr globalObject); 274 275 RegisterID* emitResolveBase(RegisterID* dst, const Identifier& property); 276 RegisterID* emitResolveWithBase(RegisterID* baseDst, RegisterID* propDst, const Identifier& property); 277 RegisterID* emitResolveFunction(RegisterID* baseDst, RegisterID* funcDst, const Identifier& property); 278 279 RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property); 280 RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value); 281 RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&); 282 RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property); 283 RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); 284 RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); 285 RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value); 286 RegisterID* emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value); 287 RegisterID* emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value); 288 289 RegisterID* emitCall(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); 290 RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); 291 292 RegisterID* emitReturn(RegisterID* src); emitEnd(RegisterID * src)293 RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); } 294 295 RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); 296 297 PassRefPtr<Label> emitLabel(Label*); 298 PassRefPtr<Label> emitJump(Label* target); 299 PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target); 300 PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target); 301 PassRefPtr<Label> emitJumpScopes(Label* target, int targetScopeDepth); 302 303 PassRefPtr<Label> emitJumpSubroutine(RegisterID* retAddrDst, Label*); 304 void emitSubroutineReturn(RegisterID* retAddrSrc); 305 emitGetPropertyNames(RegisterID * dst,RegisterID * base)306 RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base) { return emitUnaryOp(op_get_pnames, dst, base); } 307 RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* iter, Label* target); 308 309 RegisterID* emitCatch(RegisterID*, Label* start, Label* end); emitThrow(RegisterID * exc)310 void emitThrow(RegisterID* exc) { emitUnaryNoDstOp(op_throw, exc); } 311 RegisterID* emitNewError(RegisterID* dst, ErrorType type, JSValuePtr message); 312 void emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value); 313 314 RegisterID* emitPushScope(RegisterID* scope); 315 void emitPopScope(); 316 317 void emitDebugHook(DebugHookID, int firstLine, int lastLine); 318 scopeDepth()319 int scopeDepth() { return m_dynamicScopeDepth + m_finallyDepth; } 320 321 void pushFinallyContext(Label* target, RegisterID* returnAddrDst); 322 void popFinallyContext(); 323 324 LabelScope* breakTarget(const Identifier&); 325 LabelScope* continueTarget(const Identifier&); 326 327 void beginSwitch(RegisterID*, SwitchInfo::SwitchType); 328 void endSwitch(uint32_t clauseCount, RefPtr<Label>*, ExpressionNode**, Label* defaultLabel, int32_t min, int32_t range); 329 codeType()330 CodeType codeType() const { return m_codeType; } 331 setRegeneratingForExceptionInfo(CodeBlock * originalCodeBlock)332 void setRegeneratingForExceptionInfo(CodeBlock* originalCodeBlock) 333 { 334 m_regeneratingForExceptionInfo = true; 335 m_codeBlockBeingRegeneratedFrom = originalCodeBlock; 336 } 337 338 private: 339 void emitOpcode(OpcodeID); 340 void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); 341 void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); 342 void rewindBinaryOp(); 343 void rewindUnaryOp(); 344 345 PassRefPtr<Label> emitComplexJumpScopes(Label* target, ControlFlowContext* topScope, ControlFlowContext* bottomScope); 346 347 struct JSValueHashTraits : HashTraits<JSValueEncodedAsPointer*> { constructDeletedValueJSValueHashTraits348 static void constructDeletedValue(JSValueEncodedAsPointer*& slot) { slot = JSValuePtr::encode(jsImpossibleValue()); } isDeletedValueJSValueHashTraits349 static bool isDeletedValue(JSValueEncodedAsPointer* value) { return value == JSValuePtr::encode(jsImpossibleValue()); } 350 }; 351 352 typedef HashMap<JSValueEncodedAsPointer*, unsigned, PtrHash<JSValueEncodedAsPointer*>, JSValueHashTraits> JSValueMap; 353 354 struct IdentifierMapIndexHashTraits { 355 typedef int TraitType; 356 typedef IdentifierMapIndexHashTraits StorageTraits; emptyValueIdentifierMapIndexHashTraits357 static int emptyValue() { return std::numeric_limits<int>::max(); } 358 static const bool emptyValueIsZero = false; 359 static const bool needsDestruction = false; 360 static const bool needsRef = false; 361 }; 362 363 typedef HashMap<RefPtr<UString::Rep>, int, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, IdentifierMapIndexHashTraits> IdentifierMap; 364 typedef HashMap<double, JSValuePtr> NumberMap; 365 typedef HashMap<UString::Rep*, JSString*, IdentifierRepHash> IdentifierStringMap; 366 367 RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); 368 369 RegisterID* newRegister(); 370 371 // Returns the RegisterID corresponding to ident. addVar(const Identifier & ident,bool isConstant)372 RegisterID* addVar(const Identifier& ident, bool isConstant) 373 { 374 RegisterID* local; 375 addVar(ident, isConstant, local); 376 return local; 377 } 378 // Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. 379 bool addVar(const Identifier&, bool isConstant, RegisterID*&); 380 381 // Returns the RegisterID corresponding to ident. addGlobalVar(const Identifier & ident,bool isConstant)382 RegisterID* addGlobalVar(const Identifier& ident, bool isConstant) 383 { 384 RegisterID* local; 385 addGlobalVar(ident, isConstant, local); 386 return local; 387 } 388 // Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. 389 bool addGlobalVar(const Identifier&, bool isConstant, RegisterID*&); 390 391 RegisterID* addParameter(const Identifier&); 392 393 void allocateConstants(size_t); 394 registerFor(int index)395 RegisterID& registerFor(int index) 396 { 397 if (index >= 0) 398 return m_calleeRegisters[index]; 399 400 if (index == RegisterFile::OptionalCalleeArguments) 401 return m_argumentsRegister; 402 403 if (m_parameters.size()) { 404 ASSERT(!m_globals.size()); 405 return m_parameters[index + m_parameters.size() + RegisterFile::CallFrameHeaderSize]; 406 } 407 408 return m_globals[-index - 1]; 409 } 410 411 unsigned addConstant(FuncDeclNode*); 412 unsigned addConstant(FuncExprNode*); 413 unsigned addConstant(const Identifier&); 414 RegisterID* addConstant(JSValuePtr); 415 unsigned addUnexpectedConstant(JSValuePtr); 416 unsigned addRegExp(RegExp*); 417 instructions()418 Vector<Instruction>& instructions() { return m_codeBlock->instructions(); } symbolTable()419 SymbolTable& symbolTable() { return *m_symbolTable; } 420 shouldOptimizeLocals()421 bool shouldOptimizeLocals() { return (m_codeType != EvalCode) && !m_dynamicScopeDepth; } canOptimizeNonLocals()422 bool canOptimizeNonLocals() { return (m_codeType == FunctionCode) && !m_dynamicScopeDepth && !m_codeBlock->usesEval(); } 423 424 RegisterID* emitThrowExpressionTooDeepException(); 425 426 bool m_shouldEmitDebugHooks; 427 bool m_shouldEmitProfileHooks; 428 429 const ScopeChain* m_scopeChain; 430 SymbolTable* m_symbolTable; 431 432 ScopeNode* m_scopeNode; 433 CodeBlock* m_codeBlock; 434 435 HashSet<RefPtr<UString::Rep>, IdentifierRepHash> m_functions; 436 RegisterID m_ignoredResultRegister; 437 RegisterID m_thisRegister; 438 RegisterID m_argumentsRegister; 439 int m_activationRegisterIndex; 440 SegmentedVector<RegisterID, 512> m_calleeRegisters; 441 SegmentedVector<RegisterID, 512> m_parameters; 442 SegmentedVector<RegisterID, 512> m_globals; 443 SegmentedVector<LabelScope, 256> m_labelScopes; 444 SegmentedVector<Label, 256> m_labels; 445 RefPtr<RegisterID> m_lastConstant; 446 int m_finallyDepth; 447 int m_dynamicScopeDepth; 448 int m_baseScopeDepth; 449 CodeType m_codeType; 450 451 Vector<ControlFlowContext> m_scopeContextStack; 452 Vector<SwitchInfo> m_switchContextStack; 453 454 int m_nextGlobalIndex; 455 int m_nextParameterIndex; 456 int m_nextConstantIndex; 457 458 int m_globalVarStorageOffset; 459 460 // Constant pool 461 IdentifierMap m_identifierMap; 462 JSValueMap m_jsValueMap; 463 NumberMap m_numberMap; 464 IdentifierStringMap m_stringMap; 465 466 JSGlobalData* m_globalData; 467 468 OpcodeID m_lastOpcodeID; 469 470 unsigned m_emitNodeDepth; 471 472 bool m_regeneratingForExceptionInfo; 473 CodeBlock* m_codeBlockBeingRegeneratedFrom; 474 475 static const unsigned s_maxEmitNodeDepth = 10000; 476 }; 477 478 } 479 480 #endif // BytecodeGenerator_h 481