1/* 2 * Copyright (C) 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> 4 * Copyright (C) 2012 Igalia, S.L. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 16 * its contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#ifndef BytecodeGenerator_h 32#define BytecodeGenerator_h 33 34#include "CodeBlock.h" 35#include <wtf/HashTraits.h> 36#include "Instruction.h" 37#include "Label.h" 38#include "LabelScope.h" 39#include "Interpreter.h" 40#include "ParserError.h" 41#include "RegisterID.h" 42#include "SymbolTable.h" 43#include "Debugger.h" 44#include "Nodes.h" 45#include "StaticPropertyAnalyzer.h" 46#include "UnlinkedCodeBlock.h" 47 48#include <functional> 49 50#include <wtf/PassRefPtr.h> 51#include <wtf/SegmentedVector.h> 52#include <wtf/Vector.h> 53 54 55namespace JSC { 56 57 class Identifier; 58 class Label; 59 60 enum ExpectedFunction { 61 NoExpectedFunction, 62 ExpectObjectConstructor, 63 ExpectArrayConstructor 64 }; 65 66 class CallArguments { 67 public: 68 CallArguments(BytecodeGenerator&, ArgumentsNode*, unsigned additionalArguments = 0); 69 70 RegisterID* thisRegister() { return m_argv[0].get(); } 71 RegisterID* argumentRegister(unsigned i) { return m_argv[i + 1].get(); } 72 unsigned stackOffset() { return -m_argv[0]->index() + JSStack::CallFrameHeaderSize; } 73 unsigned argumentCountIncludingThis() { return m_argv.size() - m_padding; } 74 RegisterID* profileHookRegister() { return m_profileHookRegister.get(); } 75 ArgumentsNode* argumentsNode() { return m_argumentsNode; } 76 77 private: 78 RefPtr<RegisterID> m_profileHookRegister; 79 ArgumentsNode* m_argumentsNode; 80 Vector<RefPtr<RegisterID>, 8, UnsafeVectorOverflow> m_argv; 81 unsigned m_padding; 82 }; 83 84 struct FinallyContext { 85 StatementNode* finallyBlock; 86 unsigned scopeContextStackSize; 87 unsigned switchContextStackSize; 88 unsigned forInContextStackSize; 89 unsigned tryContextStackSize; 90 unsigned labelScopesSize; 91 int finallyDepth; 92 int dynamicScopeDepth; 93 }; 94 95 struct ControlFlowContext { 96 bool isFinallyBlock; 97 FinallyContext finallyContext; 98 }; 99 100 struct ForInContext { 101 RefPtr<RegisterID> expectedSubscriptRegister; 102 RefPtr<RegisterID> iterRegister; 103 RefPtr<RegisterID> indexRegister; 104 RefPtr<RegisterID> propertyRegister; 105 }; 106 107 struct TryData { 108 RefPtr<Label> target; 109 unsigned targetScopeDepth; 110 }; 111 112 struct TryContext { 113 RefPtr<Label> start; 114 TryData* tryData; 115 }; 116 117 enum CaptureMode { 118 NotCaptured, 119 IsCaptured 120 }; 121 122 class Local { 123 public: 124 Local() 125 : m_local(0) 126 , m_attributes(0) 127 { 128 } 129 130 Local(RegisterID* local, unsigned attributes, CaptureMode captureMode) 131 : m_local(local) 132 , m_attributes(attributes) 133 , m_isCaptured(captureMode == IsCaptured) 134 { 135 } 136 137 operator bool() { return m_local; } 138 139 RegisterID* get() { return m_local; } 140 141 bool isReadOnly() { return m_attributes & ReadOnly; } 142 143 bool isCaptured() { return m_isCaptured; } 144 CaptureMode captureMode() { return isCaptured() ? IsCaptured : NotCaptured; } 145 146 private: 147 RegisterID* m_local; 148 unsigned m_attributes; 149 bool m_isCaptured; 150 }; 151 152 struct TryRange { 153 RefPtr<Label> start; 154 RefPtr<Label> end; 155 TryData* tryData; 156 }; 157 158 class BytecodeGenerator { 159 WTF_MAKE_FAST_ALLOCATED; 160 public: 161 typedef DeclarationStacks::VarStack VarStack; 162 typedef DeclarationStacks::FunctionStack FunctionStack; 163 164 BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode); 165 BytecodeGenerator(VM&, FunctionBodyNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode); 166 BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode); 167 168 ~BytecodeGenerator(); 169 170 VM* vm() const { return m_vm; } 171 const CommonIdentifiers& propertyNames() const { return *m_vm->propertyNames; } 172 173 bool isConstructor() { return m_codeBlock->isConstructor(); } 174 175 ParserError generate(); 176 177 bool isArgumentNumber(const Identifier&, int); 178 179 void setIsNumericCompareFunction(bool isNumericCompareFunction); 180 181 bool willResolveToArguments(const Identifier&); 182 RegisterID* uncheckedRegisterForArguments(); 183 184 bool isCaptured(int operand); 185 CaptureMode captureMode(int operand) { return isCaptured(operand) ? IsCaptured : NotCaptured; } 186 187 Local local(const Identifier&); 188 Local constLocal(const Identifier&); 189 190 // Returns the register storing "this" 191 RegisterID* thisRegister() { return &m_thisRegister; } 192 193 // Returns the next available temporary register. Registers returned by 194 // newTemporary require a modified form of reference counting: any 195 // register with a refcount of 0 is considered "available", meaning that 196 // the next instruction may overwrite it. 197 RegisterID* newTemporary(); 198 199 // The same as newTemporary(), but this function returns "suggestion" if 200 // "suggestion" is a temporary. This function is helpful in situations 201 // where you've put "suggestion" in a RefPtr, but you'd like to allow 202 // the next instruction to overwrite it anyway. 203 RegisterID* newTemporaryOr(RegisterID* suggestion) { return suggestion->isTemporary() ? suggestion : newTemporary(); } 204 205 // Functions for handling of dst register 206 207 RegisterID* ignoredResult() { return &m_ignoredResultRegister; } 208 209 // Returns a place to write intermediate values of an operation 210 // which reuses dst if it is safe to do so. 211 RegisterID* tempDestination(RegisterID* dst) 212 { 213 return (dst && dst != ignoredResult() && dst->isTemporary()) ? dst : newTemporary(); 214 } 215 216 // Returns the place to write the final output of an operation. 217 RegisterID* finalDestination(RegisterID* originalDst, RegisterID* tempDst = 0) 218 { 219 if (originalDst && originalDst != ignoredResult()) 220 return originalDst; 221 ASSERT(tempDst != ignoredResult()); 222 if (tempDst && tempDst->isTemporary()) 223 return tempDst; 224 return newTemporary(); 225 } 226 227 RegisterID* destinationForAssignResult(RegisterID* dst) 228 { 229 if (dst && dst != ignoredResult() && m_codeBlock->needsFullScopeChain()) 230 return dst->isTemporary() ? dst : newTemporary(); 231 return 0; 232 } 233 234 // Moves src to dst if dst is not null and is different from src, otherwise just returns src. 235 RegisterID* moveToDestinationIfNeeded(RegisterID* dst, RegisterID* src) 236 { 237 return dst == ignoredResult() ? 0 : (dst && dst != src) ? emitMove(dst, src) : src; 238 } 239 240 LabelScopePtr newLabelScope(LabelScope::Type, const Identifier* = 0); 241 PassRefPtr<Label> newLabel(); 242 243 void emitNode(RegisterID* dst, StatementNode* n) 244 { 245 // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. 246 ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); 247 // Should never store directly into a captured variable. 248 ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst->index())); 249 if (!m_vm->isSafeToRecurse()) { 250 emitThrowExpressionTooDeepException(); 251 return; 252 } 253 n->emitBytecode(*this, dst); 254 } 255 256 void emitNode(StatementNode* n) 257 { 258 emitNode(0, n); 259 } 260 261 RegisterID* emitNode(RegisterID* dst, ExpressionNode* n) 262 { 263 // Node::emitCode assumes that dst, if provided, is either a local or a referenced temporary. 264 ASSERT(!dst || dst == ignoredResult() || !dst->isTemporary() || dst->refCount()); 265 // Should never store directly into a captured variable. 266 ASSERT(!dst || dst == ignoredResult() || !isCaptured(dst->index())); 267 if (!m_vm->isSafeToRecurse()) 268 return emitThrowExpressionTooDeepException(); 269 return n->emitBytecode(*this, dst); 270 } 271 272 RegisterID* emitNode(ExpressionNode* n) 273 { 274 return emitNode(0, n); 275 } 276 277 void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, FallThroughMode fallThroughMode) 278 { 279 if (!m_vm->isSafeToRecurse()) { 280 emitThrowExpressionTooDeepException(); 281 return; 282 } 283 284 n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMode); 285 } 286 287 void emitExpressionInfo(const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) 288 { 289 ASSERT(divot.offset >= divotStart.offset); 290 ASSERT(divotEnd.offset >= divot.offset); 291 292 int sourceOffset = m_scopeNode->source().startOffset(); 293 unsigned firstLine = m_scopeNode->source().firstLine(); 294 295 int divotOffset = divot.offset - sourceOffset; 296 int startOffset = divot.offset - divotStart.offset; 297 int endOffset = divotEnd.offset - divot.offset; 298 299 unsigned line = divot.line; 300 ASSERT(line >= firstLine); 301 line -= firstLine; 302 303 int lineStart = divot.lineStartOffset; 304 if (lineStart > sourceOffset) 305 lineStart -= sourceOffset; 306 else 307 lineStart = 0; 308 309 if (divotOffset < lineStart) 310 return; 311 312 unsigned column = divotOffset - lineStart; 313 314 unsigned instructionOffset = instructions().size(); 315 if (!m_isBuiltinFunction) 316 m_codeBlock->addExpressionInfo(instructionOffset, divotOffset, startOffset, endOffset, line, column); 317 } 318 319 ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure) 320 { 321 return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain() || rightHasAssignments) && !rightIsPure; 322 } 323 324 ALWAYS_INLINE PassRefPtr<RegisterID> emitNodeForLeftHandSide(ExpressionNode* n, bool rightHasAssignments, bool rightIsPure) 325 { 326 if (leftHandSideNeedsCopy(rightHasAssignments, rightIsPure)) { 327 PassRefPtr<RegisterID> dst = newTemporary(); 328 emitNode(dst.get(), n); 329 return dst; 330 } 331 332 return emitNode(n); 333 } 334 335 RegisterID* emitLoad(RegisterID* dst, bool); 336 RegisterID* emitLoad(RegisterID* dst, double); 337 RegisterID* emitLoad(RegisterID* dst, const Identifier&); 338 RegisterID* emitLoad(RegisterID* dst, JSValue); 339 RegisterID* emitLoadGlobalObject(RegisterID* dst); 340 341 RegisterID* emitUnaryOp(OpcodeID, RegisterID* dst, RegisterID* src); 342 RegisterID* emitBinaryOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2, OperandTypes); 343 RegisterID* emitEqualityOp(OpcodeID, RegisterID* dst, RegisterID* src1, RegisterID* src2); 344 RegisterID* emitUnaryNoDstOp(OpcodeID, RegisterID* src); 345 346 RegisterID* emitCreateThis(RegisterID* dst); 347 RegisterID* emitNewObject(RegisterID* dst); 348 RegisterID* emitNewArray(RegisterID* dst, ElementNode*, unsigned length); // stops at first elision 349 350 RegisterID* emitNewFunction(RegisterID* dst, CaptureMode, FunctionBodyNode*); 351 RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body); 352 RegisterID* emitNewFunctionInternal(RegisterID* dst, CaptureMode, unsigned index, bool shouldNullCheck); 353 RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func); 354 RegisterID* emitNewRegExp(RegisterID* dst, RegExp*); 355 356 RegisterID* emitMove(RegisterID* dst, CaptureMode, RegisterID* src); 357 RegisterID* emitMove(RegisterID* dst, RegisterID* src); 358 359 RegisterID* emitToNumber(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_to_number, dst, src); } 360 RegisterID* emitInc(RegisterID* srcDst); 361 RegisterID* emitDec(RegisterID* srcDst); 362 363 void emitCheckHasInstance(RegisterID* dst, RegisterID* value, RegisterID* base, Label* target); 364 RegisterID* emitInstanceOf(RegisterID* dst, RegisterID* value, RegisterID* basePrototype); 365 RegisterID* emitTypeOf(RegisterID* dst, RegisterID* src) { return emitUnaryOp(op_typeof, dst, src); } 366 RegisterID* emitIn(RegisterID* dst, RegisterID* property, RegisterID* base) { return emitBinaryOp(op_in, dst, property, base, OperandTypes()); } 367 368 RegisterID* emitInitGlobalConst(const Identifier&, RegisterID* value); 369 370 RegisterID* emitGetById(RegisterID* dst, RegisterID* base, const Identifier& property); 371 RegisterID* emitGetArgumentsLength(RegisterID* dst, RegisterID* base); 372 RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value); 373 RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value); 374 RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&); 375 RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property); 376 RegisterID* emitGetArgumentByVal(RegisterID* dst, RegisterID* base, RegisterID* property); 377 RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); 378 RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value); 379 RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property); 380 RegisterID* emitPutByIndex(RegisterID* base, unsigned index, RegisterID* value); 381 void emitPutGetterSetter(RegisterID* base, const Identifier& property, RegisterID* getter, RegisterID* setter); 382 383 ExpectedFunction expectedFunctionForIdentifier(const Identifier&); 384 RegisterID* emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); 385 RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); 386 RegisterID* emitCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); 387 388 void emitEnumeration(ThrowableExpressionData* enumerationNode, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack); 389 390 RegisterID* emitReturn(RegisterID* src); 391 RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); } 392 393 RegisterID* emitConstruct(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); 394 RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count); 395 void emitToPrimitive(RegisterID* dst, RegisterID* src); 396 397 ResolveType resolveType(); 398 RegisterID* emitResolveScope(RegisterID* dst, const Identifier&); 399 RegisterID* emitGetFromScope(RegisterID* dst, RegisterID* scope, const Identifier&, ResolveMode); 400 RegisterID* emitPutToScope(RegisterID* scope, const Identifier&, RegisterID* value, ResolveMode); 401 402 PassRefPtr<Label> emitLabel(Label*); 403 void emitLoopHint(); 404 PassRefPtr<Label> emitJump(Label* target); 405 PassRefPtr<Label> emitJumpIfTrue(RegisterID* cond, Label* target); 406 PassRefPtr<Label> emitJumpIfFalse(RegisterID* cond, Label* target); 407 PassRefPtr<Label> emitJumpIfNotFunctionCall(RegisterID* cond, Label* target); 408 PassRefPtr<Label> emitJumpIfNotFunctionApply(RegisterID* cond, Label* target); 409 void emitPopScopes(int targetScopeDepth); 410 411 RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget); 412 RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target); 413 414 void emitReadOnlyExceptionIfNeeded(); 415 416 // Start a try block. 'start' must have been emitted. 417 TryData* pushTry(Label* start); 418 // End a try block. 'end' must have been emitted. 419 RegisterID* popTryAndEmitCatch(TryData*, RegisterID* targetRegister, Label* end); 420 421 void emitThrow(RegisterID* exc) 422 { 423 m_usesExceptions = true; 424 emitUnaryNoDstOp(op_throw, exc); 425 } 426 427 void emitThrowReferenceError(const String& message); 428 429 void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, unsigned attributes); 430 void emitPushCatchScope(const Identifier& property, RegisterID* value, unsigned attributes); 431 432 RegisterID* emitPushWithScope(RegisterID* scope); 433 void emitPopScope(); 434 435 void emitDebugHook(DebugHookID, unsigned line, unsigned charOffset, unsigned lineStart); 436 437 int scopeDepth() { return m_localScopeDepth + m_finallyDepth; } 438 bool hasFinaliser() { return m_finallyDepth != 0; } 439 440 void pushFinallyContext(StatementNode* finallyBlock); 441 void popFinallyContext(); 442 443 void pushOptimisedForIn(RegisterID* expectedSubscript, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister) 444 { 445 ForInContext context = { expectedSubscript, iter, index, propertyRegister }; 446 m_forInContextStack.append(context); 447 } 448 449 void popOptimisedForIn() 450 { 451 m_forInContextStack.removeLast(); 452 } 453 454 LabelScopePtr breakTarget(const Identifier&); 455 LabelScopePtr continueTarget(const Identifier&); 456 457 void beginSwitch(RegisterID*, SwitchInfo::SwitchType); 458 void endSwitch(uint32_t clauseCount, RefPtr<Label>*, ExpressionNode**, Label* defaultLabel, int32_t min, int32_t range); 459 460 CodeType codeType() const { return m_codeType; } 461 462 bool shouldEmitProfileHooks() { return m_shouldEmitProfileHooks; } 463 bool shouldEmitDebugHooks() { return m_shouldEmitDebugHooks; } 464 465 bool isStrictMode() const { return m_codeBlock->isStrictMode(); } 466 467 bool isBuiltinFunction() const { return m_isBuiltinFunction; } 468 469 private: 470 friend class Label; 471 472 void emitOpcode(OpcodeID); 473 UnlinkedArrayAllocationProfile newArrayAllocationProfile(); 474 UnlinkedObjectAllocationProfile newObjectAllocationProfile(); 475 UnlinkedArrayProfile newArrayProfile(); 476 UnlinkedValueProfile emitProfiledOpcode(OpcodeID); 477 int kill(RegisterID* dst) 478 { 479 int index = dst->index(); 480 m_staticPropertyAnalyzer.kill(index); 481 return index; 482 } 483 484 void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index); 485 void retrieveLastUnaryOp(int& dstIndex, int& srcIndex); 486 ALWAYS_INLINE void rewindBinaryOp(); 487 ALWAYS_INLINE void rewindUnaryOp(); 488 489 void emitComplexPopScopes(ControlFlowContext* topScope, ControlFlowContext* bottomScope); 490 491 typedef HashMap<double, JSValue> NumberMap; 492 typedef HashMap<StringImpl*, JSString*, IdentifierRepHash> IdentifierStringMap; 493 494 // Helper for emitCall() and emitConstruct(). This works because the set of 495 // expected functions have identical behavior for both call and construct 496 // (i.e. "Object()" is identical to "new Object()"). 497 ExpectedFunction emitExpectedFunctionSnippet(RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, Label* done); 498 499 RegisterID* emitCall(OpcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction, CallArguments&, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); 500 501 RegisterID* newRegister(); 502 503 // Adds a var slot and maps it to the name ident in symbolTable(). 504 enum WatchMode { IsWatchable, NotWatchable }; 505 RegisterID* addVar(const Identifier& ident, ConstantMode constantMode, WatchMode watchMode) 506 { 507 RegisterID* local; 508 addVar(ident, constantMode, watchMode, local); 509 return local; 510 } 511 512 // Ditto. Returns true if a new RegisterID was added, false if a pre-existing RegisterID was re-used. 513 bool addVar(const Identifier&, ConstantMode, WatchMode, RegisterID*&); 514 515 // Adds an anonymous var slot. To give this slot a name, add it to symbolTable(). 516 RegisterID* addVar() 517 { 518 ++m_codeBlock->m_numVars; 519 return newRegister(); 520 } 521 522 // Returns the index of the added var. 523 void addParameter(const Identifier&, int parameterIndex); 524 RegisterID* resolveCallee(FunctionBodyNode*); 525 void addCallee(FunctionBodyNode*, RegisterID*); 526 527 void preserveLastVar(); 528 529 RegisterID& registerFor(int index) 530 { 531 if (operandIsLocal(index)) 532 return m_calleeRegisters[VirtualRegister(index).toLocal()]; 533 534 if (index == JSStack::Callee) 535 return m_calleeRegister; 536 537 ASSERT(m_parameters.size()); 538 return m_parameters[VirtualRegister(index).toArgument()]; 539 } 540 541 unsigned addConstant(const Identifier&); 542 RegisterID* addConstantValue(JSValue); 543 RegisterID* addConstantEmptyValue(); 544 unsigned addRegExp(RegExp*); 545 546 unsigned addConstantBuffer(unsigned length); 547 548 UnlinkedFunctionExecutable* makeFunction(FunctionBodyNode* body) 549 { 550 return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), body, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction); 551 } 552 553 RegisterID* emitInitLazyRegister(RegisterID*); 554 555 RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); 556 RegisterID* emitCallVarargs(OpcodeID, RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); 557 558 public: 559 JSString* addStringConstant(const Identifier&); 560 561 Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow>& instructions() { return m_instructions; } 562 563 SymbolTable& symbolTable() { return *m_symbolTable; } 564 565 bool shouldOptimizeLocals() 566 { 567 if (m_codeType != FunctionCode) 568 return false; 569 570 if (m_localScopeDepth) 571 return false; 572 573 return true; 574 } 575 576 bool canOptimizeNonLocals() 577 { 578 if (m_localScopeDepth) 579 return false; 580 581 if (m_codeType == EvalCode) 582 return false; 583 584 if (m_codeType == FunctionCode && m_codeBlock->usesEval()) 585 return false; 586 587 return true; 588 } 589 590 bool shouldTearOffArgumentsEagerly() 591 { 592 return m_codeType == FunctionCode && isStrictMode() && m_scopeNode->modifiesParameter(); 593 } 594 595 RegisterID* emitThrowExpressionTooDeepException(); 596 597 void createArgumentsIfNecessary(); 598 void createActivationIfNecessary(); 599 RegisterID* createLazyRegisterIfNecessary(RegisterID*); 600 601 unsigned watchableVariable(int operand) 602 { 603 VirtualRegister reg(operand); 604 if (!reg.isLocal()) 605 return UINT_MAX; 606 if (static_cast<size_t>(reg.toLocal()) >= m_watchableVariables.size()) 607 return UINT_MAX; 608 Identifier& ident = m_watchableVariables[reg.toLocal()]; 609 if (ident.isNull()) 610 return UINT_MAX; 611 return addConstant(ident); 612 } 613 614 bool hasWatchableVariable(int operand) 615 { 616 return watchableVariable(operand) != UINT_MAX; 617 } 618 619 Vector<UnlinkedInstruction, 0, UnsafeVectorOverflow> m_instructions; 620 621 bool m_shouldEmitDebugHooks; 622 bool m_shouldEmitProfileHooks; 623 624 SymbolTable* m_symbolTable; 625 626 ScopeNode* m_scopeNode; 627 Strong<UnlinkedCodeBlock> m_codeBlock; 628 629 // Some of these objects keep pointers to one another. They are arranged 630 // to ensure a sane destruction order that avoids references to freed memory. 631 HashSet<RefPtr<StringImpl>, IdentifierRepHash> m_functions; 632 RegisterID m_ignoredResultRegister; 633 RegisterID m_thisRegister; 634 RegisterID m_calleeRegister; 635 RegisterID* m_activationRegister; 636 RegisterID* m_emptyValueRegister; 637 RegisterID* m_globalObjectRegister; 638 Vector<Identifier, 16> m_watchableVariables; 639 SegmentedVector<RegisterID, 32> m_constantPoolRegisters; 640 SegmentedVector<RegisterID, 32> m_calleeRegisters; 641 SegmentedVector<RegisterID, 32> m_parameters; 642 SegmentedVector<Label, 32> m_labels; 643 LabelScopeStore m_labelScopes; 644 RefPtr<RegisterID> m_lastVar; 645 int m_finallyDepth; 646 int m_localScopeDepth; 647 CodeType m_codeType; 648 649 Vector<ControlFlowContext, 0, UnsafeVectorOverflow> m_scopeContextStack; 650 Vector<SwitchInfo> m_switchContextStack; 651 Vector<ForInContext> m_forInContextStack; 652 Vector<TryContext> m_tryContextStack; 653 Vector<std::pair<RefPtr<RegisterID>, const DeconstructionPatternNode*>> m_deconstructedParameters; 654 655 Vector<TryRange> m_tryRanges; 656 SegmentedVector<TryData, 8> m_tryData; 657 658 int m_firstConstantIndex; 659 int m_nextConstantOffset; 660 unsigned m_globalConstantIndex; 661 662 int m_globalVarStorageOffset; 663 664 int m_firstLazyFunction; 665 int m_lastLazyFunction; 666 HashMap<unsigned int, FunctionBodyNode*, WTF::IntHash<unsigned int>, WTF::UnsignedWithZeroKeyHashTraits<unsigned int>> m_lazyFunctions; 667 typedef HashMap<FunctionBodyNode*, unsigned> FunctionOffsetMap; 668 FunctionOffsetMap m_functionOffsets; 669 670 // Constant pool 671 IdentifierMap m_identifierMap; 672 JSValueMap m_jsValueMap; 673 NumberMap m_numberMap; 674 IdentifierStringMap m_stringMap; 675 676 StaticPropertyAnalyzer m_staticPropertyAnalyzer; 677 678 VM* m_vm; 679 680 OpcodeID m_lastOpcodeID; 681#ifndef NDEBUG 682 size_t m_lastOpcodePosition; 683#endif 684 685 bool m_usesExceptions; 686 bool m_expressionTooDeep; 687 bool m_isBuiltinFunction; 688 }; 689 690} 691 692#endif // BytecodeGenerator_h 693