1 /* 2 * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "DFGByteCodeParser.h" 28 29#if ENABLE(DFG_JIT) 30 31#include "ArrayConstructor.h" 32#include "CallLinkStatus.h" 33#include "CodeBlock.h" 34#include "CodeBlockWithJITType.h" 35#include "DFGArrayMode.h" 36#include "DFGCapabilities.h" 37#include "DFGJITCode.h" 38#include "GetByIdStatus.h" 39#include "Heap.h" 40#include "JSActivation.h" 41#include "JSCInlines.h" 42#include "PreciseJumpTargets.h" 43#include "PutByIdStatus.h" 44#include "StackAlignment.h" 45#include "StringConstructor.h" 46#include <wtf/CommaPrinter.h> 47#include <wtf/HashMap.h> 48#include <wtf/MathExtras.h> 49#include <wtf/StdLibExtras.h> 50 51namespace JSC { namespace DFG { 52 53class ConstantBufferKey { 54public: 55 ConstantBufferKey() 56 : m_codeBlock(0) 57 , m_index(0) 58 { 59 } 60 61 ConstantBufferKey(WTF::HashTableDeletedValueType) 62 : m_codeBlock(0) 63 , m_index(1) 64 { 65 } 66 67 ConstantBufferKey(CodeBlock* codeBlock, unsigned index) 68 : m_codeBlock(codeBlock) 69 , m_index(index) 70 { 71 } 72 73 bool operator==(const ConstantBufferKey& other) const 74 { 75 return m_codeBlock == other.m_codeBlock 76 && m_index == other.m_index; 77 } 78 79 unsigned hash() const 80 { 81 return WTF::PtrHash<CodeBlock*>::hash(m_codeBlock) ^ m_index; 82 } 83 84 bool isHashTableDeletedValue() const 85 { 86 return !m_codeBlock && m_index; 87 } 88 89 CodeBlock* codeBlock() const { return m_codeBlock; } 90 unsigned index() const { return m_index; } 91 92private: 93 CodeBlock* m_codeBlock; 94 unsigned m_index; 95}; 96 97struct ConstantBufferKeyHash { 98 static unsigned hash(const ConstantBufferKey& key) { return key.hash(); } 99 static bool equal(const ConstantBufferKey& a, const ConstantBufferKey& b) 100 { 101 return a == b; 102 } 103 104 static const bool safeToCompareToEmptyOrDeleted = true; 105}; 106 107} } // namespace JSC::DFG 108 109namespace WTF { 110 111template<typename T> struct DefaultHash; 112template<> struct DefaultHash<JSC::DFG::ConstantBufferKey> { 113 typedef JSC::DFG::ConstantBufferKeyHash Hash; 114}; 115 116template<typename T> struct HashTraits; 117template<> struct HashTraits<JSC::DFG::ConstantBufferKey> : SimpleClassHashTraits<JSC::DFG::ConstantBufferKey> { }; 118 119} // namespace WTF 120 121namespace JSC { namespace DFG { 122 123// === ByteCodeParser === 124// 125// This class is used to compile the dataflow graph from a CodeBlock. 126class ByteCodeParser { 127public: 128 ByteCodeParser(Graph& graph) 129 : m_vm(&graph.m_vm) 130 , m_codeBlock(graph.m_codeBlock) 131 , m_profiledBlock(graph.m_profiledBlock) 132 , m_graph(graph) 133 , m_currentBlock(0) 134 , m_currentIndex(0) 135 , m_constantUndefined(UINT_MAX) 136 , m_constantNull(UINT_MAX) 137 , m_constantNaN(UINT_MAX) 138 , m_constant1(UINT_MAX) 139 , m_constants(m_codeBlock->numberOfConstantRegisters()) 140 , m_numArguments(m_codeBlock->numParameters()) 141 , m_numLocals(m_codeBlock->m_numCalleeRegisters) 142 , m_parameterSlots(0) 143 , m_numPassedVarArgs(0) 144 , m_inlineStackTop(0) 145 , m_haveBuiltOperandMaps(false) 146 , m_emptyJSValueIndex(UINT_MAX) 147 , m_currentInstruction(0) 148 { 149 ASSERT(m_profiledBlock); 150 } 151 152 // Parse a full CodeBlock of bytecode. 153 bool parse(); 154 155private: 156 struct InlineStackEntry; 157 158 // Just parse from m_currentIndex to the end of the current CodeBlock. 159 void parseCodeBlock(); 160 161 void ensureLocals(unsigned newNumLocals) 162 { 163 if (newNumLocals <= m_numLocals) 164 return; 165 m_numLocals = newNumLocals; 166 for (size_t i = 0; i < m_graph.numBlocks(); ++i) 167 m_graph.block(i)->ensureLocals(newNumLocals); 168 } 169 170 // Helper for min and max. 171 bool handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis); 172 173 // Handle calls. This resolves issues surrounding inlining and intrinsics. 174 void handleCall(int result, NodeType op, CodeSpecializationKind, unsigned instructionSize, int callee, int argCount, int registerOffset); 175 void handleCall(Instruction* pc, NodeType op, CodeSpecializationKind); 176 void emitFunctionChecks(const CallLinkStatus&, Node* callTarget, int registerOffset, CodeSpecializationKind); 177 void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind); 178 // Handle inlining. Return true if it succeeded, false if we need to plant a call. 179 bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind); 180 // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call. 181 bool handleIntrinsic(int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction); 182 bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType); 183 bool handleConstantInternalFunction(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind); 184 Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, Node* value); 185 Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset); 186 void handleGetByOffset( 187 int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber, 188 PropertyOffset); 189 void handleGetById( 190 int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber, 191 const GetByIdStatus&); 192 void emitPutById( 193 Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&, bool isDirect); 194 void handlePutById( 195 Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&, 196 bool isDirect); 197 Node* emitPrototypeChecks(Structure*, IntendedStructureChain*); 198 199 Node* getScope(bool skipTop, unsigned skipCount); 200 201 // Prepare to parse a block. 202 void prepareToParseBlock(); 203 // Parse a single basic block of bytecode instructions. 204 bool parseBlock(unsigned limit); 205 // Link block successors. 206 void linkBlock(BasicBlock*, Vector<BasicBlock*>& possibleTargets); 207 void linkBlocks(Vector<UnlinkedBlock>& unlinkedBlocks, Vector<BasicBlock*>& possibleTargets); 208 209 VariableAccessData* newVariableAccessData(VirtualRegister operand, bool isCaptured) 210 { 211 ASSERT(!operand.isConstant()); 212 213 m_graph.m_variableAccessData.append(VariableAccessData(operand, isCaptured)); 214 return &m_graph.m_variableAccessData.last(); 215 } 216 217 // Get/Set the operands/result of a bytecode instruction. 218 Node* getDirect(VirtualRegister operand) 219 { 220 // Is this a constant? 221 if (operand.isConstant()) { 222 unsigned constant = operand.toConstantIndex(); 223 ASSERT(constant < m_constants.size()); 224 return getJSConstant(constant); 225 } 226 227 // Is this an argument? 228 if (operand.isArgument()) 229 return getArgument(operand); 230 231 // Must be a local. 232 return getLocal(operand); 233 } 234 235 Node* get(VirtualRegister operand) 236 { 237 if (inlineCallFrame()) { 238 if (!inlineCallFrame()->isClosureCall) { 239 JSFunction* callee = inlineCallFrame()->calleeConstant(); 240 if (operand.offset() == JSStack::Callee) 241 return cellConstant(callee); 242 if (operand.offset() == JSStack::ScopeChain) 243 return cellConstant(callee->scope()); 244 } 245 } else if (operand.offset() == JSStack::Callee) 246 return addToGraph(GetCallee); 247 else if (operand.offset() == JSStack::ScopeChain) 248 return addToGraph(GetMyScope); 249 250 return getDirect(m_inlineStackTop->remapOperand(operand)); 251 } 252 253 enum SetMode { 254 // A normal set which follows a two-phase commit that spans code origins. During 255 // the current code origin it issues a MovHint, and at the start of the next 256 // code origin there will be a SetLocal. If the local needs flushing, the second 257 // SetLocal will be preceded with a Flush. 258 NormalSet, 259 260 // A set where the SetLocal happens immediately and there is still a Flush. This 261 // is relevant when assigning to a local in tricky situations for the delayed 262 // SetLocal logic but where we know that we have not performed any side effects 263 // within this code origin. This is a safe replacement for NormalSet anytime we 264 // know that we have not yet performed side effects in this code origin. 265 ImmediateSetWithFlush, 266 267 // A set where the SetLocal happens immediately and we do not Flush it even if 268 // this is a local that is marked as needing it. This is relevant when 269 // initializing locals at the top of a function. 270 ImmediateNakedSet 271 }; 272 Node* setDirect(VirtualRegister operand, Node* value, SetMode setMode = NormalSet) 273 { 274 addToGraph(MovHint, OpInfo(operand.offset()), value); 275 276 DelayedSetLocal delayed = DelayedSetLocal(operand, value); 277 278 if (setMode == NormalSet) { 279 m_setLocalQueue.append(delayed); 280 return 0; 281 } 282 283 return delayed.execute(this, setMode); 284 } 285 286 Node* set(VirtualRegister operand, Node* value, SetMode setMode = NormalSet) 287 { 288 return setDirect(m_inlineStackTop->remapOperand(operand), value, setMode); 289 } 290 291 Node* injectLazyOperandSpeculation(Node* node) 292 { 293 ASSERT(node->op() == GetLocal); 294 ASSERT(node->origin.semantic.bytecodeIndex == m_currentIndex); 295 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 296 LazyOperandValueProfileKey key(m_currentIndex, node->local()); 297 SpeculatedType prediction = m_inlineStackTop->m_lazyOperands.prediction(locker, key); 298 node->variableAccessData()->predict(prediction); 299 return node; 300 } 301 302 // Used in implementing get/set, above, where the operand is a local variable. 303 Node* getLocal(VirtualRegister operand) 304 { 305 unsigned local = operand.toLocal(); 306 307 if (local < m_localWatchpoints.size()) { 308 if (VariableWatchpointSet* set = m_localWatchpoints[local]) { 309 if (JSValue value = set->inferredValue()) { 310 addToGraph(FunctionReentryWatchpoint, OpInfo(m_codeBlock->symbolTable())); 311 addToGraph(VariableWatchpoint, OpInfo(set)); 312 // Note: this is very special from an OSR exit standpoint. We wouldn't be 313 // able to do this for most locals, but it works here because we're dealing 314 // with a flushed local. For most locals we would need to issue a GetLocal 315 // here and ensure that we have uses in DFG IR wherever there would have 316 // been uses in bytecode. Clearly this optimization does not do this. But 317 // that's fine, because we don't need to track liveness for captured 318 // locals, and this optimization only kicks in for captured locals. 319 return inferredConstant(value); 320 } 321 } 322 } 323 324 Node* node = m_currentBlock->variablesAtTail.local(local); 325 bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame()); 326 327 // This has two goals: 1) link together variable access datas, and 2) 328 // try to avoid creating redundant GetLocals. (1) is required for 329 // correctness - no other phase will ensure that block-local variable 330 // access data unification is done correctly. (2) is purely opportunistic 331 // and is meant as an compile-time optimization only. 332 333 VariableAccessData* variable; 334 335 if (node) { 336 variable = node->variableAccessData(); 337 variable->mergeIsCaptured(isCaptured); 338 339 if (!isCaptured) { 340 switch (node->op()) { 341 case GetLocal: 342 return node; 343 case SetLocal: 344 return node->child1().node(); 345 default: 346 break; 347 } 348 } 349 } else 350 variable = newVariableAccessData(operand, isCaptured); 351 352 node = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variable))); 353 m_currentBlock->variablesAtTail.local(local) = node; 354 return node; 355 } 356 357 Node* setLocal(VirtualRegister operand, Node* value, SetMode setMode = NormalSet) 358 { 359 unsigned local = operand.toLocal(); 360 bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame()); 361 362 if (setMode != ImmediateNakedSet) { 363 ArgumentPosition* argumentPosition = findArgumentPositionForLocal(operand); 364 if (isCaptured || argumentPosition) 365 flushDirect(operand, argumentPosition); 366 } 367 368 VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured); 369 variableAccessData->mergeStructureCheckHoistingFailed( 370 m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) 371 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCacheWatchpoint)); 372 variableAccessData->mergeCheckArrayHoistingFailed( 373 m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType)); 374 Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value); 375 m_currentBlock->variablesAtTail.local(local) = node; 376 return node; 377 } 378 379 // Used in implementing get/set, above, where the operand is an argument. 380 Node* getArgument(VirtualRegister operand) 381 { 382 unsigned argument = operand.toArgument(); 383 ASSERT(argument < m_numArguments); 384 385 Node* node = m_currentBlock->variablesAtTail.argument(argument); 386 bool isCaptured = m_codeBlock->isCaptured(operand); 387 388 VariableAccessData* variable; 389 390 if (node) { 391 variable = node->variableAccessData(); 392 variable->mergeIsCaptured(isCaptured); 393 394 switch (node->op()) { 395 case GetLocal: 396 return node; 397 case SetLocal: 398 return node->child1().node(); 399 default: 400 break; 401 } 402 } else 403 variable = newVariableAccessData(operand, isCaptured); 404 405 node = injectLazyOperandSpeculation(addToGraph(GetLocal, OpInfo(variable))); 406 m_currentBlock->variablesAtTail.argument(argument) = node; 407 return node; 408 } 409 Node* setArgument(VirtualRegister operand, Node* value, SetMode setMode = NormalSet) 410 { 411 unsigned argument = operand.toArgument(); 412 ASSERT(argument < m_numArguments); 413 414 bool isCaptured = m_codeBlock->isCaptured(operand); 415 416 VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured); 417 418 // Always flush arguments, except for 'this'. If 'this' is created by us, 419 // then make sure that it's never unboxed. 420 if (argument) { 421 if (setMode != ImmediateNakedSet) 422 flushDirect(operand); 423 } else if (m_codeBlock->specializationKind() == CodeForConstruct) 424 variableAccessData->mergeShouldNeverUnbox(true); 425 426 variableAccessData->mergeStructureCheckHoistingFailed( 427 m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) 428 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCacheWatchpoint)); 429 variableAccessData->mergeCheckArrayHoistingFailed( 430 m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType)); 431 Node* node = addToGraph(SetLocal, OpInfo(variableAccessData), value); 432 m_currentBlock->variablesAtTail.argument(argument) = node; 433 return node; 434 } 435 436 ArgumentPosition* findArgumentPositionForArgument(int argument) 437 { 438 InlineStackEntry* stack = m_inlineStackTop; 439 while (stack->m_inlineCallFrame) 440 stack = stack->m_caller; 441 return stack->m_argumentPositions[argument]; 442 } 443 444 ArgumentPosition* findArgumentPositionForLocal(VirtualRegister operand) 445 { 446 for (InlineStackEntry* stack = m_inlineStackTop; ; stack = stack->m_caller) { 447 InlineCallFrame* inlineCallFrame = stack->m_inlineCallFrame; 448 if (!inlineCallFrame) 449 break; 450 if (operand.offset() < static_cast<int>(inlineCallFrame->stackOffset + JSStack::CallFrameHeaderSize)) 451 continue; 452 if (operand.offset() == inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset()) 453 continue; 454 if (operand.offset() >= static_cast<int>(inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset() + inlineCallFrame->arguments.size())) 455 continue; 456 int argument = VirtualRegister(operand.offset() - inlineCallFrame->stackOffset).toArgument(); 457 return stack->m_argumentPositions[argument]; 458 } 459 return 0; 460 } 461 462 ArgumentPosition* findArgumentPosition(VirtualRegister operand) 463 { 464 if (operand.isArgument()) 465 return findArgumentPositionForArgument(operand.toArgument()); 466 return findArgumentPositionForLocal(operand); 467 } 468 469 void addConstant(JSValue value) 470 { 471 unsigned constantIndex = m_codeBlock->addConstantLazily(); 472 initializeLazyWriteBarrierForConstant( 473 m_graph.m_plan.writeBarriers, 474 m_codeBlock->constants()[constantIndex], 475 m_codeBlock, 476 constantIndex, 477 m_codeBlock->ownerExecutable(), 478 value); 479 } 480 481 void flush(VirtualRegister operand) 482 { 483 flushDirect(m_inlineStackTop->remapOperand(operand)); 484 } 485 486 void flushDirect(VirtualRegister operand) 487 { 488 flushDirect(operand, findArgumentPosition(operand)); 489 } 490 491 void flushDirect(VirtualRegister operand, ArgumentPosition* argumentPosition) 492 { 493 bool isCaptured = m_codeBlock->isCaptured(operand, inlineCallFrame()); 494 495 ASSERT(!operand.isConstant()); 496 497 Node* node = m_currentBlock->variablesAtTail.operand(operand); 498 499 VariableAccessData* variable; 500 501 if (node) { 502 variable = node->variableAccessData(); 503 variable->mergeIsCaptured(isCaptured); 504 } else 505 variable = newVariableAccessData(operand, isCaptured); 506 507 node = addToGraph(Flush, OpInfo(variable)); 508 m_currentBlock->variablesAtTail.operand(operand) = node; 509 if (argumentPosition) 510 argumentPosition->addVariable(variable); 511 } 512 513 void flush(InlineStackEntry* inlineStackEntry) 514 { 515 int numArguments; 516 if (InlineCallFrame* inlineCallFrame = inlineStackEntry->m_inlineCallFrame) { 517 numArguments = inlineCallFrame->arguments.size(); 518 if (inlineCallFrame->isClosureCall) { 519 flushDirect(inlineStackEntry->remapOperand(VirtualRegister(JSStack::Callee))); 520 flushDirect(inlineStackEntry->remapOperand(VirtualRegister(JSStack::ScopeChain))); 521 } 522 } else 523 numArguments = inlineStackEntry->m_codeBlock->numParameters(); 524 for (unsigned argument = numArguments; argument-- > 1;) 525 flushDirect(inlineStackEntry->remapOperand(virtualRegisterForArgument(argument))); 526 for (int local = 0; local < inlineStackEntry->m_codeBlock->m_numVars; ++local) { 527 if (!inlineStackEntry->m_codeBlock->isCaptured(virtualRegisterForLocal(local))) 528 continue; 529 flushDirect(inlineStackEntry->remapOperand(virtualRegisterForLocal(local))); 530 } 531 } 532 533 void flushForTerminal() 534 { 535 for (InlineStackEntry* inlineStackEntry = m_inlineStackTop; inlineStackEntry; inlineStackEntry = inlineStackEntry->m_caller) 536 flush(inlineStackEntry); 537 } 538 539 void flushForReturn() 540 { 541 flush(m_inlineStackTop); 542 } 543 544 void flushIfTerminal(SwitchData& data) 545 { 546 if (data.fallThrough.bytecodeIndex() > m_currentIndex) 547 return; 548 549 for (unsigned i = data.cases.size(); i--;) { 550 if (data.cases[i].target.bytecodeIndex() > m_currentIndex) 551 return; 552 } 553 554 flushForTerminal(); 555 } 556 557 // NOTE: Only use this to construct constants that arise from non-speculative 558 // constant folding. I.e. creating constants using this if we had constant 559 // field inference would be a bad idea, since the bytecode parser's folding 560 // doesn't handle liveness preservation. 561 Node* getJSConstantForValue(JSValue constantValue) 562 { 563 unsigned constantIndex; 564 if (!m_codeBlock->findConstant(constantValue, constantIndex)) { 565 addConstant(constantValue); 566 m_constants.append(ConstantRecord()); 567 } 568 569 ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); 570 571 return getJSConstant(constantIndex); 572 } 573 574 Node* getJSConstant(unsigned constant) 575 { 576 Node* node = m_constants[constant].asJSValue; 577 if (node) 578 return node; 579 580 Node* result = addToGraph(JSConstant, OpInfo(constant)); 581 m_constants[constant].asJSValue = result; 582 return result; 583 } 584 585 // Helper functions to get/set the this value. 586 Node* getThis() 587 { 588 return get(m_inlineStackTop->m_codeBlock->thisRegister()); 589 } 590 591 void setThis(Node* value) 592 { 593 set(m_inlineStackTop->m_codeBlock->thisRegister(), value); 594 } 595 596 // Convenience methods for checking nodes for constants. 597 bool isJSConstant(Node* node) 598 { 599 return node->op() == JSConstant; 600 } 601 bool isInt32Constant(Node* node) 602 { 603 return isJSConstant(node) && valueOfJSConstant(node).isInt32(); 604 } 605 // Convenience methods for getting constant values. 606 JSValue valueOfJSConstant(Node* node) 607 { 608 ASSERT(isJSConstant(node)); 609 return m_codeBlock->getConstant(FirstConstantRegisterIndex + node->constantNumber()); 610 } 611 int32_t valueOfInt32Constant(Node* node) 612 { 613 ASSERT(isInt32Constant(node)); 614 return valueOfJSConstant(node).asInt32(); 615 } 616 617 // This method returns a JSConstant with the value 'undefined'. 618 Node* constantUndefined() 619 { 620 // Has m_constantUndefined been set up yet? 621 if (m_constantUndefined == UINT_MAX) { 622 // Search the constant pool for undefined, if we find it, we can just reuse this! 623 unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters(); 624 for (m_constantUndefined = 0; m_constantUndefined < numberOfConstants; ++m_constantUndefined) { 625 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined); 626 if (testMe.isUndefined()) 627 return getJSConstant(m_constantUndefined); 628 } 629 630 // Add undefined to the CodeBlock's constants, and add a corresponding slot in m_constants. 631 ASSERT(m_constants.size() == numberOfConstants); 632 addConstant(jsUndefined()); 633 m_constants.append(ConstantRecord()); 634 ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); 635 } 636 637 // m_constantUndefined must refer to an entry in the CodeBlock's constant pool that has the value 'undefined'. 638 ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantUndefined).isUndefined()); 639 return getJSConstant(m_constantUndefined); 640 } 641 642 // This method returns a JSConstant with the value 'null'. 643 Node* constantNull() 644 { 645 // Has m_constantNull been set up yet? 646 if (m_constantNull == UINT_MAX) { 647 // Search the constant pool for null, if we find it, we can just reuse this! 648 unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters(); 649 for (m_constantNull = 0; m_constantNull < numberOfConstants; ++m_constantNull) { 650 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull); 651 if (testMe.isNull()) 652 return getJSConstant(m_constantNull); 653 } 654 655 // Add null to the CodeBlock's constants, and add a corresponding slot in m_constants. 656 ASSERT(m_constants.size() == numberOfConstants); 657 addConstant(jsNull()); 658 m_constants.append(ConstantRecord()); 659 ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); 660 } 661 662 // m_constantNull must refer to an entry in the CodeBlock's constant pool that has the value 'null'. 663 ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNull).isNull()); 664 return getJSConstant(m_constantNull); 665 } 666 667 // This method returns a DoubleConstant with the value 1. 668 Node* one() 669 { 670 // Has m_constant1 been set up yet? 671 if (m_constant1 == UINT_MAX) { 672 // Search the constant pool for the value 1, if we find it, we can just reuse this! 673 unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters(); 674 for (m_constant1 = 0; m_constant1 < numberOfConstants; ++m_constant1) { 675 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1); 676 if (testMe.isInt32() && testMe.asInt32() == 1) 677 return getJSConstant(m_constant1); 678 } 679 680 // Add the value 1 to the CodeBlock's constants, and add a corresponding slot in m_constants. 681 ASSERT(m_constants.size() == numberOfConstants); 682 addConstant(jsNumber(1)); 683 m_constants.append(ConstantRecord()); 684 ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); 685 } 686 687 // m_constant1 must refer to an entry in the CodeBlock's constant pool that has the integer value 1. 688 ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).isInt32()); 689 ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constant1).asInt32() == 1); 690 return getJSConstant(m_constant1); 691 } 692 693 // This method returns a DoubleConstant with the value NaN. 694 Node* constantNaN() 695 { 696 JSValue nan = jsNaN(); 697 698 // Has m_constantNaN been set up yet? 699 if (m_constantNaN == UINT_MAX) { 700 // Search the constant pool for the value NaN, if we find it, we can just reuse this! 701 unsigned numberOfConstants = m_codeBlock->numberOfConstantRegisters(); 702 for (m_constantNaN = 0; m_constantNaN < numberOfConstants; ++m_constantNaN) { 703 JSValue testMe = m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN); 704 if (JSValue::encode(testMe) == JSValue::encode(nan)) 705 return getJSConstant(m_constantNaN); 706 } 707 708 // Add the value nan to the CodeBlock's constants, and add a corresponding slot in m_constants. 709 ASSERT(m_constants.size() == numberOfConstants); 710 addConstant(nan); 711 m_constants.append(ConstantRecord()); 712 ASSERT(m_constants.size() == m_codeBlock->numberOfConstantRegisters()); 713 } 714 715 // m_constantNaN must refer to an entry in the CodeBlock's constant pool that has the value nan. 716 ASSERT(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN).isDouble()); 717 ASSERT(std::isnan(m_codeBlock->getConstant(FirstConstantRegisterIndex + m_constantNaN).asDouble())); 718 return getJSConstant(m_constantNaN); 719 } 720 721 Node* cellConstant(JSCell* cell) 722 { 723 HashMap<JSCell*, Node*>::AddResult result = m_cellConstantNodes.add(cell, nullptr); 724 if (result.isNewEntry) { 725 ASSERT(!Heap::isZombified(cell)); 726 result.iterator->value = addToGraph(WeakJSConstant, OpInfo(cell)); 727 } 728 729 return result.iterator->value; 730 } 731 732 Node* inferredConstant(JSValue value) 733 { 734 if (value.isCell()) 735 return cellConstant(value.asCell()); 736 return getJSConstantForValue(value); 737 } 738 739 InlineCallFrame* inlineCallFrame() 740 { 741 return m_inlineStackTop->m_inlineCallFrame; 742 } 743 744 CodeOrigin currentCodeOrigin() 745 { 746 return CodeOrigin(m_currentIndex, inlineCallFrame()); 747 } 748 749 BranchData* branchData(unsigned taken, unsigned notTaken) 750 { 751 // We assume that branches originating from bytecode always have a fall-through. We 752 // use this assumption to avoid checking for the creation of terminal blocks. 753 ASSERT((taken > m_currentIndex) || (notTaken > m_currentIndex)); 754 BranchData* data = m_graph.m_branchData.add(); 755 *data = BranchData::withBytecodeIndices(taken, notTaken); 756 return data; 757 } 758 759 Node* addToGraph(NodeType op, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0) 760 { 761 Node* result = m_graph.addNode( 762 SpecNone, op, NodeOrigin(currentCodeOrigin()), Edge(child1), Edge(child2), 763 Edge(child3)); 764 ASSERT(op != Phi); 765 m_currentBlock->append(result); 766 return result; 767 } 768 Node* addToGraph(NodeType op, Edge child1, Edge child2 = Edge(), Edge child3 = Edge()) 769 { 770 Node* result = m_graph.addNode( 771 SpecNone, op, NodeOrigin(currentCodeOrigin()), child1, child2, child3); 772 ASSERT(op != Phi); 773 m_currentBlock->append(result); 774 return result; 775 } 776 Node* addToGraph(NodeType op, OpInfo info, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0) 777 { 778 Node* result = m_graph.addNode( 779 SpecNone, op, NodeOrigin(currentCodeOrigin()), info, Edge(child1), Edge(child2), 780 Edge(child3)); 781 ASSERT(op != Phi); 782 m_currentBlock->append(result); 783 return result; 784 } 785 Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0) 786 { 787 Node* result = m_graph.addNode( 788 SpecNone, op, NodeOrigin(currentCodeOrigin()), info1, info2, 789 Edge(child1), Edge(child2), Edge(child3)); 790 ASSERT(op != Phi); 791 m_currentBlock->append(result); 792 return result; 793 } 794 795 Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2) 796 { 797 Node* result = m_graph.addNode( 798 SpecNone, Node::VarArg, op, NodeOrigin(currentCodeOrigin()), info1, info2, 799 m_graph.m_varArgChildren.size() - m_numPassedVarArgs, m_numPassedVarArgs); 800 ASSERT(op != Phi); 801 m_currentBlock->append(result); 802 803 m_numPassedVarArgs = 0; 804 805 return result; 806 } 807 808 void addVarArgChild(Node* child) 809 { 810 m_graph.m_varArgChildren.append(Edge(child)); 811 m_numPassedVarArgs++; 812 } 813 814 Node* addCall(int result, NodeType op, int callee, int argCount, int registerOffset) 815 { 816 SpeculatedType prediction = getPrediction(); 817 818 addVarArgChild(get(VirtualRegister(callee))); 819 size_t parameterSlots = JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + argCount; 820 if (parameterSlots > m_parameterSlots) 821 m_parameterSlots = parameterSlots; 822 823 int dummyThisArgument = op == Call ? 0 : 1; 824 for (int i = 0 + dummyThisArgument; i < argCount; ++i) 825 addVarArgChild(get(virtualRegisterForArgument(i, registerOffset))); 826 827 Node* call = addToGraph(Node::VarArg, op, OpInfo(0), OpInfo(prediction)); 828 set(VirtualRegister(result), call); 829 return call; 830 } 831 832 Node* cellConstantWithStructureCheck(JSCell* object, Structure* structure) 833 { 834 Node* objectNode = cellConstant(object); 835 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structure)), objectNode); 836 return objectNode; 837 } 838 839 Node* cellConstantWithStructureCheck(JSCell* object) 840 { 841 return cellConstantWithStructureCheck(object, object->structure()); 842 } 843 844 SpeculatedType getPredictionWithoutOSRExit(unsigned bytecodeIndex) 845 { 846 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 847 return m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(locker, bytecodeIndex); 848 } 849 850 SpeculatedType getPrediction(unsigned bytecodeIndex) 851 { 852 SpeculatedType prediction = getPredictionWithoutOSRExit(bytecodeIndex); 853 854 if (prediction == SpecNone) { 855 // We have no information about what values this node generates. Give up 856 // on executing this code, since we're likely to do more damage than good. 857 addToGraph(ForceOSRExit); 858 } 859 860 return prediction; 861 } 862 863 SpeculatedType getPredictionWithoutOSRExit() 864 { 865 return getPredictionWithoutOSRExit(m_currentIndex); 866 } 867 868 SpeculatedType getPrediction() 869 { 870 return getPrediction(m_currentIndex); 871 } 872 873 ArrayMode getArrayMode(ArrayProfile* profile, Array::Action action) 874 { 875 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 876 profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock); 877 return ArrayMode::fromObserved(locker, profile, action, false); 878 } 879 880 ArrayMode getArrayMode(ArrayProfile* profile) 881 { 882 return getArrayMode(profile, Array::Read); 883 } 884 885 ArrayMode getArrayModeConsideringSlowPath(ArrayProfile* profile, Array::Action action) 886 { 887 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 888 889 profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock); 890 891 bool makeSafe = 892 m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex) 893 || profile->outOfBounds(locker); 894 895 ArrayMode result = ArrayMode::fromObserved(locker, profile, action, makeSafe); 896 897 return result; 898 } 899 900 Node* makeSafe(Node* node) 901 { 902 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) 903 node->mergeFlags(NodeMayOverflowInDFG); 904 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero)) 905 node->mergeFlags(NodeMayNegZeroInDFG); 906 907 if (!isX86() && node->op() == ArithMod) 908 return node; 909 910 if (!m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)) 911 return node; 912 913 switch (node->op()) { 914 case UInt32ToNumber: 915 case ArithAdd: 916 case ArithSub: 917 case ValueAdd: 918 case ArithMod: // for ArithMod "MayOverflow" means we tried to divide by zero, or we saw double. 919 node->mergeFlags(NodeMayOverflowInBaseline); 920 break; 921 922 case ArithNegate: 923 // Currently we can't tell the difference between a negation overflowing 924 // (i.e. -(1 << 31)) or generating negative zero (i.e. -0). If it took slow 925 // path then we assume that it did both of those things. 926 node->mergeFlags(NodeMayOverflowInBaseline); 927 node->mergeFlags(NodeMayNegZeroInBaseline); 928 break; 929 930 case ArithMul: 931 // FIXME: We should detect cases where we only overflowed but never created 932 // negative zero. 933 // https://bugs.webkit.org/show_bug.cgi?id=132470 934 if (m_inlineStackTop->m_profiledBlock->likelyToTakeDeepestSlowCase(m_currentIndex) 935 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) 936 node->mergeFlags(NodeMayOverflowInBaseline | NodeMayNegZeroInBaseline); 937 else if (m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex) 938 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero)) 939 node->mergeFlags(NodeMayNegZeroInBaseline); 940 break; 941 942 default: 943 RELEASE_ASSERT_NOT_REACHED(); 944 break; 945 } 946 947 return node; 948 } 949 950 Node* makeDivSafe(Node* node) 951 { 952 ASSERT(node->op() == ArithDiv); 953 954 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) 955 node->mergeFlags(NodeMayOverflowInDFG); 956 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, NegativeZero)) 957 node->mergeFlags(NodeMayNegZeroInDFG); 958 959 // The main slow case counter for op_div in the old JIT counts only when 960 // the operands are not numbers. We don't care about that since we already 961 // have speculations in place that take care of that separately. We only 962 // care about when the outcome of the division is not an integer, which 963 // is what the special fast case counter tells us. 964 965 if (!m_inlineStackTop->m_profiledBlock->couldTakeSpecialFastCase(m_currentIndex)) 966 return node; 967 968 // FIXME: It might be possible to make this more granular. 969 node->mergeFlags(NodeMayOverflowInBaseline | NodeMayNegZeroInBaseline); 970 971 return node; 972 } 973 974 bool structureChainIsStillValid(bool direct, Structure* previousStructure, StructureChain* chain) 975 { 976 if (direct) 977 return true; 978 979 if (!previousStructure->storedPrototype().isNull() && previousStructure->storedPrototype().asCell()->structure() != chain->head()->get()) 980 return false; 981 982 for (WriteBarrier<Structure>* it = chain->head(); *it; ++it) { 983 if (!(*it)->storedPrototype().isNull() && (*it)->storedPrototype().asCell()->structure() != it[1].get()) 984 return false; 985 } 986 987 return true; 988 } 989 990 void buildOperandMapsIfNecessary(); 991 992 VM* m_vm; 993 CodeBlock* m_codeBlock; 994 CodeBlock* m_profiledBlock; 995 Graph& m_graph; 996 997 // The current block being generated. 998 BasicBlock* m_currentBlock; 999 // The bytecode index of the current instruction being generated. 1000 unsigned m_currentIndex; 1001 1002 // We use these values during code generation, and to avoid the need for 1003 // special handling we make sure they are available as constants in the 1004 // CodeBlock's constant pool. These variables are initialized to 1005 // UINT_MAX, and lazily updated to hold an index into the CodeBlock's 1006 // constant pool, as necessary. 1007 unsigned m_constantUndefined; 1008 unsigned m_constantNull; 1009 unsigned m_constantNaN; 1010 unsigned m_constant1; 1011 HashMap<JSCell*, unsigned> m_cellConstants; 1012 HashMap<JSCell*, Node*> m_cellConstantNodes; 1013 1014 // A constant in the constant pool may be represented by more than one 1015 // node in the graph, depending on the context in which it is being used. 1016 struct ConstantRecord { 1017 ConstantRecord() 1018 : asInt32(0) 1019 , asNumeric(0) 1020 , asJSValue(0) 1021 { 1022 } 1023 1024 Node* asInt32; 1025 Node* asNumeric; 1026 Node* asJSValue; 1027 }; 1028 1029 // Track the index of the node whose result is the current value for every 1030 // register value in the bytecode - argument, local, and temporary. 1031 Vector<ConstantRecord, 16> m_constants; 1032 1033 // The number of arguments passed to the function. 1034 unsigned m_numArguments; 1035 // The number of locals (vars + temporaries) used in the function. 1036 unsigned m_numLocals; 1037 // The number of slots (in units of sizeof(Register)) that we need to 1038 // preallocate for arguments to outgoing calls from this frame. This 1039 // number includes the CallFrame slots that we initialize for the callee 1040 // (but not the callee-initialized CallerFrame and ReturnPC slots). 1041 // This number is 0 if and only if this function is a leaf. 1042 unsigned m_parameterSlots; 1043 // The number of var args passed to the next var arg node. 1044 unsigned m_numPassedVarArgs; 1045 1046 HashMap<ConstantBufferKey, unsigned> m_constantBufferCache; 1047 1048 Vector<VariableWatchpointSet*, 16> m_localWatchpoints; 1049 1050 struct InlineStackEntry { 1051 ByteCodeParser* m_byteCodeParser; 1052 1053 CodeBlock* m_codeBlock; 1054 CodeBlock* m_profiledBlock; 1055 InlineCallFrame* m_inlineCallFrame; 1056 1057 ScriptExecutable* executable() { return m_codeBlock->ownerExecutable(); } 1058 1059 QueryableExitProfile m_exitProfile; 1060 1061 // Remapping of identifier and constant numbers from the code block being 1062 // inlined (inline callee) to the code block that we're inlining into 1063 // (the machine code block, which is the transitive, though not necessarily 1064 // direct, caller). 1065 Vector<unsigned> m_identifierRemap; 1066 Vector<unsigned> m_constantRemap; 1067 Vector<unsigned> m_constantBufferRemap; 1068 Vector<unsigned> m_switchRemap; 1069 1070 // Blocks introduced by this code block, which need successor linking. 1071 // May include up to one basic block that includes the continuation after 1072 // the callsite in the caller. These must be appended in the order that they 1073 // are created, but their bytecodeBegin values need not be in order as they 1074 // are ignored. 1075 Vector<UnlinkedBlock> m_unlinkedBlocks; 1076 1077 // Potential block linking targets. Must be sorted by bytecodeBegin, and 1078 // cannot have two blocks that have the same bytecodeBegin. For this very 1079 // reason, this is not equivalent to 1080 Vector<BasicBlock*> m_blockLinkingTargets; 1081 1082 // If the callsite's basic block was split into two, then this will be 1083 // the head of the callsite block. It needs its successors linked to the 1084 // m_unlinkedBlocks, but not the other way around: there's no way for 1085 // any blocks in m_unlinkedBlocks to jump back into this block. 1086 BasicBlock* m_callsiteBlockHead; 1087 1088 // Does the callsite block head need linking? This is typically true 1089 // but will be false for the machine code block's inline stack entry 1090 // (since that one is not inlined) and for cases where an inline callee 1091 // did the linking for us. 1092 bool m_callsiteBlockHeadNeedsLinking; 1093 1094 VirtualRegister m_returnValue; 1095 1096 // Speculations about variable types collected from the profiled code block, 1097 // which are based on OSR exit profiles that past DFG compilatins of this 1098 // code block had gathered. 1099 LazyOperandValueProfileParser m_lazyOperands; 1100 1101 CallLinkInfoMap m_callLinkInfos; 1102 StubInfoMap m_stubInfos; 1103 1104 // Did we see any returns? We need to handle the (uncommon but necessary) 1105 // case where a procedure that does not return was inlined. 1106 bool m_didReturn; 1107 1108 // Did we have any early returns? 1109 bool m_didEarlyReturn; 1110 1111 // Pointers to the argument position trackers for this slice of code. 1112 Vector<ArgumentPosition*> m_argumentPositions; 1113 1114 InlineStackEntry* m_caller; 1115 1116 InlineStackEntry( 1117 ByteCodeParser*, 1118 CodeBlock*, 1119 CodeBlock* profiledBlock, 1120 BasicBlock* callsiteBlockHead, 1121 JSFunction* callee, // Null if this is a closure call. 1122 VirtualRegister returnValueVR, 1123 VirtualRegister inlineCallFrameStart, 1124 int argumentCountIncludingThis, 1125 CodeSpecializationKind); 1126 1127 ~InlineStackEntry() 1128 { 1129 m_byteCodeParser->m_inlineStackTop = m_caller; 1130 } 1131 1132 VirtualRegister remapOperand(VirtualRegister operand) const 1133 { 1134 if (!m_inlineCallFrame) 1135 return operand; 1136 1137 if (operand.isConstant()) { 1138 VirtualRegister result = VirtualRegister(m_constantRemap[operand.toConstantIndex()]); 1139 ASSERT(result.isConstant()); 1140 return result; 1141 } 1142 1143 return VirtualRegister(operand.offset() + m_inlineCallFrame->stackOffset); 1144 } 1145 }; 1146 1147 InlineStackEntry* m_inlineStackTop; 1148 1149 struct DelayedSetLocal { 1150 VirtualRegister m_operand; 1151 Node* m_value; 1152 1153 DelayedSetLocal() { } 1154 DelayedSetLocal(VirtualRegister operand, Node* value) 1155 : m_operand(operand) 1156 , m_value(value) 1157 { 1158 } 1159 1160 Node* execute(ByteCodeParser* parser, SetMode setMode = NormalSet) 1161 { 1162 if (m_operand.isArgument()) 1163 return parser->setArgument(m_operand, m_value, setMode); 1164 return parser->setLocal(m_operand, m_value, setMode); 1165 } 1166 }; 1167 1168 Vector<DelayedSetLocal, 2> m_setLocalQueue; 1169 1170 // Have we built operand maps? We initialize them lazily, and only when doing 1171 // inlining. 1172 bool m_haveBuiltOperandMaps; 1173 // Mapping between identifier names and numbers. 1174 BorrowedIdentifierMap m_identifierMap; 1175 // Mapping between values and constant numbers. 1176 JSValueMap m_jsValueMap; 1177 // Index of the empty value, or UINT_MAX if there is no mapping. This is a horrible 1178 // work-around for the fact that JSValueMap can't handle "empty" values. 1179 unsigned m_emptyJSValueIndex; 1180 1181 CodeBlock* m_dfgCodeBlock; 1182 CallLinkStatus::ContextMap m_callContextMap; 1183 StubInfoMap m_dfgStubInfos; 1184 1185 Instruction* m_currentInstruction; 1186}; 1187 1188#define NEXT_OPCODE(name) \ 1189 m_currentIndex += OPCODE_LENGTH(name); \ 1190 continue 1191 1192#define LAST_OPCODE(name) \ 1193 m_currentIndex += OPCODE_LENGTH(name); \ 1194 return shouldContinueParsing 1195 1196void ByteCodeParser::handleCall(Instruction* pc, NodeType op, CodeSpecializationKind kind) 1197{ 1198 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct)); 1199 handleCall( 1200 pc[1].u.operand, op, kind, OPCODE_LENGTH(op_call), 1201 pc[2].u.operand, pc[3].u.operand, -pc[4].u.operand); 1202} 1203 1204void ByteCodeParser::handleCall( 1205 int result, NodeType op, CodeSpecializationKind kind, unsigned instructionSize, 1206 int callee, int argumentCountIncludingThis, int registerOffset) 1207{ 1208 ASSERT(registerOffset <= 0); 1209 1210 Node* callTarget = get(VirtualRegister(callee)); 1211 1212 CallLinkStatus callLinkStatus; 1213 1214 if (m_graph.isConstant(callTarget)) { 1215 callLinkStatus = CallLinkStatus( 1216 m_graph.valueOfJSConstant(callTarget)).setIsProved(true); 1217 } else { 1218 callLinkStatus = CallLinkStatus::computeFor( 1219 m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), 1220 m_inlineStackTop->m_callLinkInfos, m_callContextMap); 1221 } 1222 1223 if (!callLinkStatus.canOptimize()) { 1224 // Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically 1225 // that we cannot optimize them. 1226 1227 addCall(result, op, callee, argumentCountIncludingThis, registerOffset); 1228 return; 1229 } 1230 1231 unsigned nextOffset = m_currentIndex + instructionSize; 1232 SpeculatedType prediction = getPrediction(); 1233 1234 if (InternalFunction* function = callLinkStatus.internalFunction()) { 1235 if (handleConstantInternalFunction(result, function, registerOffset, argumentCountIncludingThis, prediction, kind)) { 1236 // This phantoming has to be *after* the code for the intrinsic, to signify that 1237 // the inputs must be kept alive whatever exits the intrinsic may do. 1238 addToGraph(Phantom, callTarget); 1239 emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind); 1240 return; 1241 } 1242 1243 // Can only handle this using the generic call handler. 1244 addCall(result, op, callee, argumentCountIncludingThis, registerOffset); 1245 return; 1246 } 1247 1248 Intrinsic intrinsic = callLinkStatus.intrinsicFor(kind); 1249 if (intrinsic != NoIntrinsic) { 1250 emitFunctionChecks(callLinkStatus, callTarget, registerOffset, kind); 1251 1252 if (handleIntrinsic(result, intrinsic, registerOffset, argumentCountIncludingThis, prediction)) { 1253 // This phantoming has to be *after* the code for the intrinsic, to signify that 1254 // the inputs must be kept alive whatever exits the intrinsic may do. 1255 addToGraph(Phantom, callTarget); 1256 emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind); 1257 if (m_graph.compilation()) 1258 m_graph.compilation()->noticeInlinedCall(); 1259 return; 1260 } 1261 } else if (handleInlining(callTarget, result, callLinkStatus, registerOffset, argumentCountIncludingThis, nextOffset, kind)) { 1262 if (m_graph.compilation()) 1263 m_graph.compilation()->noticeInlinedCall(); 1264 return; 1265 } 1266 1267 addCall(result, op, callee, argumentCountIncludingThis, registerOffset); 1268} 1269 1270void ByteCodeParser::emitFunctionChecks(const CallLinkStatus& callLinkStatus, Node* callTarget, int registerOffset, CodeSpecializationKind kind) 1271{ 1272 Node* thisArgument; 1273 if (kind == CodeForCall) 1274 thisArgument = get(virtualRegisterForArgument(0, registerOffset)); 1275 else 1276 thisArgument = 0; 1277 1278 if (callLinkStatus.isProved()) { 1279 addToGraph(Phantom, callTarget, thisArgument); 1280 return; 1281 } 1282 1283 ASSERT(callLinkStatus.canOptimize()); 1284 1285 if (JSFunction* function = callLinkStatus.function()) 1286 addToGraph(CheckFunction, OpInfo(function), callTarget, thisArgument); 1287 else { 1288 ASSERT(callLinkStatus.structure()); 1289 ASSERT(callLinkStatus.executable()); 1290 1291 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(callLinkStatus.structure())), callTarget); 1292 addToGraph(CheckExecutable, OpInfo(callLinkStatus.executable()), callTarget, thisArgument); 1293 } 1294} 1295 1296void ByteCodeParser::emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind kind) 1297{ 1298 for (int i = kind == CodeForCall ? 0 : 1; i < argumentCountIncludingThis; ++i) 1299 addToGraph(Phantom, get(virtualRegisterForArgument(i, registerOffset))); 1300} 1301 1302bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus& callLinkStatus, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind kind) 1303{ 1304 static const bool verbose = false; 1305 1306 if (verbose) 1307 dataLog("Considering inlining ", callLinkStatus, " into ", currentCodeOrigin(), "\n"); 1308 1309 // First, the really simple checks: do we have an actual JS function? 1310 if (!callLinkStatus.executable()) { 1311 if (verbose) 1312 dataLog(" Failing because there is no executable.\n"); 1313 return false; 1314 } 1315 if (callLinkStatus.executable()->isHostFunction()) { 1316 if (verbose) 1317 dataLog(" Failing because it's a host function.\n"); 1318 return false; 1319 } 1320 1321 FunctionExecutable* executable = jsCast<FunctionExecutable*>(callLinkStatus.executable()); 1322 1323 // Does the number of arguments we're passing match the arity of the target? We currently 1324 // inline only if the number of arguments passed is greater than or equal to the number 1325 // arguments expected. 1326 if (static_cast<int>(executable->parameterCount()) + 1 > argumentCountIncludingThis) { 1327 if (verbose) 1328 dataLog(" Failing because of arity mismatch.\n"); 1329 return false; 1330 } 1331 1332 // Do we have a code block, and does the code block's size match the heuristics/requirements for 1333 // being an inline candidate? We might not have a code block if code was thrown away or if we 1334 // simply hadn't actually made this call yet. We could still theoretically attempt to inline it 1335 // if we had a static proof of what was being called; this might happen for example if you call a 1336 // global function, where watchpointing gives us static information. Overall, it's a rare case 1337 // because we expect that any hot callees would have already been compiled. 1338 CodeBlock* codeBlock = executable->baselineCodeBlockFor(kind); 1339 if (!codeBlock) { 1340 if (verbose) 1341 dataLog(" Failing because no code block available.\n"); 1342 return false; 1343 } 1344 CapabilityLevel capabilityLevel = inlineFunctionForCapabilityLevel( 1345 codeBlock, kind, callLinkStatus.isClosureCall()); 1346 if (!canInline(capabilityLevel)) { 1347 if (verbose) 1348 dataLog(" Failing because the function is not inlineable.\n"); 1349 return false; 1350 } 1351 1352 // Check if the caller is already too large. We do this check here because that's just 1353 // where we happen to also have the callee's code block, and we want that for the 1354 // purpose of unsetting SABI. 1355 if (!isSmallEnoughToInlineCodeInto(m_codeBlock)) { 1356 codeBlock->m_shouldAlwaysBeInlined = false; 1357 if (verbose) 1358 dataLog(" Failing because the caller is too large.\n"); 1359 return false; 1360 } 1361 1362 // FIXME: this should be better at predicting how much bloat we will introduce by inlining 1363 // this function. 1364 // https://bugs.webkit.org/show_bug.cgi?id=127627 1365 1366 // Have we exceeded inline stack depth, or are we trying to inline a recursive call to 1367 // too many levels? If either of these are detected, then don't inline. We adjust our 1368 // heuristics if we are dealing with a function that cannot otherwise be compiled. 1369 1370 unsigned depth = 0; 1371 unsigned recursion = 0; 1372 1373 for (InlineStackEntry* entry = m_inlineStackTop; entry; entry = entry->m_caller) { 1374 ++depth; 1375 if (depth >= Options::maximumInliningDepth()) { 1376 if (verbose) 1377 dataLog(" Failing because depth exceeded.\n"); 1378 return false; 1379 } 1380 1381 if (entry->executable() == executable) { 1382 ++recursion; 1383 if (recursion >= Options::maximumInliningRecursion()) { 1384 if (verbose) 1385 dataLog(" Failing because recursion detected.\n"); 1386 return false; 1387 } 1388 } 1389 } 1390 1391 if (verbose) 1392 dataLog(" Committing to inlining.\n"); 1393 1394 // Now we know without a doubt that we are committed to inlining. So begin the process 1395 // by checking the callee (if necessary) and making sure that arguments and the callee 1396 // are flushed. 1397 emitFunctionChecks(callLinkStatus, callTargetNode, registerOffset, kind); 1398 1399 // FIXME: Don't flush constants! 1400 1401 int inlineCallFrameStart = m_inlineStackTop->remapOperand(VirtualRegister(registerOffset)).offset() + JSStack::CallFrameHeaderSize; 1402 1403 ensureLocals( 1404 VirtualRegister(inlineCallFrameStart).toLocal() + 1 + 1405 JSStack::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters); 1406 1407 size_t argumentPositionStart = m_graph.m_argumentPositions.size(); 1408 1409 InlineStackEntry inlineStackEntry( 1410 this, codeBlock, codeBlock, m_graph.lastBlock(), callLinkStatus.function(), 1411 m_inlineStackTop->remapOperand(VirtualRegister(resultOperand)), 1412 (VirtualRegister)inlineCallFrameStart, argumentCountIncludingThis, kind); 1413 1414 // This is where the actual inlining really happens. 1415 unsigned oldIndex = m_currentIndex; 1416 m_currentIndex = 0; 1417 1418 InlineVariableData inlineVariableData; 1419 inlineVariableData.inlineCallFrame = m_inlineStackTop->m_inlineCallFrame; 1420 inlineVariableData.argumentPositionStart = argumentPositionStart; 1421 inlineVariableData.calleeVariable = 0; 1422 1423 RELEASE_ASSERT( 1424 m_inlineStackTop->m_inlineCallFrame->isClosureCall 1425 == callLinkStatus.isClosureCall()); 1426 if (callLinkStatus.isClosureCall()) { 1427 VariableAccessData* calleeVariable = 1428 set(VirtualRegister(JSStack::Callee), callTargetNode, ImmediateNakedSet)->variableAccessData(); 1429 VariableAccessData* scopeVariable = 1430 set(VirtualRegister(JSStack::ScopeChain), addToGraph(GetScope, callTargetNode), ImmediateNakedSet)->variableAccessData(); 1431 1432 calleeVariable->mergeShouldNeverUnbox(true); 1433 scopeVariable->mergeShouldNeverUnbox(true); 1434 1435 inlineVariableData.calleeVariable = calleeVariable; 1436 } 1437 1438 m_graph.m_inlineVariableData.append(inlineVariableData); 1439 1440 parseCodeBlock(); 1441 1442 m_currentIndex = oldIndex; 1443 1444 // If the inlined code created some new basic blocks, then we have linking to do. 1445 if (inlineStackEntry.m_callsiteBlockHead != m_graph.lastBlock()) { 1446 1447 ASSERT(!inlineStackEntry.m_unlinkedBlocks.isEmpty()); 1448 if (inlineStackEntry.m_callsiteBlockHeadNeedsLinking) 1449 linkBlock(inlineStackEntry.m_callsiteBlockHead, inlineStackEntry.m_blockLinkingTargets); 1450 else 1451 ASSERT(inlineStackEntry.m_callsiteBlockHead->isLinked); 1452 1453 // It's possible that the callsite block head is not owned by the caller. 1454 if (!inlineStackEntry.m_caller->m_unlinkedBlocks.isEmpty()) { 1455 // It's definitely owned by the caller, because the caller created new blocks. 1456 // Assert that this all adds up. 1457 ASSERT(inlineStackEntry.m_caller->m_unlinkedBlocks.last().m_block == inlineStackEntry.m_callsiteBlockHead); 1458 ASSERT(inlineStackEntry.m_caller->m_unlinkedBlocks.last().m_needsNormalLinking); 1459 inlineStackEntry.m_caller->m_unlinkedBlocks.last().m_needsNormalLinking = false; 1460 } else { 1461 // It's definitely not owned by the caller. Tell the caller that he does not 1462 // need to link his callsite block head, because we did it for him. 1463 ASSERT(inlineStackEntry.m_caller->m_callsiteBlockHeadNeedsLinking); 1464 ASSERT(inlineStackEntry.m_caller->m_callsiteBlockHead == inlineStackEntry.m_callsiteBlockHead); 1465 inlineStackEntry.m_caller->m_callsiteBlockHeadNeedsLinking = false; 1466 } 1467 1468 linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets); 1469 } else 1470 ASSERT(inlineStackEntry.m_unlinkedBlocks.isEmpty()); 1471 1472 BasicBlock* lastBlock = m_graph.lastBlock(); 1473 // If there was a return, but no early returns, then we're done. We allow parsing of 1474 // the caller to continue in whatever basic block we're in right now. 1475 if (!inlineStackEntry.m_didEarlyReturn && inlineStackEntry.m_didReturn) { 1476 ASSERT(lastBlock->isEmpty() || !lastBlock->last()->isTerminal()); 1477 1478 // If we created new blocks then the last block needs linking, but in the 1479 // caller. It doesn't need to be linked to, but it needs outgoing links. 1480 if (!inlineStackEntry.m_unlinkedBlocks.isEmpty()) { 1481 // For debugging purposes, set the bytecodeBegin. Note that this doesn't matter 1482 // for release builds because this block will never serve as a potential target 1483 // in the linker's binary search. 1484 lastBlock->bytecodeBegin = m_currentIndex; 1485 m_inlineStackTop->m_caller->m_unlinkedBlocks.append(UnlinkedBlock(m_graph.lastBlock())); 1486 } 1487 1488 m_currentBlock = m_graph.lastBlock(); 1489 return true; 1490 } 1491 1492 // If we get to this point then all blocks must end in some sort of terminals. 1493 ASSERT(lastBlock->last()->isTerminal()); 1494 1495 1496 // Need to create a new basic block for the continuation at the caller. 1497 RefPtr<BasicBlock> block = adoptRef(new BasicBlock(nextOffset, m_numArguments, m_numLocals, PNaN)); 1498 1499 // Link the early returns to the basic block we're about to create. 1500 for (size_t i = 0; i < inlineStackEntry.m_unlinkedBlocks.size(); ++i) { 1501 if (!inlineStackEntry.m_unlinkedBlocks[i].m_needsEarlyReturnLinking) 1502 continue; 1503 BasicBlock* blockToLink = inlineStackEntry.m_unlinkedBlocks[i].m_block; 1504 ASSERT(!blockToLink->isLinked); 1505 Node* node = blockToLink->last(); 1506 ASSERT(node->op() == Jump); 1507 ASSERT(!node->targetBlock()); 1508 node->targetBlock() = block.get(); 1509 inlineStackEntry.m_unlinkedBlocks[i].m_needsEarlyReturnLinking = false; 1510#if !ASSERT_DISABLED 1511 blockToLink->isLinked = true; 1512#endif 1513 } 1514 1515 m_currentBlock = block.get(); 1516 ASSERT(m_inlineStackTop->m_caller->m_blockLinkingTargets.isEmpty() || m_inlineStackTop->m_caller->m_blockLinkingTargets.last()->bytecodeBegin < nextOffset); 1517 m_inlineStackTop->m_caller->m_unlinkedBlocks.append(UnlinkedBlock(block.get())); 1518 m_inlineStackTop->m_caller->m_blockLinkingTargets.append(block.get()); 1519 m_graph.appendBlock(block); 1520 prepareToParseBlock(); 1521 1522 // At this point we return and continue to generate code for the caller, but 1523 // in the new basic block. 1524 return true; 1525} 1526 1527bool ByteCodeParser::handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis) 1528{ 1529 if (argumentCountIncludingThis == 1) { // Math.min() 1530 set(VirtualRegister(resultOperand), constantNaN()); 1531 return true; 1532 } 1533 1534 if (argumentCountIncludingThis == 2) { // Math.min(x) 1535 Node* result = get(VirtualRegister(virtualRegisterForArgument(1, registerOffset))); 1536 addToGraph(Phantom, Edge(result, NumberUse)); 1537 set(VirtualRegister(resultOperand), result); 1538 return true; 1539 } 1540 1541 if (argumentCountIncludingThis == 3) { // Math.min(x, y) 1542 set(VirtualRegister(resultOperand), addToGraph(op, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)))); 1543 return true; 1544 } 1545 1546 // Don't handle >=3 arguments for now. 1547 return false; 1548} 1549 1550bool ByteCodeParser::handleIntrinsic(int resultOperand, Intrinsic intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction) 1551{ 1552 switch (intrinsic) { 1553 case AbsIntrinsic: { 1554 if (argumentCountIncludingThis == 1) { // Math.abs() 1555 set(VirtualRegister(resultOperand), constantNaN()); 1556 return true; 1557 } 1558 1559 if (!MacroAssembler::supportsFloatingPointAbs()) 1560 return false; 1561 1562 Node* node = addToGraph(ArithAbs, get(virtualRegisterForArgument(1, registerOffset))); 1563 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) 1564 node->mergeFlags(NodeMayOverflowInDFG); 1565 set(VirtualRegister(resultOperand), node); 1566 return true; 1567 } 1568 1569 case MinIntrinsic: 1570 return handleMinMax(resultOperand, ArithMin, registerOffset, argumentCountIncludingThis); 1571 1572 case MaxIntrinsic: 1573 return handleMinMax(resultOperand, ArithMax, registerOffset, argumentCountIncludingThis); 1574 1575 case SqrtIntrinsic: 1576 case CosIntrinsic: 1577 case SinIntrinsic: { 1578 if (argumentCountIncludingThis == 1) { 1579 set(VirtualRegister(resultOperand), constantNaN()); 1580 return true; 1581 } 1582 1583 switch (intrinsic) { 1584 case SqrtIntrinsic: 1585 if (!MacroAssembler::supportsFloatingPointSqrt()) 1586 return false; 1587 1588 set(VirtualRegister(resultOperand), addToGraph(ArithSqrt, get(virtualRegisterForArgument(1, registerOffset)))); 1589 return true; 1590 1591 case CosIntrinsic: 1592 set(VirtualRegister(resultOperand), addToGraph(ArithCos, get(virtualRegisterForArgument(1, registerOffset)))); 1593 return true; 1594 1595 case SinIntrinsic: 1596 set(VirtualRegister(resultOperand), addToGraph(ArithSin, get(virtualRegisterForArgument(1, registerOffset)))); 1597 return true; 1598 1599 default: 1600 RELEASE_ASSERT_NOT_REACHED(); 1601 return false; 1602 } 1603 } 1604 1605 case ArrayPushIntrinsic: { 1606 if (argumentCountIncludingThis != 2) 1607 return false; 1608 1609 ArrayMode arrayMode = getArrayMode(m_currentInstruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile); 1610 if (!arrayMode.isJSArray()) 1611 return false; 1612 switch (arrayMode.type()) { 1613 case Array::Undecided: 1614 case Array::Int32: 1615 case Array::Double: 1616 case Array::Contiguous: 1617 case Array::ArrayStorage: { 1618 Node* arrayPush = addToGraph(ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); 1619 set(VirtualRegister(resultOperand), arrayPush); 1620 1621 return true; 1622 } 1623 1624 default: 1625 return false; 1626 } 1627 } 1628 1629 case ArrayPopIntrinsic: { 1630 if (argumentCountIncludingThis != 1) 1631 return false; 1632 1633 ArrayMode arrayMode = getArrayMode(m_currentInstruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile); 1634 if (!arrayMode.isJSArray()) 1635 return false; 1636 switch (arrayMode.type()) { 1637 case Array::Int32: 1638 case Array::Double: 1639 case Array::Contiguous: 1640 case Array::ArrayStorage: { 1641 Node* arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset))); 1642 set(VirtualRegister(resultOperand), arrayPop); 1643 return true; 1644 } 1645 1646 default: 1647 return false; 1648 } 1649 } 1650 1651 case CharCodeAtIntrinsic: { 1652 if (argumentCountIncludingThis != 2) 1653 return false; 1654 1655 VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); 1656 VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); 1657 Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), get(indexOperand)); 1658 1659 set(VirtualRegister(resultOperand), charCode); 1660 return true; 1661 } 1662 1663 case CharAtIntrinsic: { 1664 if (argumentCountIncludingThis != 2) 1665 return false; 1666 1667 VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); 1668 VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); 1669 Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String).asWord()), get(thisOperand), get(indexOperand)); 1670 1671 set(VirtualRegister(resultOperand), charCode); 1672 return true; 1673 } 1674 case FromCharCodeIntrinsic: { 1675 if (argumentCountIncludingThis != 2) 1676 return false; 1677 1678 VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); 1679 Node* charCode = addToGraph(StringFromCharCode, get(indexOperand)); 1680 1681 set(VirtualRegister(resultOperand), charCode); 1682 1683 return true; 1684 } 1685 1686 case RegExpExecIntrinsic: { 1687 if (argumentCountIncludingThis != 2) 1688 return false; 1689 1690 Node* regExpExec = addToGraph(RegExpExec, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); 1691 set(VirtualRegister(resultOperand), regExpExec); 1692 1693 return true; 1694 } 1695 1696 case RegExpTestIntrinsic: { 1697 if (argumentCountIncludingThis != 2) 1698 return false; 1699 1700 Node* regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); 1701 set(VirtualRegister(resultOperand), regExpExec); 1702 1703 return true; 1704 } 1705 1706 case IMulIntrinsic: { 1707 if (argumentCountIncludingThis != 3) 1708 return false; 1709 VirtualRegister leftOperand = virtualRegisterForArgument(1, registerOffset); 1710 VirtualRegister rightOperand = virtualRegisterForArgument(2, registerOffset); 1711 Node* left = get(leftOperand); 1712 Node* right = get(rightOperand); 1713 set(VirtualRegister(resultOperand), addToGraph(ArithIMul, left, right)); 1714 return true; 1715 } 1716 1717 case FRoundIntrinsic: { 1718 if (argumentCountIncludingThis != 2) 1719 return false; 1720 VirtualRegister operand = virtualRegisterForArgument(1, registerOffset); 1721 set(VirtualRegister(resultOperand), addToGraph(ArithFRound, get(operand))); 1722 return true; 1723 } 1724 1725 case DFGTrueIntrinsic: { 1726 set(VirtualRegister(resultOperand), getJSConstantForValue(jsBoolean(true))); 1727 return true; 1728 } 1729 1730 case OSRExitIntrinsic: { 1731 addToGraph(ForceOSRExit); 1732 set(VirtualRegister(resultOperand), constantUndefined()); 1733 return true; 1734 } 1735 1736 case IsFinalTierIntrinsic: { 1737 set(VirtualRegister(resultOperand), 1738 getJSConstantForValue(jsBoolean(Options::useFTLJIT() ? isFTL(m_graph.m_plan.mode) : true))); 1739 return true; 1740 } 1741 1742 case SetInt32HeapPredictionIntrinsic: { 1743 for (int i = 1; i < argumentCountIncludingThis; ++i) { 1744 Node* node = get(virtualRegisterForArgument(i, registerOffset)); 1745 if (node->hasHeapPrediction()) 1746 node->setHeapPrediction(SpecInt32); 1747 } 1748 set(VirtualRegister(resultOperand), constantUndefined()); 1749 return true; 1750 } 1751 1752 case FiatInt52Intrinsic: { 1753 if (argumentCountIncludingThis != 2) 1754 return false; 1755 VirtualRegister operand = virtualRegisterForArgument(1, registerOffset); 1756 if (enableInt52()) 1757 set(VirtualRegister(resultOperand), addToGraph(FiatInt52, get(operand))); 1758 else 1759 set(VirtualRegister(resultOperand), get(operand)); 1760 return true; 1761 } 1762 1763 default: 1764 return false; 1765 } 1766} 1767 1768bool ByteCodeParser::handleTypedArrayConstructor( 1769 int resultOperand, InternalFunction* function, int registerOffset, 1770 int argumentCountIncludingThis, TypedArrayType type) 1771{ 1772 if (!isTypedView(type)) 1773 return false; 1774 1775 if (function->classInfo() != constructorClassInfoForType(type)) 1776 return false; 1777 1778 if (function->globalObject() != m_inlineStackTop->m_codeBlock->globalObject()) 1779 return false; 1780 1781 // We only have an intrinsic for the case where you say: 1782 // 1783 // new FooArray(blah); 1784 // 1785 // Of course, 'blah' could be any of the following: 1786 // 1787 // - Integer, indicating that you want to allocate an array of that length. 1788 // This is the thing we're hoping for, and what we can actually do meaningful 1789 // optimizations for. 1790 // 1791 // - Array buffer, indicating that you want to create a view onto that _entire_ 1792 // buffer. 1793 // 1794 // - Non-buffer object, indicating that you want to create a copy of that 1795 // object by pretending that it quacks like an array. 1796 // 1797 // - Anything else, indicating that you want to have an exception thrown at 1798 // you. 1799 // 1800 // The intrinsic, NewTypedArray, will behave as if it could do any of these 1801 // things up until we do Fixup. Thereafter, if child1 (i.e. 'blah') is 1802 // predicted Int32, then we lock it in as a normal typed array allocation. 1803 // Otherwise, NewTypedArray turns into a totally opaque function call that 1804 // may clobber the world - by virtue of it accessing properties on what could 1805 // be an object. 1806 // 1807 // Note that although the generic form of NewTypedArray sounds sort of awful, 1808 // it is actually quite likely to be more efficient than a fully generic 1809 // Construct. So, we might want to think about making NewTypedArray variadic, 1810 // or else making Construct not super slow. 1811 1812 if (argumentCountIncludingThis != 2) 1813 return false; 1814 1815 set(VirtualRegister(resultOperand), 1816 addToGraph(NewTypedArray, OpInfo(type), get(virtualRegisterForArgument(1, registerOffset)))); 1817 return true; 1818} 1819 1820bool ByteCodeParser::handleConstantInternalFunction( 1821 int resultOperand, InternalFunction* function, int registerOffset, 1822 int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind kind) 1823{ 1824 // If we ever find that we have a lot of internal functions that we specialize for, 1825 // then we should probably have some sort of hashtable dispatch, or maybe even 1826 // dispatch straight through the MethodTable of the InternalFunction. But for now, 1827 // it seems that this case is hit infrequently enough, and the number of functions 1828 // we know about is small enough, that having just a linear cascade of if statements 1829 // is good enough. 1830 1831 UNUSED_PARAM(prediction); // Remove this once we do more things. 1832 1833 if (function->classInfo() == ArrayConstructor::info()) { 1834 if (function->globalObject() != m_inlineStackTop->m_codeBlock->globalObject()) 1835 return false; 1836 1837 if (argumentCountIncludingThis == 2) { 1838 set(VirtualRegister(resultOperand), 1839 addToGraph(NewArrayWithSize, OpInfo(ArrayWithUndecided), get(virtualRegisterForArgument(1, registerOffset)))); 1840 return true; 1841 } 1842 1843 for (int i = 1; i < argumentCountIncludingThis; ++i) 1844 addVarArgChild(get(virtualRegisterForArgument(i, registerOffset))); 1845 set(VirtualRegister(resultOperand), 1846 addToGraph(Node::VarArg, NewArray, OpInfo(ArrayWithUndecided), OpInfo(0))); 1847 return true; 1848 } 1849 1850 if (function->classInfo() == StringConstructor::info()) { 1851 Node* result; 1852 1853 if (argumentCountIncludingThis <= 1) 1854 result = cellConstant(m_vm->smallStrings.emptyString()); 1855 else 1856 result = addToGraph(ToString, get(virtualRegisterForArgument(1, registerOffset))); 1857 1858 if (kind == CodeForConstruct) 1859 result = addToGraph(NewStringObject, OpInfo(function->globalObject()->stringObjectStructure()), result); 1860 1861 set(VirtualRegister(resultOperand), result); 1862 return true; 1863 } 1864 1865 for (unsigned typeIndex = 0; typeIndex < NUMBER_OF_TYPED_ARRAY_TYPES; ++typeIndex) { 1866 bool result = handleTypedArrayConstructor( 1867 resultOperand, function, registerOffset, argumentCountIncludingThis, 1868 indexToTypedArrayType(typeIndex)); 1869 if (result) 1870 return true; 1871 } 1872 1873 return false; 1874} 1875 1876Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, unsigned identifierNumber, PropertyOffset offset) 1877{ 1878 Node* propertyStorage; 1879 if (isInlineOffset(offset)) 1880 propertyStorage = base; 1881 else 1882 propertyStorage = addToGraph(GetButterfly, base); 1883 Node* getByOffset = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage, base); 1884 1885 StorageAccessData storageAccessData; 1886 storageAccessData.offset = offset; 1887 storageAccessData.identifierNumber = identifierNumber; 1888 m_graph.m_storageAccessData.append(storageAccessData); 1889 1890 return getByOffset; 1891} 1892 1893void ByteCodeParser::handleGetByOffset( 1894 int destinationOperand, SpeculatedType prediction, Node* base, unsigned identifierNumber, 1895 PropertyOffset offset) 1896{ 1897 set(VirtualRegister(destinationOperand), handleGetByOffset(prediction, base, identifierNumber, offset)); 1898} 1899 1900Node* ByteCodeParser::handlePutByOffset(Node* base, unsigned identifier, PropertyOffset offset, Node* value) 1901{ 1902 Node* propertyStorage; 1903 if (isInlineOffset(offset)) 1904 propertyStorage = base; 1905 else 1906 propertyStorage = addToGraph(GetButterfly, base); 1907 Node* result = addToGraph(PutByOffset, OpInfo(m_graph.m_storageAccessData.size()), propertyStorage, base, value); 1908 1909 StorageAccessData storageAccessData; 1910 storageAccessData.offset = offset; 1911 storageAccessData.identifierNumber = identifier; 1912 m_graph.m_storageAccessData.append(storageAccessData); 1913 1914 return result; 1915} 1916 1917Node* ByteCodeParser::emitPrototypeChecks( 1918 Structure* structure, IntendedStructureChain* chain) 1919{ 1920 Node* base = 0; 1921 m_graph.chains().addLazily(chain); 1922 Structure* currentStructure = structure; 1923 JSObject* currentObject = 0; 1924 for (unsigned i = 0; i < chain->size(); ++i) { 1925 currentObject = asObject(currentStructure->prototypeForLookup(m_inlineStackTop->m_codeBlock)); 1926 currentStructure = chain->at(i); 1927 base = cellConstantWithStructureCheck(currentObject, currentStructure); 1928 } 1929 return base; 1930} 1931 1932void ByteCodeParser::handleGetById( 1933 int destinationOperand, SpeculatedType prediction, Node* base, unsigned identifierNumber, 1934 const GetByIdStatus& getByIdStatus) 1935{ 1936 if (!getByIdStatus.isSimple() || !Options::enableAccessInlining()) { 1937 set(VirtualRegister(destinationOperand), 1938 addToGraph( 1939 getByIdStatus.makesCalls() ? GetByIdFlush : GetById, 1940 OpInfo(identifierNumber), OpInfo(prediction), base)); 1941 return; 1942 } 1943 1944 if (getByIdStatus.numVariants() > 1) { 1945 if (!isFTL(m_graph.m_plan.mode) || !Options::enablePolymorphicAccessInlining()) { 1946 set(VirtualRegister(destinationOperand), 1947 addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); 1948 return; 1949 } 1950 1951 if (m_graph.compilation()) 1952 m_graph.compilation()->noticeInlinedGetById(); 1953 1954 // 1) Emit prototype structure checks for all chains. This could sort of maybe not be 1955 // optimal, if there is some rarely executed case in the chain that requires a lot 1956 // of checks and those checks are not watchpointable. 1957 for (unsigned variantIndex = getByIdStatus.numVariants(); variantIndex--;) { 1958 if (getByIdStatus[variantIndex].chain()) { 1959 emitPrototypeChecks( 1960 getByIdStatus[variantIndex].structureSet().singletonStructure(), 1961 getByIdStatus[variantIndex].chain()); 1962 } 1963 } 1964 1965 // 2) Emit a MultiGetByOffset 1966 MultiGetByOffsetData* data = m_graph.m_multiGetByOffsetData.add(); 1967 data->variants = getByIdStatus.variants(); 1968 data->identifierNumber = identifierNumber; 1969 set(VirtualRegister(destinationOperand), 1970 addToGraph(MultiGetByOffset, OpInfo(data), OpInfo(prediction), base)); 1971 return; 1972 } 1973 1974 ASSERT(getByIdStatus.numVariants() == 1); 1975 GetByIdVariant variant = getByIdStatus[0]; 1976 1977 if (m_graph.compilation()) 1978 m_graph.compilation()->noticeInlinedGetById(); 1979 1980 Node* originalBaseForBaselineJIT = base; 1981 1982 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), base); 1983 1984 if (variant.chain()) { 1985 base = emitPrototypeChecks( 1986 variant.structureSet().singletonStructure(), variant.chain()); 1987 } 1988 1989 // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to 1990 // ensure that the base of the original get_by_id is kept alive until we're done with 1991 // all of the speculations. We only insert the Phantom if there had been a CheckStructure 1992 // on something other than the base following the CheckStructure on base, or if the 1993 // access was compiled to a WeakJSConstant specific value, in which case we might not 1994 // have any explicit use of the base at all. 1995 if (variant.specificValue() || originalBaseForBaselineJIT != base) 1996 addToGraph(Phantom, originalBaseForBaselineJIT); 1997 1998 if (variant.specificValue()) { 1999 ASSERT(variant.specificValue().isCell()); 2000 2001 set(VirtualRegister(destinationOperand), cellConstant(variant.specificValue().asCell())); 2002 return; 2003 } 2004 2005 handleGetByOffset( 2006 destinationOperand, prediction, base, identifierNumber, variant.offset()); 2007} 2008 2009void ByteCodeParser::emitPutById( 2010 Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus& putByIdStatus, bool isDirect) 2011{ 2012 if (isDirect) 2013 addToGraph(PutByIdDirect, OpInfo(identifierNumber), base, value); 2014 else 2015 addToGraph(putByIdStatus.makesCalls() ? PutByIdFlush : PutById, OpInfo(identifierNumber), base, value); 2016} 2017 2018void ByteCodeParser::handlePutById( 2019 Node* base, unsigned identifierNumber, Node* value, 2020 const PutByIdStatus& putByIdStatus, bool isDirect) 2021{ 2022 if (!putByIdStatus.isSimple() || !Options::enableAccessInlining()) { 2023 if (!putByIdStatus.isSet()) 2024 addToGraph(ForceOSRExit); 2025 emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); 2026 return; 2027 } 2028 2029 if (putByIdStatus.numVariants() > 1) { 2030 if (!isFTL(m_graph.m_plan.mode) || putByIdStatus.makesCalls() 2031 || !Options::enablePolymorphicAccessInlining()) { 2032 emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); 2033 return; 2034 } 2035 2036 if (m_graph.compilation()) 2037 m_graph.compilation()->noticeInlinedPutById(); 2038 2039 if (!isDirect) { 2040 for (unsigned variantIndex = putByIdStatus.numVariants(); variantIndex--;) { 2041 if (putByIdStatus[variantIndex].kind() != PutByIdVariant::Transition) 2042 continue; 2043 if (!putByIdStatus[variantIndex].structureChain()) 2044 continue; 2045 emitPrototypeChecks( 2046 putByIdStatus[variantIndex].oldStructure(), 2047 putByIdStatus[variantIndex].structureChain()); 2048 } 2049 } 2050 2051 MultiPutByOffsetData* data = m_graph.m_multiPutByOffsetData.add(); 2052 data->variants = putByIdStatus.variants(); 2053 data->identifierNumber = identifierNumber; 2054 addToGraph(MultiPutByOffset, OpInfo(data), base, value); 2055 return; 2056 } 2057 2058 ASSERT(putByIdStatus.numVariants() == 1); 2059 const PutByIdVariant& variant = putByIdStatus[0]; 2060 2061 if (variant.kind() == PutByIdVariant::Replace) { 2062 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structure())), base); 2063 handlePutByOffset(base, identifierNumber, variant.offset(), value); 2064 if (m_graph.compilation()) 2065 m_graph.compilation()->noticeInlinedPutById(); 2066 return; 2067 } 2068 2069 if (variant.kind() != PutByIdVariant::Transition) { 2070 emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); 2071 return; 2072 } 2073 2074 if (variant.structureChain() && !variant.structureChain()->isStillValid()) { 2075 emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); 2076 return; 2077 } 2078 2079 m_graph.chains().addLazily(variant.structureChain()); 2080 2081 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base); 2082 if (!isDirect) 2083 emitPrototypeChecks(variant.oldStructure(), variant.structureChain()); 2084 2085 ASSERT(variant.oldStructure()->transitionWatchpointSetHasBeenInvalidated()); 2086 2087 Node* propertyStorage; 2088 StructureTransitionData* transitionData = m_graph.addStructureTransitionData( 2089 StructureTransitionData(variant.oldStructure(), variant.newStructure())); 2090 2091 if (variant.oldStructure()->outOfLineCapacity() 2092 != variant.newStructure()->outOfLineCapacity()) { 2093 2094 // If we're growing the property storage then it must be because we're 2095 // storing into the out-of-line storage. 2096 ASSERT(!isInlineOffset(variant.offset())); 2097 2098 if (!variant.oldStructure()->outOfLineCapacity()) { 2099 propertyStorage = addToGraph( 2100 AllocatePropertyStorage, OpInfo(transitionData), base); 2101 } else { 2102 propertyStorage = addToGraph( 2103 ReallocatePropertyStorage, OpInfo(transitionData), 2104 base, addToGraph(GetButterfly, base)); 2105 } 2106 } else { 2107 if (isInlineOffset(variant.offset())) 2108 propertyStorage = base; 2109 else 2110 propertyStorage = addToGraph(GetButterfly, base); 2111 } 2112 2113 addToGraph(PutStructure, OpInfo(transitionData), base); 2114 2115 addToGraph( 2116 PutByOffset, 2117 OpInfo(m_graph.m_storageAccessData.size()), 2118 propertyStorage, 2119 base, 2120 value); 2121 2122 StorageAccessData storageAccessData; 2123 storageAccessData.offset = variant.offset(); 2124 storageAccessData.identifierNumber = identifierNumber; 2125 m_graph.m_storageAccessData.append(storageAccessData); 2126 2127 if (m_graph.compilation()) 2128 m_graph.compilation()->noticeInlinedPutById(); 2129} 2130 2131void ByteCodeParser::prepareToParseBlock() 2132{ 2133 for (unsigned i = 0; i < m_constants.size(); ++i) 2134 m_constants[i] = ConstantRecord(); 2135 m_cellConstantNodes.clear(); 2136} 2137 2138Node* ByteCodeParser::getScope(bool skipTop, unsigned skipCount) 2139{ 2140 Node* localBase = get(VirtualRegister(JSStack::ScopeChain)); 2141 if (skipTop) { 2142 ASSERT(!inlineCallFrame()); 2143 localBase = addToGraph(SkipTopScope, localBase); 2144 } 2145 for (unsigned n = skipCount; n--;) 2146 localBase = addToGraph(SkipScope, localBase); 2147 return localBase; 2148} 2149 2150bool ByteCodeParser::parseBlock(unsigned limit) 2151{ 2152 bool shouldContinueParsing = true; 2153 2154 Interpreter* interpreter = m_vm->interpreter; 2155 Instruction* instructionsBegin = m_inlineStackTop->m_codeBlock->instructions().begin(); 2156 unsigned blockBegin = m_currentIndex; 2157 2158 // If we are the first basic block, introduce markers for arguments. This allows 2159 // us to track if a use of an argument may use the actual argument passed, as 2160 // opposed to using a value we set explicitly. 2161 if (m_currentBlock == m_graph.block(0) && !inlineCallFrame()) { 2162 m_graph.m_arguments.resize(m_numArguments); 2163 for (unsigned argument = 0; argument < m_numArguments; ++argument) { 2164 VariableAccessData* variable = newVariableAccessData( 2165 virtualRegisterForArgument(argument), m_codeBlock->isCaptured(virtualRegisterForArgument(argument))); 2166 variable->mergeStructureCheckHoistingFailed( 2167 m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) 2168 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCacheWatchpoint)); 2169 variable->mergeCheckArrayHoistingFailed( 2170 m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType)); 2171 2172 Node* setArgument = addToGraph(SetArgument, OpInfo(variable)); 2173 m_graph.m_arguments[argument] = setArgument; 2174 m_currentBlock->variablesAtTail.setArgumentFirstTime(argument, setArgument); 2175 } 2176 } 2177 2178 while (true) { 2179 for (unsigned i = 0; i < m_setLocalQueue.size(); ++i) 2180 m_setLocalQueue[i].execute(this); 2181 m_setLocalQueue.resize(0); 2182 2183 // Don't extend over jump destinations. 2184 if (m_currentIndex == limit) { 2185 // Ordinarily we want to plant a jump. But refuse to do this if the block is 2186 // empty. This is a special case for inlining, which might otherwise create 2187 // some empty blocks in some cases. When parseBlock() returns with an empty 2188 // block, it will get repurposed instead of creating a new one. Note that this 2189 // logic relies on every bytecode resulting in one or more nodes, which would 2190 // be true anyway except for op_loop_hint, which emits a Phantom to force this 2191 // to be true. 2192 if (!m_currentBlock->isEmpty()) 2193 addToGraph(Jump, OpInfo(m_currentIndex)); 2194 return shouldContinueParsing; 2195 } 2196 2197 // Switch on the current bytecode opcode. 2198 Instruction* currentInstruction = instructionsBegin + m_currentIndex; 2199 m_currentInstruction = currentInstruction; // Some methods want to use this, and we'd rather not thread it through calls. 2200 OpcodeID opcodeID = interpreter->getOpcodeID(currentInstruction->u.opcode); 2201 2202 if (Options::verboseDFGByteCodeParsing()) 2203 dataLog(" parsing ", currentCodeOrigin(), "\n"); 2204 2205 if (m_graph.compilation()) { 2206 addToGraph(CountExecution, OpInfo(m_graph.compilation()->executionCounterFor( 2207 Profiler::OriginStack(*m_vm->m_perBytecodeProfiler, m_codeBlock, currentCodeOrigin())))); 2208 } 2209 2210 switch (opcodeID) { 2211 2212 // === Function entry opcodes === 2213 2214 case op_enter: 2215 // Initialize all locals to undefined. 2216 for (int i = 0; i < m_inlineStackTop->m_codeBlock->m_numVars; ++i) 2217 set(virtualRegisterForLocal(i), constantUndefined(), ImmediateNakedSet); 2218 if (m_inlineStackTop->m_codeBlock->specializationKind() == CodeForConstruct) 2219 set(virtualRegisterForArgument(0), constantUndefined(), ImmediateNakedSet); 2220 NEXT_OPCODE(op_enter); 2221 2222 case op_touch_entry: 2223 if (m_inlineStackTop->m_codeBlock->symbolTable()->m_functionEnteredOnce.isStillValid()) 2224 addToGraph(ForceOSRExit); 2225 NEXT_OPCODE(op_touch_entry); 2226 2227 case op_to_this: { 2228 Node* op1 = getThis(); 2229 if (op1->op() != ToThis) { 2230 Structure* cachedStructure = currentInstruction[2].u.structure.get(); 2231 if (!cachedStructure 2232 || cachedStructure->classInfo()->methodTable.toThis != JSObject::info()->methodTable.toThis 2233 || m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) 2234 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) 2235 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCacheWatchpoint) 2236 || (op1->op() == GetLocal && op1->variableAccessData()->structureCheckHoistingFailed())) { 2237 setThis(addToGraph(ToThis, op1)); 2238 } else { 2239 addToGraph( 2240 CheckStructure, 2241 OpInfo(m_graph.addStructureSet(cachedStructure)), 2242 op1); 2243 } 2244 } 2245 NEXT_OPCODE(op_to_this); 2246 } 2247 2248 case op_create_this: { 2249 int calleeOperand = currentInstruction[2].u.operand; 2250 Node* callee = get(VirtualRegister(calleeOperand)); 2251 bool alreadyEmitted = false; 2252 if (callee->op() == WeakJSConstant) { 2253 JSCell* cell = callee->weakConstant(); 2254 ASSERT(cell->inherits(JSFunction::info())); 2255 2256 JSFunction* function = jsCast<JSFunction*>(cell); 2257 if (Structure* structure = function->allocationStructure()) { 2258 addToGraph(AllocationProfileWatchpoint, OpInfo(function)); 2259 // The callee is still live up to this point. 2260 addToGraph(Phantom, callee); 2261 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewObject, OpInfo(structure))); 2262 alreadyEmitted = true; 2263 } 2264 } 2265 if (!alreadyEmitted) { 2266 set(VirtualRegister(currentInstruction[1].u.operand), 2267 addToGraph(CreateThis, OpInfo(currentInstruction[3].u.operand), callee)); 2268 } 2269 NEXT_OPCODE(op_create_this); 2270 } 2271 2272 case op_new_object: { 2273 set(VirtualRegister(currentInstruction[1].u.operand), 2274 addToGraph(NewObject, 2275 OpInfo(currentInstruction[3].u.objectAllocationProfile->structure()))); 2276 NEXT_OPCODE(op_new_object); 2277 } 2278 2279 case op_new_array: { 2280 int startOperand = currentInstruction[2].u.operand; 2281 int numOperands = currentInstruction[3].u.operand; 2282 ArrayAllocationProfile* profile = currentInstruction[4].u.arrayAllocationProfile; 2283 for (int operandIdx = startOperand; operandIdx > startOperand - numOperands; --operandIdx) 2284 addVarArgChild(get(VirtualRegister(operandIdx))); 2285 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(Node::VarArg, NewArray, OpInfo(profile->selectIndexingType()), OpInfo(0))); 2286 NEXT_OPCODE(op_new_array); 2287 } 2288 2289 case op_new_array_with_size: { 2290 int lengthOperand = currentInstruction[2].u.operand; 2291 ArrayAllocationProfile* profile = currentInstruction[3].u.arrayAllocationProfile; 2292 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewArrayWithSize, OpInfo(profile->selectIndexingType()), get(VirtualRegister(lengthOperand)))); 2293 NEXT_OPCODE(op_new_array_with_size); 2294 } 2295 2296 case op_new_array_buffer: { 2297 int startConstant = currentInstruction[2].u.operand; 2298 int numConstants = currentInstruction[3].u.operand; 2299 ArrayAllocationProfile* profile = currentInstruction[4].u.arrayAllocationProfile; 2300 NewArrayBufferData data; 2301 data.startConstant = m_inlineStackTop->m_constantBufferRemap[startConstant]; 2302 data.numConstants = numConstants; 2303 data.indexingType = profile->selectIndexingType(); 2304 2305 // If this statement has never executed, we'll have the wrong indexing type in the profile. 2306 for (int i = 0; i < numConstants; ++i) { 2307 data.indexingType = 2308 leastUpperBoundOfIndexingTypeAndValue( 2309 data.indexingType, 2310 m_codeBlock->constantBuffer(data.startConstant)[i]); 2311 } 2312 2313 m_graph.m_newArrayBufferData.append(data); 2314 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewArrayBuffer, OpInfo(&m_graph.m_newArrayBufferData.last()))); 2315 NEXT_OPCODE(op_new_array_buffer); 2316 } 2317 2318 case op_new_regexp: { 2319 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(NewRegexp, OpInfo(currentInstruction[2].u.operand))); 2320 NEXT_OPCODE(op_new_regexp); 2321 } 2322 2323 case op_get_callee: { 2324 JSCell* cachedFunction = currentInstruction[2].u.jsCell.get(); 2325 if (!cachedFunction 2326 || m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) 2327 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadFunction)) { 2328 set(VirtualRegister(currentInstruction[1].u.operand), get(VirtualRegister(JSStack::Callee))); 2329 } else { 2330 ASSERT(cachedFunction->inherits(JSFunction::info())); 2331 Node* actualCallee = get(VirtualRegister(JSStack::Callee)); 2332 addToGraph(CheckFunction, OpInfo(cachedFunction), actualCallee); 2333 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(WeakJSConstant, OpInfo(cachedFunction))); 2334 } 2335 NEXT_OPCODE(op_get_callee); 2336 } 2337 2338 // === Bitwise operations === 2339 2340 case op_bitand: { 2341 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2342 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2343 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitAnd, op1, op2)); 2344 NEXT_OPCODE(op_bitand); 2345 } 2346 2347 case op_bitor: { 2348 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2349 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2350 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitOr, op1, op2)); 2351 NEXT_OPCODE(op_bitor); 2352 } 2353 2354 case op_bitxor: { 2355 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2356 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2357 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(BitXor, op1, op2)); 2358 NEXT_OPCODE(op_bitxor); 2359 } 2360 2361 case op_rshift: { 2362 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2363 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2364 set(VirtualRegister(currentInstruction[1].u.operand), 2365 addToGraph(BitRShift, op1, op2)); 2366 NEXT_OPCODE(op_rshift); 2367 } 2368 2369 case op_lshift: { 2370 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2371 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2372 set(VirtualRegister(currentInstruction[1].u.operand), 2373 addToGraph(BitLShift, op1, op2)); 2374 NEXT_OPCODE(op_lshift); 2375 } 2376 2377 case op_urshift: { 2378 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2379 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2380 set(VirtualRegister(currentInstruction[1].u.operand), 2381 addToGraph(BitURShift, op1, op2)); 2382 NEXT_OPCODE(op_urshift); 2383 } 2384 2385 case op_unsigned: { 2386 set(VirtualRegister(currentInstruction[1].u.operand), 2387 makeSafe(addToGraph(UInt32ToNumber, get(VirtualRegister(currentInstruction[2].u.operand))))); 2388 NEXT_OPCODE(op_unsigned); 2389 } 2390 2391 // === Increment/Decrement opcodes === 2392 2393 case op_inc: { 2394 int srcDst = currentInstruction[1].u.operand; 2395 VirtualRegister srcDstVirtualRegister = VirtualRegister(srcDst); 2396 Node* op = get(srcDstVirtualRegister); 2397 set(srcDstVirtualRegister, makeSafe(addToGraph(ArithAdd, op, one()))); 2398 NEXT_OPCODE(op_inc); 2399 } 2400 2401 case op_dec: { 2402 int srcDst = currentInstruction[1].u.operand; 2403 VirtualRegister srcDstVirtualRegister = VirtualRegister(srcDst); 2404 Node* op = get(srcDstVirtualRegister); 2405 set(srcDstVirtualRegister, makeSafe(addToGraph(ArithSub, op, one()))); 2406 NEXT_OPCODE(op_dec); 2407 } 2408 2409 // === Arithmetic operations === 2410 2411 case op_add: { 2412 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2413 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2414 if (op1->hasNumberResult() && op2->hasNumberResult()) 2415 set(VirtualRegister(currentInstruction[1].u.operand), makeSafe(addToGraph(ArithAdd, op1, op2))); 2416 else 2417 set(VirtualRegister(currentInstruction[1].u.operand), makeSafe(addToGraph(ValueAdd, op1, op2))); 2418 NEXT_OPCODE(op_add); 2419 } 2420 2421 case op_sub: { 2422 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2423 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2424 set(VirtualRegister(currentInstruction[1].u.operand), makeSafe(addToGraph(ArithSub, op1, op2))); 2425 NEXT_OPCODE(op_sub); 2426 } 2427 2428 case op_negate: { 2429 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2430 set(VirtualRegister(currentInstruction[1].u.operand), makeSafe(addToGraph(ArithNegate, op1))); 2431 NEXT_OPCODE(op_negate); 2432 } 2433 2434 case op_mul: { 2435 // Multiply requires that the inputs are not truncated, unfortunately. 2436 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2437 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2438 set(VirtualRegister(currentInstruction[1].u.operand), makeSafe(addToGraph(ArithMul, op1, op2))); 2439 NEXT_OPCODE(op_mul); 2440 } 2441 2442 case op_mod: { 2443 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2444 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2445 set(VirtualRegister(currentInstruction[1].u.operand), makeSafe(addToGraph(ArithMod, op1, op2))); 2446 NEXT_OPCODE(op_mod); 2447 } 2448 2449 case op_div: { 2450 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2451 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2452 set(VirtualRegister(currentInstruction[1].u.operand), makeDivSafe(addToGraph(ArithDiv, op1, op2))); 2453 NEXT_OPCODE(op_div); 2454 } 2455 2456 // === Misc operations === 2457 2458 case op_debug: 2459 addToGraph(Breakpoint); 2460 NEXT_OPCODE(op_debug); 2461 2462 case op_profile_will_call: { 2463 addToGraph(ProfileWillCall); 2464 NEXT_OPCODE(op_profile_will_call); 2465 } 2466 2467 case op_profile_did_call: { 2468 addToGraph(ProfileDidCall); 2469 NEXT_OPCODE(op_profile_did_call); 2470 } 2471 2472 case op_mov: { 2473 Node* op = get(VirtualRegister(currentInstruction[2].u.operand)); 2474 set(VirtualRegister(currentInstruction[1].u.operand), op); 2475 NEXT_OPCODE(op_mov); 2476 } 2477 2478 case op_captured_mov: { 2479 Node* op = get(VirtualRegister(currentInstruction[2].u.operand)); 2480 if (VariableWatchpointSet* set = currentInstruction[3].u.watchpointSet) { 2481 if (set->state() != IsInvalidated) 2482 addToGraph(NotifyWrite, OpInfo(set), op); 2483 } 2484 set(VirtualRegister(currentInstruction[1].u.operand), op); 2485 NEXT_OPCODE(op_captured_mov); 2486 } 2487 2488 case op_check_has_instance: 2489 addToGraph(CheckHasInstance, get(VirtualRegister(currentInstruction[3].u.operand))); 2490 NEXT_OPCODE(op_check_has_instance); 2491 2492 case op_instanceof: { 2493 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2494 Node* prototype = get(VirtualRegister(currentInstruction[3].u.operand)); 2495 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(InstanceOf, value, prototype)); 2496 NEXT_OPCODE(op_instanceof); 2497 } 2498 2499 case op_is_undefined: { 2500 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2501 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsUndefined, value)); 2502 NEXT_OPCODE(op_is_undefined); 2503 } 2504 2505 case op_is_boolean: { 2506 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2507 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsBoolean, value)); 2508 NEXT_OPCODE(op_is_boolean); 2509 } 2510 2511 case op_is_number: { 2512 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2513 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsNumber, value)); 2514 NEXT_OPCODE(op_is_number); 2515 } 2516 2517 case op_is_string: { 2518 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2519 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsString, value)); 2520 NEXT_OPCODE(op_is_string); 2521 } 2522 2523 case op_is_object: { 2524 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2525 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsObject, value)); 2526 NEXT_OPCODE(op_is_object); 2527 } 2528 2529 case op_is_function: { 2530 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2531 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(IsFunction, value)); 2532 NEXT_OPCODE(op_is_function); 2533 } 2534 2535 case op_not: { 2536 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2537 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(LogicalNot, value)); 2538 NEXT_OPCODE(op_not); 2539 } 2540 2541 case op_to_primitive: { 2542 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2543 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(ToPrimitive, value)); 2544 NEXT_OPCODE(op_to_primitive); 2545 } 2546 2547 case op_strcat: { 2548 int startOperand = currentInstruction[2].u.operand; 2549 int numOperands = currentInstruction[3].u.operand; 2550#if CPU(X86) 2551 // X86 doesn't have enough registers to compile MakeRope with three arguments. 2552 // Rather than try to be clever, we just make MakeRope dumber on this processor. 2553 const unsigned maxRopeArguments = 2; 2554#else 2555 const unsigned maxRopeArguments = 3; 2556#endif 2557 auto toStringNodes = std::make_unique<Node*[]>(numOperands); 2558 for (int i = 0; i < numOperands; i++) 2559 toStringNodes[i] = addToGraph(ToString, get(VirtualRegister(startOperand - i))); 2560 2561 for (int i = 0; i < numOperands; i++) 2562 addToGraph(Phantom, toStringNodes[i]); 2563 2564 Node* operands[AdjacencyList::Size]; 2565 unsigned indexInOperands = 0; 2566 for (unsigned i = 0; i < AdjacencyList::Size; ++i) 2567 operands[i] = 0; 2568 for (int operandIdx = 0; operandIdx < numOperands; ++operandIdx) { 2569 if (indexInOperands == maxRopeArguments) { 2570 operands[0] = addToGraph(MakeRope, operands[0], operands[1], operands[2]); 2571 for (unsigned i = 1; i < AdjacencyList::Size; ++i) 2572 operands[i] = 0; 2573 indexInOperands = 1; 2574 } 2575 2576 ASSERT(indexInOperands < AdjacencyList::Size); 2577 ASSERT(indexInOperands < maxRopeArguments); 2578 operands[indexInOperands++] = toStringNodes[operandIdx]; 2579 } 2580 set(VirtualRegister(currentInstruction[1].u.operand), 2581 addToGraph(MakeRope, operands[0], operands[1], operands[2])); 2582 NEXT_OPCODE(op_strcat); 2583 } 2584 2585 case op_less: { 2586 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2587 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2588 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareLess, op1, op2)); 2589 NEXT_OPCODE(op_less); 2590 } 2591 2592 case op_lesseq: { 2593 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2594 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2595 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareLessEq, op1, op2)); 2596 NEXT_OPCODE(op_lesseq); 2597 } 2598 2599 case op_greater: { 2600 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2601 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2602 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareGreater, op1, op2)); 2603 NEXT_OPCODE(op_greater); 2604 } 2605 2606 case op_greatereq: { 2607 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2608 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2609 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareGreaterEq, op1, op2)); 2610 NEXT_OPCODE(op_greatereq); 2611 } 2612 2613 case op_eq: { 2614 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2615 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2616 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareEq, op1, op2)); 2617 NEXT_OPCODE(op_eq); 2618 } 2619 2620 case op_eq_null: { 2621 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2622 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareEqConstant, value, constantNull())); 2623 NEXT_OPCODE(op_eq_null); 2624 } 2625 2626 case op_stricteq: { 2627 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2628 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2629 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CompareStrictEq, op1, op2)); 2630 NEXT_OPCODE(op_stricteq); 2631 } 2632 2633 case op_neq: { 2634 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2635 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2636 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(LogicalNot, addToGraph(CompareEq, op1, op2))); 2637 NEXT_OPCODE(op_neq); 2638 } 2639 2640 case op_neq_null: { 2641 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2642 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(LogicalNot, addToGraph(CompareEqConstant, value, constantNull()))); 2643 NEXT_OPCODE(op_neq_null); 2644 } 2645 2646 case op_nstricteq: { 2647 Node* op1 = get(VirtualRegister(currentInstruction[2].u.operand)); 2648 Node* op2 = get(VirtualRegister(currentInstruction[3].u.operand)); 2649 Node* invertedResult; 2650 invertedResult = addToGraph(CompareStrictEq, op1, op2); 2651 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(LogicalNot, invertedResult)); 2652 NEXT_OPCODE(op_nstricteq); 2653 } 2654 2655 // === Property access operations === 2656 2657 case op_get_by_val: { 2658 SpeculatedType prediction = getPrediction(); 2659 2660 Node* base = get(VirtualRegister(currentInstruction[2].u.operand)); 2661 ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Read); 2662 Node* property = get(VirtualRegister(currentInstruction[3].u.operand)); 2663 Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property); 2664 set(VirtualRegister(currentInstruction[1].u.operand), getByVal); 2665 2666 NEXT_OPCODE(op_get_by_val); 2667 } 2668 2669 case op_put_by_val_direct: 2670 case op_put_by_val: { 2671 Node* base = get(VirtualRegister(currentInstruction[1].u.operand)); 2672 2673 ArrayMode arrayMode = getArrayModeConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Write); 2674 2675 Node* property = get(VirtualRegister(currentInstruction[2].u.operand)); 2676 Node* value = get(VirtualRegister(currentInstruction[3].u.operand)); 2677 2678 addVarArgChild(base); 2679 addVarArgChild(property); 2680 addVarArgChild(value); 2681 addVarArgChild(0); // Leave room for property storage. 2682 addVarArgChild(0); // Leave room for length. 2683 addToGraph(Node::VarArg, opcodeID == op_put_by_val_direct ? PutByValDirect : PutByVal, OpInfo(arrayMode.asWord()), OpInfo(0)); 2684 2685 NEXT_OPCODE(op_put_by_val); 2686 } 2687 2688 case op_get_by_id: 2689 case op_get_by_id_out_of_line: 2690 case op_get_array_length: { 2691 SpeculatedType prediction = getPrediction(); 2692 2693 Node* base = get(VirtualRegister(currentInstruction[2].u.operand)); 2694 unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; 2695 2696 StringImpl* uid = m_graph.identifiers()[identifierNumber]; 2697 GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( 2698 m_inlineStackTop->m_profiledBlock, m_dfgCodeBlock, 2699 m_inlineStackTop->m_stubInfos, m_dfgStubInfos, 2700 currentCodeOrigin(), uid); 2701 2702 handleGetById( 2703 currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus); 2704 2705 NEXT_OPCODE(op_get_by_id); 2706 } 2707 case op_put_by_id: 2708 case op_put_by_id_out_of_line: 2709 case op_put_by_id_transition_direct: 2710 case op_put_by_id_transition_normal: 2711 case op_put_by_id_transition_direct_out_of_line: 2712 case op_put_by_id_transition_normal_out_of_line: { 2713 Node* value = get(VirtualRegister(currentInstruction[3].u.operand)); 2714 Node* base = get(VirtualRegister(currentInstruction[1].u.operand)); 2715 unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; 2716 bool direct = currentInstruction[8].u.operand; 2717 2718 PutByIdStatus putByIdStatus = PutByIdStatus::computeFor( 2719 m_inlineStackTop->m_profiledBlock, m_dfgCodeBlock, 2720 m_inlineStackTop->m_stubInfos, m_dfgStubInfos, 2721 currentCodeOrigin(), m_graph.identifiers()[identifierNumber]); 2722 2723 handlePutById(base, identifierNumber, value, putByIdStatus, direct); 2724 NEXT_OPCODE(op_put_by_id); 2725 } 2726 2727 case op_init_global_const_nop: { 2728 NEXT_OPCODE(op_init_global_const_nop); 2729 } 2730 2731 case op_init_global_const: { 2732 Node* value = get(VirtualRegister(currentInstruction[2].u.operand)); 2733 addToGraph( 2734 PutGlobalVar, 2735 OpInfo(m_inlineStackTop->m_codeBlock->globalObject()->assertRegisterIsInThisObject(currentInstruction[1].u.registerPointer)), 2736 value); 2737 NEXT_OPCODE(op_init_global_const); 2738 } 2739 2740 // === Block terminators. === 2741 2742 case op_jmp: { 2743 int relativeOffset = currentInstruction[1].u.operand; 2744 if (relativeOffset <= 0) 2745 flushForTerminal(); 2746 addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset)); 2747 LAST_OPCODE(op_jmp); 2748 } 2749 2750 case op_jtrue: { 2751 unsigned relativeOffset = currentInstruction[2].u.operand; 2752 Node* condition = get(VirtualRegister(currentInstruction[1].u.operand)); 2753 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jtrue))), condition); 2754 LAST_OPCODE(op_jtrue); 2755 } 2756 2757 case op_jfalse: { 2758 unsigned relativeOffset = currentInstruction[2].u.operand; 2759 Node* condition = get(VirtualRegister(currentInstruction[1].u.operand)); 2760 addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jfalse), m_currentIndex + relativeOffset)), condition); 2761 LAST_OPCODE(op_jfalse); 2762 } 2763 2764 case op_jeq_null: { 2765 unsigned relativeOffset = currentInstruction[2].u.operand; 2766 Node* value = get(VirtualRegister(currentInstruction[1].u.operand)); 2767 Node* condition = addToGraph(CompareEqConstant, value, constantNull()); 2768 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jeq_null))), condition); 2769 LAST_OPCODE(op_jeq_null); 2770 } 2771 2772 case op_jneq_null: { 2773 unsigned relativeOffset = currentInstruction[2].u.operand; 2774 Node* value = get(VirtualRegister(currentInstruction[1].u.operand)); 2775 Node* condition = addToGraph(CompareEqConstant, value, constantNull()); 2776 addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jneq_null), m_currentIndex + relativeOffset)), condition); 2777 LAST_OPCODE(op_jneq_null); 2778 } 2779 2780 case op_jless: { 2781 unsigned relativeOffset = currentInstruction[3].u.operand; 2782 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 2783 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 2784 Node* condition = addToGraph(CompareLess, op1, op2); 2785 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jless))), condition); 2786 LAST_OPCODE(op_jless); 2787 } 2788 2789 case op_jlesseq: { 2790 unsigned relativeOffset = currentInstruction[3].u.operand; 2791 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 2792 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 2793 Node* condition = addToGraph(CompareLessEq, op1, op2); 2794 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jlesseq))), condition); 2795 LAST_OPCODE(op_jlesseq); 2796 } 2797 2798 case op_jgreater: { 2799 unsigned relativeOffset = currentInstruction[3].u.operand; 2800 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 2801 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 2802 Node* condition = addToGraph(CompareGreater, op1, op2); 2803 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jgreater))), condition); 2804 LAST_OPCODE(op_jgreater); 2805 } 2806 2807 case op_jgreatereq: { 2808 unsigned relativeOffset = currentInstruction[3].u.operand; 2809 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 2810 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 2811 Node* condition = addToGraph(CompareGreaterEq, op1, op2); 2812 addToGraph(Branch, OpInfo(branchData(m_currentIndex + relativeOffset, m_currentIndex + OPCODE_LENGTH(op_jgreatereq))), condition); 2813 LAST_OPCODE(op_jgreatereq); 2814 } 2815 2816 case op_jnless: { 2817 unsigned relativeOffset = currentInstruction[3].u.operand; 2818 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 2819 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 2820 Node* condition = addToGraph(CompareLess, op1, op2); 2821 addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jnless), m_currentIndex + relativeOffset)), condition); 2822 LAST_OPCODE(op_jnless); 2823 } 2824 2825 case op_jnlesseq: { 2826 unsigned relativeOffset = currentInstruction[3].u.operand; 2827 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 2828 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 2829 Node* condition = addToGraph(CompareLessEq, op1, op2); 2830 addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jnlesseq), m_currentIndex + relativeOffset)), condition); 2831 LAST_OPCODE(op_jnlesseq); 2832 } 2833 2834 case op_jngreater: { 2835 unsigned relativeOffset = currentInstruction[3].u.operand; 2836 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 2837 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 2838 Node* condition = addToGraph(CompareGreater, op1, op2); 2839 addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jngreater), m_currentIndex + relativeOffset)), condition); 2840 LAST_OPCODE(op_jngreater); 2841 } 2842 2843 case op_jngreatereq: { 2844 unsigned relativeOffset = currentInstruction[3].u.operand; 2845 Node* op1 = get(VirtualRegister(currentInstruction[1].u.operand)); 2846 Node* op2 = get(VirtualRegister(currentInstruction[2].u.operand)); 2847 Node* condition = addToGraph(CompareGreaterEq, op1, op2); 2848 addToGraph(Branch, OpInfo(branchData(m_currentIndex + OPCODE_LENGTH(op_jngreatereq), m_currentIndex + relativeOffset)), condition); 2849 LAST_OPCODE(op_jngreatereq); 2850 } 2851 2852 case op_switch_imm: { 2853 SwitchData& data = *m_graph.m_switchData.add(); 2854 data.kind = SwitchImm; 2855 data.switchTableIndex = m_inlineStackTop->m_switchRemap[currentInstruction[1].u.operand]; 2856 data.fallThrough.setBytecodeIndex(m_currentIndex + currentInstruction[2].u.operand); 2857 SimpleJumpTable& table = m_codeBlock->switchJumpTable(data.switchTableIndex); 2858 for (unsigned i = 0; i < table.branchOffsets.size(); ++i) { 2859 if (!table.branchOffsets[i]) 2860 continue; 2861 unsigned target = m_currentIndex + table.branchOffsets[i]; 2862 if (target == data.fallThrough.bytecodeIndex()) 2863 continue; 2864 data.cases.append(SwitchCase::withBytecodeIndex(jsNumber(static_cast<int32_t>(table.min + i)), target)); 2865 } 2866 flushIfTerminal(data); 2867 addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand))); 2868 LAST_OPCODE(op_switch_imm); 2869 } 2870 2871 case op_switch_char: { 2872 SwitchData& data = *m_graph.m_switchData.add(); 2873 data.kind = SwitchChar; 2874 data.switchTableIndex = m_inlineStackTop->m_switchRemap[currentInstruction[1].u.operand]; 2875 data.fallThrough.setBytecodeIndex(m_currentIndex + currentInstruction[2].u.operand); 2876 SimpleJumpTable& table = m_codeBlock->switchJumpTable(data.switchTableIndex); 2877 for (unsigned i = 0; i < table.branchOffsets.size(); ++i) { 2878 if (!table.branchOffsets[i]) 2879 continue; 2880 unsigned target = m_currentIndex + table.branchOffsets[i]; 2881 if (target == data.fallThrough.bytecodeIndex()) 2882 continue; 2883 data.cases.append( 2884 SwitchCase::withBytecodeIndex(LazyJSValue::singleCharacterString(table.min + i), target)); 2885 } 2886 flushIfTerminal(data); 2887 addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand))); 2888 LAST_OPCODE(op_switch_char); 2889 } 2890 2891 case op_switch_string: { 2892 SwitchData& data = *m_graph.m_switchData.add(); 2893 data.kind = SwitchString; 2894 data.switchTableIndex = currentInstruction[1].u.operand; 2895 data.fallThrough.setBytecodeIndex(m_currentIndex + currentInstruction[2].u.operand); 2896 StringJumpTable& table = m_codeBlock->stringSwitchJumpTable(data.switchTableIndex); 2897 StringJumpTable::StringOffsetTable::iterator iter; 2898 StringJumpTable::StringOffsetTable::iterator end = table.offsetTable.end(); 2899 for (iter = table.offsetTable.begin(); iter != end; ++iter) { 2900 unsigned target = m_currentIndex + iter->value.branchOffset; 2901 if (target == data.fallThrough.bytecodeIndex()) 2902 continue; 2903 data.cases.append( 2904 SwitchCase::withBytecodeIndex(LazyJSValue::knownStringImpl(iter->key.get()), target)); 2905 } 2906 flushIfTerminal(data); 2907 addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand))); 2908 LAST_OPCODE(op_switch_string); 2909 } 2910 2911 case op_ret: 2912 flushForReturn(); 2913 if (inlineCallFrame()) { 2914 ASSERT(m_inlineStackTop->m_returnValue.isValid()); 2915 setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush); 2916 m_inlineStackTop->m_didReturn = true; 2917 if (m_inlineStackTop->m_unlinkedBlocks.isEmpty()) { 2918 // If we're returning from the first block, then we're done parsing. 2919 ASSERT(m_inlineStackTop->m_callsiteBlockHead == m_graph.lastBlock()); 2920 shouldContinueParsing = false; 2921 LAST_OPCODE(op_ret); 2922 } else { 2923 // If inlining created blocks, and we're doing a return, then we need some 2924 // special linking. 2925 ASSERT(m_inlineStackTop->m_unlinkedBlocks.last().m_block == m_graph.lastBlock()); 2926 m_inlineStackTop->m_unlinkedBlocks.last().m_needsNormalLinking = false; 2927 } 2928 if (m_currentIndex + OPCODE_LENGTH(op_ret) != m_inlineStackTop->m_codeBlock->instructions().size() || m_inlineStackTop->m_didEarlyReturn) { 2929 ASSERT(m_currentIndex + OPCODE_LENGTH(op_ret) <= m_inlineStackTop->m_codeBlock->instructions().size()); 2930 addToGraph(Jump, OpInfo(0)); 2931 m_inlineStackTop->m_unlinkedBlocks.last().m_needsEarlyReturnLinking = true; 2932 m_inlineStackTop->m_didEarlyReturn = true; 2933 } 2934 LAST_OPCODE(op_ret); 2935 } 2936 addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand))); 2937 LAST_OPCODE(op_ret); 2938 2939 case op_end: 2940 flushForReturn(); 2941 ASSERT(!inlineCallFrame()); 2942 addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand))); 2943 LAST_OPCODE(op_end); 2944 2945 case op_throw: 2946 addToGraph(Throw, get(VirtualRegister(currentInstruction[1].u.operand))); 2947 flushForTerminal(); 2948 addToGraph(Unreachable); 2949 LAST_OPCODE(op_throw); 2950 2951 case op_throw_static_error: 2952 addToGraph(ThrowReferenceError); 2953 flushForTerminal(); 2954 addToGraph(Unreachable); 2955 LAST_OPCODE(op_throw_static_error); 2956 2957 case op_call: 2958 handleCall(currentInstruction, Call, CodeForCall); 2959 NEXT_OPCODE(op_call); 2960 2961 case op_construct: 2962 handleCall(currentInstruction, Construct, CodeForConstruct); 2963 NEXT_OPCODE(op_construct); 2964 2965 case op_call_varargs: { 2966 int result = currentInstruction[1].u.operand; 2967 int callee = currentInstruction[2].u.operand; 2968 int thisReg = currentInstruction[3].u.operand; 2969 int arguments = currentInstruction[4].u.operand; 2970 int firstFreeReg = currentInstruction[5].u.operand; 2971 2972 ASSERT(inlineCallFrame()); 2973 ASSERT_UNUSED(arguments, arguments == m_inlineStackTop->m_codeBlock->argumentsRegister().offset()); 2974 ASSERT(!m_inlineStackTop->m_codeBlock->symbolTable()->slowArguments()); 2975 2976 addToGraph(CheckArgumentsNotCreated); 2977 2978 unsigned argCount = inlineCallFrame()->arguments.size(); 2979 2980 // Let's compute the register offset. We start with the last used register, and 2981 // then adjust for the things we want in the call frame. 2982 int registerOffset = firstFreeReg + 1; 2983 registerOffset -= argCount; // We will be passing some arguments. 2984 registerOffset -= JSStack::CallFrameHeaderSize; // We will pretend to have a call frame header. 2985 2986 // Get the alignment right. 2987 registerOffset = -WTF::roundUpToMultipleOf( 2988 stackAlignmentRegisters(), 2989 -registerOffset); 2990 2991 ensureLocals( 2992 m_inlineStackTop->remapOperand( 2993 VirtualRegister(registerOffset)).toLocal()); 2994 2995 // The bytecode wouldn't have set up the arguments. But we'll do it and make it 2996 // look like the bytecode had done it. 2997 int nextRegister = registerOffset + JSStack::CallFrameHeaderSize; 2998 set(VirtualRegister(nextRegister++), get(VirtualRegister(thisReg)), ImmediateNakedSet); 2999 for (unsigned argument = 1; argument < argCount; ++argument) 3000 set(VirtualRegister(nextRegister++), get(virtualRegisterForArgument(argument)), ImmediateNakedSet); 3001 3002 handleCall( 3003 result, Call, CodeForCall, OPCODE_LENGTH(op_call_varargs), 3004 callee, argCount, registerOffset); 3005 NEXT_OPCODE(op_call_varargs); 3006 } 3007 3008 case op_jneq_ptr: 3009 // Statically speculate for now. It makes sense to let speculate-only jneq_ptr 3010 // support simmer for a while before making it more general, since it's 3011 // already gnarly enough as it is. 3012 ASSERT(pointerIsFunction(currentInstruction[2].u.specialPointer)); 3013 addToGraph( 3014 CheckFunction, 3015 OpInfo(actualPointerFor(m_inlineStackTop->m_codeBlock, currentInstruction[2].u.specialPointer)), 3016 get(VirtualRegister(currentInstruction[1].u.operand))); 3017 addToGraph(Jump, OpInfo(m_currentIndex + OPCODE_LENGTH(op_jneq_ptr))); 3018 LAST_OPCODE(op_jneq_ptr); 3019 3020 case op_resolve_scope: { 3021 int dst = currentInstruction[1].u.operand; 3022 ResolveType resolveType = static_cast<ResolveType>(currentInstruction[3].u.operand); 3023 unsigned depth = currentInstruction[4].u.operand; 3024 3025 // get_from_scope and put_to_scope depend on this watchpoint forcing OSR exit, so they don't add their own watchpoints. 3026 if (needsVarInjectionChecks(resolveType)) 3027 addToGraph(VarInjectionWatchpoint); 3028 3029 switch (resolveType) { 3030 case GlobalProperty: 3031 case GlobalVar: 3032 case GlobalPropertyWithVarInjectionChecks: 3033 case GlobalVarWithVarInjectionChecks: 3034 set(VirtualRegister(dst), cellConstant(m_inlineStackTop->m_codeBlock->globalObject())); 3035 break; 3036 case ClosureVar: 3037 case ClosureVarWithVarInjectionChecks: { 3038 JSActivation* activation = currentInstruction[5].u.activation.get(); 3039 if (activation 3040 && activation->symbolTable()->m_functionEnteredOnce.isStillValid()) { 3041 addToGraph(FunctionReentryWatchpoint, OpInfo(activation->symbolTable())); 3042 set(VirtualRegister(dst), cellConstant(activation)); 3043 break; 3044 } 3045 set(VirtualRegister(dst), 3046 getScope(m_inlineStackTop->m_codeBlock->needsActivation(), depth)); 3047 break; 3048 } 3049 case Dynamic: 3050 RELEASE_ASSERT_NOT_REACHED(); 3051 break; 3052 } 3053 NEXT_OPCODE(op_resolve_scope); 3054 } 3055 3056 case op_get_from_scope: { 3057 int dst = currentInstruction[1].u.operand; 3058 int scope = currentInstruction[2].u.operand; 3059 unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[3].u.operand]; 3060 StringImpl* uid = m_graph.identifiers()[identifierNumber]; 3061 ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type(); 3062 3063 Structure* structure = 0; 3064 WatchpointSet* watchpoints = 0; 3065 uintptr_t operand; 3066 { 3067 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 3068 if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks) 3069 watchpoints = currentInstruction[5].u.watchpointSet; 3070 else 3071 structure = currentInstruction[5].u.structure.get(); 3072 operand = reinterpret_cast<uintptr_t>(currentInstruction[6].u.pointer); 3073 } 3074 3075 UNUSED_PARAM(watchpoints); // We will use this in the future. For now we set it as a way of documenting the fact that that's what index 5 is in GlobalVar mode. 3076 3077 SpeculatedType prediction = getPrediction(); 3078 JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); 3079 3080 switch (resolveType) { 3081 case GlobalProperty: 3082 case GlobalPropertyWithVarInjectionChecks: { 3083 GetByIdStatus status = GetByIdStatus::computeFor(*m_vm, structure, uid); 3084 if (status.state() != GetByIdStatus::Simple || status.numVariants() != 1) { 3085 set(VirtualRegister(dst), addToGraph(GetByIdFlush, OpInfo(identifierNumber), OpInfo(prediction), get(VirtualRegister(scope)))); 3086 break; 3087 } 3088 Node* base = cellConstantWithStructureCheck(globalObject, status[0].structureSet().singletonStructure()); 3089 addToGraph(Phantom, get(VirtualRegister(scope))); 3090 if (JSValue specificValue = status[0].specificValue()) 3091 set(VirtualRegister(dst), cellConstant(specificValue.asCell())); 3092 else 3093 set(VirtualRegister(dst), handleGetByOffset(prediction, base, identifierNumber, operand)); 3094 break; 3095 } 3096 case GlobalVar: 3097 case GlobalVarWithVarInjectionChecks: { 3098 addToGraph(Phantom, get(VirtualRegister(scope))); 3099 SymbolTableEntry entry = globalObject->symbolTable()->get(uid); 3100 VariableWatchpointSet* watchpointSet = entry.watchpointSet(); 3101 JSValue specificValue = 3102 watchpointSet ? watchpointSet->inferredValue() : JSValue(); 3103 if (!specificValue) { 3104 set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction))); 3105 break; 3106 } 3107 3108 addToGraph(VariableWatchpoint, OpInfo(watchpointSet)); 3109 set(VirtualRegister(dst), inferredConstant(specificValue)); 3110 break; 3111 } 3112 case ClosureVar: 3113 case ClosureVarWithVarInjectionChecks: { 3114 Node* scopeNode = get(VirtualRegister(scope)); 3115 if (JSActivation* activation = m_graph.tryGetActivation(scopeNode)) { 3116 SymbolTable* symbolTable = activation->symbolTable(); 3117 ConcurrentJITLocker locker(symbolTable->m_lock); 3118 SymbolTable::Map::iterator iter = symbolTable->find(locker, uid); 3119 ASSERT(iter != symbolTable->end(locker)); 3120 VariableWatchpointSet* watchpointSet = iter->value.watchpointSet(); 3121 if (watchpointSet) { 3122 if (JSValue value = watchpointSet->inferredValue()) { 3123 addToGraph(Phantom, scopeNode); 3124 addToGraph(VariableWatchpoint, OpInfo(watchpointSet)); 3125 set(VirtualRegister(dst), inferredConstant(value)); 3126 break; 3127 } 3128 } 3129 } 3130 set(VirtualRegister(dst), 3131 addToGraph(GetClosureVar, OpInfo(operand), OpInfo(prediction), 3132 addToGraph(GetClosureRegisters, scopeNode))); 3133 break; 3134 } 3135 case Dynamic: 3136 RELEASE_ASSERT_NOT_REACHED(); 3137 break; 3138 } 3139 NEXT_OPCODE(op_get_from_scope); 3140 } 3141 3142 case op_put_to_scope: { 3143 unsigned scope = currentInstruction[1].u.operand; 3144 unsigned identifierNumber = m_inlineStackTop->m_identifierRemap[currentInstruction[2].u.operand]; 3145 unsigned value = currentInstruction[3].u.operand; 3146 ResolveType resolveType = ResolveModeAndType(currentInstruction[4].u.operand).type(); 3147 StringImpl* uid = m_graph.identifiers()[identifierNumber]; 3148 3149 Structure* structure = 0; 3150 VariableWatchpointSet* watchpoints = 0; 3151 uintptr_t operand; 3152 { 3153 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 3154 if (resolveType == GlobalVar || resolveType == GlobalVarWithVarInjectionChecks) 3155 watchpoints = currentInstruction[5].u.watchpointSet; 3156 else 3157 structure = currentInstruction[5].u.structure.get(); 3158 operand = reinterpret_cast<uintptr_t>(currentInstruction[6].u.pointer); 3159 } 3160 3161 JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); 3162 3163 switch (resolveType) { 3164 case GlobalProperty: 3165 case GlobalPropertyWithVarInjectionChecks: { 3166 PutByIdStatus status = PutByIdStatus::computeFor(*m_vm, globalObject, structure, uid, false); 3167 if (status.numVariants() != 1 || status[0].kind() != PutByIdVariant::Replace) { 3168 addToGraph(PutById, OpInfo(identifierNumber), get(VirtualRegister(scope)), get(VirtualRegister(value))); 3169 break; 3170 } 3171 Node* base = cellConstantWithStructureCheck(globalObject, status[0].structure()); 3172 addToGraph(Phantom, get(VirtualRegister(scope))); 3173 handlePutByOffset(base, identifierNumber, static_cast<PropertyOffset>(operand), get(VirtualRegister(value))); 3174 // Keep scope alive until after put. 3175 addToGraph(Phantom, get(VirtualRegister(scope))); 3176 break; 3177 } 3178 case GlobalVar: 3179 case GlobalVarWithVarInjectionChecks: { 3180 SymbolTableEntry entry = globalObject->symbolTable()->get(uid); 3181 ASSERT(watchpoints == entry.watchpointSet()); 3182 Node* valueNode = get(VirtualRegister(value)); 3183 addToGraph(PutGlobalVar, OpInfo(operand), valueNode); 3184 if (watchpoints->state() != IsInvalidated) 3185 addToGraph(NotifyWrite, OpInfo(watchpoints), valueNode); 3186 // Keep scope alive until after put. 3187 addToGraph(Phantom, get(VirtualRegister(scope))); 3188 break; 3189 } 3190 case ClosureVar: 3191 case ClosureVarWithVarInjectionChecks: { 3192 Node* scopeNode = get(VirtualRegister(scope)); 3193 Node* scopeRegisters = addToGraph(GetClosureRegisters, scopeNode); 3194 addToGraph(PutClosureVar, OpInfo(operand), scopeNode, scopeRegisters, get(VirtualRegister(value))); 3195 break; 3196 } 3197 case Dynamic: 3198 RELEASE_ASSERT_NOT_REACHED(); 3199 break; 3200 } 3201 NEXT_OPCODE(op_put_to_scope); 3202 } 3203 3204 case op_loop_hint: { 3205 // Baseline->DFG OSR jumps between loop hints. The DFG assumes that Baseline->DFG 3206 // OSR can only happen at basic block boundaries. Assert that these two statements 3207 // are compatible. 3208 RELEASE_ASSERT(m_currentIndex == blockBegin); 3209 3210 // We never do OSR into an inlined code block. That could not happen, since OSR 3211 // looks up the code block that is the replacement for the baseline JIT code 3212 // block. Hence, machine code block = true code block = not inline code block. 3213 if (!m_inlineStackTop->m_caller) 3214 m_currentBlock->isOSRTarget = true; 3215 3216 addToGraph(LoopHint); 3217 3218 if (m_vm->watchdog && m_vm->watchdog->isEnabled()) 3219 addToGraph(CheckWatchdogTimer); 3220 3221 NEXT_OPCODE(op_loop_hint); 3222 } 3223 3224 case op_init_lazy_reg: { 3225 set(VirtualRegister(currentInstruction[1].u.operand), getJSConstantForValue(JSValue())); 3226 ASSERT(operandIsLocal(currentInstruction[1].u.operand)); 3227 m_graph.m_lazyVars.set(VirtualRegister(currentInstruction[1].u.operand).toLocal()); 3228 NEXT_OPCODE(op_init_lazy_reg); 3229 } 3230 3231 case op_create_activation: { 3232 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(CreateActivation, get(VirtualRegister(currentInstruction[1].u.operand)))); 3233 NEXT_OPCODE(op_create_activation); 3234 } 3235 3236 case op_create_arguments: { 3237 m_graph.m_hasArguments = true; 3238 Node* createArguments = addToGraph(CreateArguments, get(VirtualRegister(currentInstruction[1].u.operand))); 3239 set(VirtualRegister(currentInstruction[1].u.operand), createArguments); 3240 set(unmodifiedArgumentsRegister(VirtualRegister(currentInstruction[1].u.operand)), createArguments); 3241 NEXT_OPCODE(op_create_arguments); 3242 } 3243 3244 case op_tear_off_activation: { 3245 addToGraph(TearOffActivation, get(VirtualRegister(currentInstruction[1].u.operand))); 3246 NEXT_OPCODE(op_tear_off_activation); 3247 } 3248 3249 case op_tear_off_arguments: { 3250 m_graph.m_hasArguments = true; 3251 addToGraph(TearOffArguments, get(unmodifiedArgumentsRegister(VirtualRegister(currentInstruction[1].u.operand))), get(VirtualRegister(currentInstruction[2].u.operand))); 3252 NEXT_OPCODE(op_tear_off_arguments); 3253 } 3254 3255 case op_get_arguments_length: { 3256 m_graph.m_hasArguments = true; 3257 set(VirtualRegister(currentInstruction[1].u.operand), addToGraph(GetMyArgumentsLengthSafe)); 3258 NEXT_OPCODE(op_get_arguments_length); 3259 } 3260 3261 case op_get_argument_by_val: { 3262 m_graph.m_hasArguments = true; 3263 set(VirtualRegister(currentInstruction[1].u.operand), 3264 addToGraph( 3265 GetMyArgumentByValSafe, OpInfo(0), OpInfo(getPrediction()), 3266 get(VirtualRegister(currentInstruction[3].u.operand)))); 3267 NEXT_OPCODE(op_get_argument_by_val); 3268 } 3269 3270 case op_new_func: { 3271 if (!currentInstruction[3].u.operand) { 3272 set(VirtualRegister(currentInstruction[1].u.operand), 3273 addToGraph(NewFunctionNoCheck, OpInfo(currentInstruction[2].u.operand))); 3274 } else { 3275 set(VirtualRegister(currentInstruction[1].u.operand), 3276 addToGraph( 3277 NewFunction, 3278 OpInfo(currentInstruction[2].u.operand), 3279 get(VirtualRegister(currentInstruction[1].u.operand)))); 3280 } 3281 NEXT_OPCODE(op_new_func); 3282 } 3283 3284 case op_new_captured_func: { 3285 Node* function = addToGraph( 3286 NewFunctionNoCheck, OpInfo(currentInstruction[2].u.operand)); 3287 if (VariableWatchpointSet* set = currentInstruction[3].u.watchpointSet) 3288 addToGraph(NotifyWrite, OpInfo(set), function); 3289 set(VirtualRegister(currentInstruction[1].u.operand), function); 3290 NEXT_OPCODE(op_new_captured_func); 3291 } 3292 3293 case op_new_func_exp: { 3294 set(VirtualRegister(currentInstruction[1].u.operand), 3295 addToGraph(NewFunctionExpression, OpInfo(currentInstruction[2].u.operand))); 3296 NEXT_OPCODE(op_new_func_exp); 3297 } 3298 3299 case op_typeof: { 3300 set(VirtualRegister(currentInstruction[1].u.operand), 3301 addToGraph(TypeOf, get(VirtualRegister(currentInstruction[2].u.operand)))); 3302 NEXT_OPCODE(op_typeof); 3303 } 3304 3305 case op_to_number: { 3306 Node* node = get(VirtualRegister(currentInstruction[2].u.operand)); 3307 addToGraph(Phantom, Edge(node, NumberUse)); 3308 set(VirtualRegister(currentInstruction[1].u.operand), node); 3309 NEXT_OPCODE(op_to_number); 3310 } 3311 3312 case op_in: { 3313 set(VirtualRegister(currentInstruction[1].u.operand), 3314 addToGraph(In, get(VirtualRegister(currentInstruction[2].u.operand)), get(VirtualRegister(currentInstruction[3].u.operand)))); 3315 NEXT_OPCODE(op_in); 3316 } 3317 3318 default: 3319 // Parse failed! This should not happen because the capabilities checker 3320 // should have caught it. 3321 RELEASE_ASSERT_NOT_REACHED(); 3322 return false; 3323 } 3324 } 3325} 3326 3327void ByteCodeParser::linkBlock(BasicBlock* block, Vector<BasicBlock*>& possibleTargets) 3328{ 3329 ASSERT(!block->isLinked); 3330 ASSERT(!block->isEmpty()); 3331 Node* node = block->last(); 3332 ASSERT(node->isTerminal()); 3333 3334 switch (node->op()) { 3335 case Jump: 3336 node->targetBlock() = blockForBytecodeOffset(possibleTargets, node->targetBytecodeOffsetDuringParsing()); 3337 break; 3338 3339 case Branch: { 3340 BranchData* data = node->branchData(); 3341 data->taken.block = blockForBytecodeOffset(possibleTargets, data->takenBytecodeIndex()); 3342 data->notTaken.block = blockForBytecodeOffset(possibleTargets, data->notTakenBytecodeIndex()); 3343 break; 3344 } 3345 3346 case Switch: { 3347 SwitchData* data = node->switchData(); 3348 for (unsigned i = node->switchData()->cases.size(); i--;) 3349 data->cases[i].target.block = blockForBytecodeOffset(possibleTargets, data->cases[i].target.bytecodeIndex()); 3350 data->fallThrough.block = blockForBytecodeOffset(possibleTargets, data->fallThrough.bytecodeIndex()); 3351 break; 3352 } 3353 3354 default: 3355 break; 3356 } 3357 3358#if !ASSERT_DISABLED 3359 block->isLinked = true; 3360#endif 3361} 3362 3363void ByteCodeParser::linkBlocks(Vector<UnlinkedBlock>& unlinkedBlocks, Vector<BasicBlock*>& possibleTargets) 3364{ 3365 for (size_t i = 0; i < unlinkedBlocks.size(); ++i) { 3366 if (unlinkedBlocks[i].m_needsNormalLinking) { 3367 linkBlock(unlinkedBlocks[i].m_block, possibleTargets); 3368 unlinkedBlocks[i].m_needsNormalLinking = false; 3369 } 3370 } 3371} 3372 3373void ByteCodeParser::buildOperandMapsIfNecessary() 3374{ 3375 if (m_haveBuiltOperandMaps) 3376 return; 3377 3378 for (size_t i = 0; i < m_codeBlock->numberOfIdentifiers(); ++i) 3379 m_identifierMap.add(m_codeBlock->identifier(i).impl(), i); 3380 for (size_t i = 0; i < m_codeBlock->numberOfConstantRegisters(); ++i) { 3381 JSValue value = m_codeBlock->getConstant(i + FirstConstantRegisterIndex); 3382 if (!value) 3383 m_emptyJSValueIndex = i + FirstConstantRegisterIndex; 3384 else 3385 m_jsValueMap.add(JSValue::encode(value), i + FirstConstantRegisterIndex); 3386 } 3387 3388 m_haveBuiltOperandMaps = true; 3389} 3390 3391ByteCodeParser::InlineStackEntry::InlineStackEntry( 3392 ByteCodeParser* byteCodeParser, 3393 CodeBlock* codeBlock, 3394 CodeBlock* profiledBlock, 3395 BasicBlock* callsiteBlockHead, 3396 JSFunction* callee, // Null if this is a closure call. 3397 VirtualRegister returnValueVR, 3398 VirtualRegister inlineCallFrameStart, 3399 int argumentCountIncludingThis, 3400 CodeSpecializationKind kind) 3401 : m_byteCodeParser(byteCodeParser) 3402 , m_codeBlock(codeBlock) 3403 , m_profiledBlock(profiledBlock) 3404 , m_callsiteBlockHead(callsiteBlockHead) 3405 , m_returnValue(returnValueVR) 3406 , m_didReturn(false) 3407 , m_didEarlyReturn(false) 3408 , m_caller(byteCodeParser->m_inlineStackTop) 3409{ 3410 { 3411 ConcurrentJITLocker locker(m_profiledBlock->m_lock); 3412 m_lazyOperands.initialize(locker, m_profiledBlock->lazyOperandValueProfiles()); 3413 m_exitProfile.initialize(locker, profiledBlock->exitProfile()); 3414 3415 // We do this while holding the lock because we want to encourage StructureStubInfo's 3416 // to be potentially added to operations and because the profiled block could be in the 3417 // middle of LLInt->JIT tier-up in which case we would be adding the info's right now. 3418 if (m_profiledBlock->hasBaselineJITProfiling()) { 3419 m_profiledBlock->getStubInfoMap(locker, m_stubInfos); 3420 m_profiledBlock->getCallLinkInfoMap(locker, m_callLinkInfos); 3421 } 3422 } 3423 3424 m_argumentPositions.resize(argumentCountIncludingThis); 3425 for (int i = 0; i < argumentCountIncludingThis; ++i) { 3426 byteCodeParser->m_graph.m_argumentPositions.append(ArgumentPosition()); 3427 ArgumentPosition* argumentPosition = &byteCodeParser->m_graph.m_argumentPositions.last(); 3428 m_argumentPositions[i] = argumentPosition; 3429 } 3430 3431 // Track the code-block-global exit sites. 3432 if (m_exitProfile.hasExitSite(ArgumentsEscaped)) { 3433 byteCodeParser->m_graph.m_executablesWhoseArgumentsEscaped.add( 3434 codeBlock->ownerExecutable()); 3435 } 3436 3437 if (m_caller) { 3438 // Inline case. 3439 ASSERT(codeBlock != byteCodeParser->m_codeBlock); 3440 ASSERT(inlineCallFrameStart.isValid()); 3441 ASSERT(callsiteBlockHead); 3442 3443 m_inlineCallFrame = byteCodeParser->m_graph.m_plan.inlineCallFrames->add(); 3444 initializeLazyWriteBarrierForInlineCallFrameExecutable( 3445 byteCodeParser->m_graph.m_plan.writeBarriers, 3446 m_inlineCallFrame->executable, 3447 byteCodeParser->m_codeBlock, 3448 m_inlineCallFrame, 3449 byteCodeParser->m_codeBlock->ownerExecutable(), 3450 codeBlock->ownerExecutable()); 3451 m_inlineCallFrame->stackOffset = inlineCallFrameStart.offset() - JSStack::CallFrameHeaderSize; 3452 if (callee) { 3453 m_inlineCallFrame->calleeRecovery = ValueRecovery::constant(callee); 3454 m_inlineCallFrame->isClosureCall = false; 3455 } else 3456 m_inlineCallFrame->isClosureCall = true; 3457 m_inlineCallFrame->caller = byteCodeParser->currentCodeOrigin(); 3458 m_inlineCallFrame->arguments.resize(argumentCountIncludingThis); // Set the number of arguments including this, but don't configure the value recoveries, yet. 3459 m_inlineCallFrame->isCall = isCall(kind); 3460 3461 if (m_inlineCallFrame->caller.inlineCallFrame) 3462 m_inlineCallFrame->capturedVars = m_inlineCallFrame->caller.inlineCallFrame->capturedVars; 3463 else { 3464 for (int i = byteCodeParser->m_codeBlock->m_numVars; i--;) { 3465 if (byteCodeParser->m_codeBlock->isCaptured(virtualRegisterForLocal(i))) 3466 m_inlineCallFrame->capturedVars.set(i); 3467 } 3468 } 3469 3470 for (int i = argumentCountIncludingThis; i--;) { 3471 VirtualRegister argument = virtualRegisterForArgument(i); 3472 if (codeBlock->isCaptured(argument)) 3473 m_inlineCallFrame->capturedVars.set(VirtualRegister(argument.offset() + m_inlineCallFrame->stackOffset).toLocal()); 3474 } 3475 for (size_t i = codeBlock->m_numVars; i--;) { 3476 VirtualRegister local = virtualRegisterForLocal(i); 3477 if (codeBlock->isCaptured(local)) 3478 m_inlineCallFrame->capturedVars.set(VirtualRegister(local.offset() + m_inlineCallFrame->stackOffset).toLocal()); 3479 } 3480 3481 byteCodeParser->buildOperandMapsIfNecessary(); 3482 3483 m_identifierRemap.resize(codeBlock->numberOfIdentifiers()); 3484 m_constantRemap.resize(codeBlock->numberOfConstantRegisters()); 3485 m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers()); 3486 m_switchRemap.resize(codeBlock->numberOfSwitchJumpTables()); 3487 3488 for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i) { 3489 StringImpl* rep = codeBlock->identifier(i).impl(); 3490 BorrowedIdentifierMap::AddResult result = byteCodeParser->m_identifierMap.add(rep, byteCodeParser->m_graph.identifiers().numberOfIdentifiers()); 3491 if (result.isNewEntry) 3492 byteCodeParser->m_graph.identifiers().addLazily(rep); 3493 m_identifierRemap[i] = result.iterator->value; 3494 } 3495 for (size_t i = 0; i < codeBlock->numberOfConstantRegisters(); ++i) { 3496 JSValue value = codeBlock->getConstant(i + FirstConstantRegisterIndex); 3497 if (!value) { 3498 if (byteCodeParser->m_emptyJSValueIndex == UINT_MAX) { 3499 byteCodeParser->m_emptyJSValueIndex = byteCodeParser->m_codeBlock->numberOfConstantRegisters() + FirstConstantRegisterIndex; 3500 byteCodeParser->addConstant(JSValue()); 3501 byteCodeParser->m_constants.append(ConstantRecord()); 3502 } 3503 m_constantRemap[i] = byteCodeParser->m_emptyJSValueIndex; 3504 continue; 3505 } 3506 JSValueMap::AddResult result = byteCodeParser->m_jsValueMap.add(JSValue::encode(value), byteCodeParser->m_codeBlock->numberOfConstantRegisters() + FirstConstantRegisterIndex); 3507 if (result.isNewEntry) { 3508 byteCodeParser->addConstant(value); 3509 byteCodeParser->m_constants.append(ConstantRecord()); 3510 } 3511 m_constantRemap[i] = result.iterator->value; 3512 } 3513 for (unsigned i = 0; i < codeBlock->numberOfConstantBuffers(); ++i) { 3514 // If we inline the same code block multiple times, we don't want to needlessly 3515 // duplicate its constant buffers. 3516 HashMap<ConstantBufferKey, unsigned>::iterator iter = 3517 byteCodeParser->m_constantBufferCache.find(ConstantBufferKey(codeBlock, i)); 3518 if (iter != byteCodeParser->m_constantBufferCache.end()) { 3519 m_constantBufferRemap[i] = iter->value; 3520 continue; 3521 } 3522 Vector<JSValue>& buffer = codeBlock->constantBufferAsVector(i); 3523 unsigned newIndex = byteCodeParser->m_codeBlock->addConstantBuffer(buffer); 3524 m_constantBufferRemap[i] = newIndex; 3525 byteCodeParser->m_constantBufferCache.add(ConstantBufferKey(codeBlock, i), newIndex); 3526 } 3527 for (unsigned i = 0; i < codeBlock->numberOfSwitchJumpTables(); ++i) { 3528 m_switchRemap[i] = byteCodeParser->m_codeBlock->numberOfSwitchJumpTables(); 3529 byteCodeParser->m_codeBlock->addSwitchJumpTable() = codeBlock->switchJumpTable(i); 3530 } 3531 m_callsiteBlockHeadNeedsLinking = true; 3532 } else { 3533 // Machine code block case. 3534 ASSERT(codeBlock == byteCodeParser->m_codeBlock); 3535 ASSERT(!callee); 3536 ASSERT(!returnValueVR.isValid()); 3537 ASSERT(!inlineCallFrameStart.isValid()); 3538 ASSERT(!callsiteBlockHead); 3539 3540 m_inlineCallFrame = 0; 3541 3542 m_identifierRemap.resize(codeBlock->numberOfIdentifiers()); 3543 m_constantRemap.resize(codeBlock->numberOfConstantRegisters()); 3544 m_constantBufferRemap.resize(codeBlock->numberOfConstantBuffers()); 3545 m_switchRemap.resize(codeBlock->numberOfSwitchJumpTables()); 3546 for (size_t i = 0; i < codeBlock->numberOfIdentifiers(); ++i) 3547 m_identifierRemap[i] = i; 3548 for (size_t i = 0; i < codeBlock->numberOfConstantRegisters(); ++i) 3549 m_constantRemap[i] = i + FirstConstantRegisterIndex; 3550 for (size_t i = 0; i < codeBlock->numberOfConstantBuffers(); ++i) 3551 m_constantBufferRemap[i] = i; 3552 for (size_t i = 0; i < codeBlock->numberOfSwitchJumpTables(); ++i) 3553 m_switchRemap[i] = i; 3554 m_callsiteBlockHeadNeedsLinking = false; 3555 } 3556 3557 for (size_t i = 0; i < m_constantRemap.size(); ++i) 3558 ASSERT(m_constantRemap[i] >= static_cast<unsigned>(FirstConstantRegisterIndex)); 3559 3560 byteCodeParser->m_inlineStackTop = this; 3561} 3562 3563void ByteCodeParser::parseCodeBlock() 3564{ 3565 CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock; 3566 3567 if (m_graph.compilation()) { 3568 m_graph.compilation()->addProfiledBytecodes( 3569 *m_vm->m_perBytecodeProfiler, m_inlineStackTop->m_profiledBlock); 3570 } 3571 3572 bool shouldDumpBytecode = Options::dumpBytecodeAtDFGTime(); 3573 if (shouldDumpBytecode) { 3574 dataLog("Parsing ", *codeBlock); 3575 if (inlineCallFrame()) { 3576 dataLog( 3577 " for inlining at ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), 3578 " ", inlineCallFrame()->caller); 3579 } 3580 dataLog( 3581 ": captureCount = ", codeBlock->symbolTable() ? codeBlock->symbolTable()->captureCount() : 0, 3582 ", needsActivation = ", codeBlock->needsActivation(), 3583 ", isStrictMode = ", codeBlock->ownerExecutable()->isStrictMode(), "\n"); 3584 codeBlock->baselineVersion()->dumpBytecode(); 3585 } 3586 3587 Vector<unsigned, 32> jumpTargets; 3588 computePreciseJumpTargets(codeBlock, jumpTargets); 3589 if (Options::dumpBytecodeAtDFGTime()) { 3590 dataLog("Jump targets: "); 3591 CommaPrinter comma; 3592 for (unsigned i = 0; i < jumpTargets.size(); ++i) 3593 dataLog(comma, jumpTargets[i]); 3594 dataLog("\n"); 3595 } 3596 3597 for (unsigned jumpTargetIndex = 0; jumpTargetIndex <= jumpTargets.size(); ++jumpTargetIndex) { 3598 // The maximum bytecode offset to go into the current basicblock is either the next jump target, or the end of the instructions. 3599 unsigned limit = jumpTargetIndex < jumpTargets.size() ? jumpTargets[jumpTargetIndex] : codeBlock->instructions().size(); 3600 ASSERT(m_currentIndex < limit); 3601 3602 // Loop until we reach the current limit (i.e. next jump target). 3603 do { 3604 if (!m_currentBlock) { 3605 // Check if we can use the last block. 3606 if (m_graph.numBlocks() && m_graph.lastBlock()->isEmpty()) { 3607 // This must be a block belonging to us. 3608 ASSERT(m_inlineStackTop->m_unlinkedBlocks.last().m_block == m_graph.lastBlock()); 3609 // Either the block is linkable or it isn't. If it's linkable then it's the last 3610 // block in the blockLinkingTargets list. If it's not then the last block will 3611 // have a lower bytecode index that the one we're about to give to this block. 3612 if (m_inlineStackTop->m_blockLinkingTargets.isEmpty() || m_inlineStackTop->m_blockLinkingTargets.last()->bytecodeBegin != m_currentIndex) { 3613 // Make the block linkable. 3614 ASSERT(m_inlineStackTop->m_blockLinkingTargets.isEmpty() || m_inlineStackTop->m_blockLinkingTargets.last()->bytecodeBegin < m_currentIndex); 3615 m_inlineStackTop->m_blockLinkingTargets.append(m_graph.lastBlock()); 3616 } 3617 // Change its bytecode begin and continue. 3618 m_currentBlock = m_graph.lastBlock(); 3619 m_currentBlock->bytecodeBegin = m_currentIndex; 3620 } else { 3621 RefPtr<BasicBlock> block = adoptRef(new BasicBlock(m_currentIndex, m_numArguments, m_numLocals, PNaN)); 3622 m_currentBlock = block.get(); 3623 // This assertion checks two things: 3624 // 1) If the bytecodeBegin is greater than currentIndex, then something has gone 3625 // horribly wrong. So, we're probably generating incorrect code. 3626 // 2) If the bytecodeBegin is equal to the currentIndex, then we failed to do 3627 // a peephole coalescing of this block in the if statement above. So, we're 3628 // generating suboptimal code and leaving more work for the CFG simplifier. 3629 ASSERT(m_inlineStackTop->m_unlinkedBlocks.isEmpty() || m_inlineStackTop->m_unlinkedBlocks.last().m_block->bytecodeBegin < m_currentIndex); 3630 m_inlineStackTop->m_unlinkedBlocks.append(UnlinkedBlock(block.get())); 3631 m_inlineStackTop->m_blockLinkingTargets.append(block.get()); 3632 // The first block is definitely an OSR target. 3633 if (!m_graph.numBlocks()) 3634 block->isOSRTarget = true; 3635 m_graph.appendBlock(block); 3636 prepareToParseBlock(); 3637 } 3638 } 3639 3640 bool shouldContinueParsing = parseBlock(limit); 3641 3642 // We should not have gone beyond the limit. 3643 ASSERT(m_currentIndex <= limit); 3644 3645 // We should have planted a terminal, or we just gave up because 3646 // we realized that the jump target information is imprecise, or we 3647 // are at the end of an inline function, or we realized that we 3648 // should stop parsing because there was a return in the first 3649 // basic block. 3650 ASSERT(m_currentBlock->isEmpty() || m_currentBlock->last()->isTerminal() || (m_currentIndex == codeBlock->instructions().size() && inlineCallFrame()) || !shouldContinueParsing); 3651 3652 if (!shouldContinueParsing) 3653 return; 3654 3655 m_currentBlock = 0; 3656 } while (m_currentIndex < limit); 3657 } 3658 3659 // Should have reached the end of the instructions. 3660 ASSERT(m_currentIndex == codeBlock->instructions().size()); 3661} 3662 3663bool ByteCodeParser::parse() 3664{ 3665 // Set during construction. 3666 ASSERT(!m_currentIndex); 3667 3668 if (Options::verboseDFGByteCodeParsing()) 3669 dataLog("Parsing ", *m_codeBlock, "\n"); 3670 3671 m_dfgCodeBlock = m_graph.m_plan.profiledDFGCodeBlock.get(); 3672 if (isFTL(m_graph.m_plan.mode) && m_dfgCodeBlock 3673 && Options::enablePolyvariantDevirtualization()) { 3674 if (Options::enablePolyvariantCallInlining()) 3675 CallLinkStatus::computeDFGStatuses(m_dfgCodeBlock, m_callContextMap); 3676 if (Options::enablePolyvariantByIdInlining()) 3677 m_dfgCodeBlock->getStubInfoMap(m_dfgStubInfos); 3678 } 3679 3680 if (m_codeBlock->captureCount()) { 3681 SymbolTable* symbolTable = m_codeBlock->symbolTable(); 3682 ConcurrentJITLocker locker(symbolTable->m_lock); 3683 SymbolTable::Map::iterator iter = symbolTable->begin(locker); 3684 SymbolTable::Map::iterator end = symbolTable->end(locker); 3685 for (; iter != end; ++iter) { 3686 VariableWatchpointSet* set = iter->value.watchpointSet(); 3687 if (!set) 3688 continue; 3689 size_t index = static_cast<size_t>(VirtualRegister(iter->value.getIndex()).toLocal()); 3690 while (m_localWatchpoints.size() <= index) 3691 m_localWatchpoints.append(nullptr); 3692 m_localWatchpoints[index] = set; 3693 } 3694 } 3695 3696 InlineStackEntry inlineStackEntry( 3697 this, m_codeBlock, m_profiledBlock, 0, 0, VirtualRegister(), VirtualRegister(), 3698 m_codeBlock->numParameters(), CodeForCall); 3699 3700 parseCodeBlock(); 3701 3702 linkBlocks(inlineStackEntry.m_unlinkedBlocks, inlineStackEntry.m_blockLinkingTargets); 3703 m_graph.determineReachability(); 3704 m_graph.killUnreachableBlocks(); 3705 3706 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) { 3707 BasicBlock* block = m_graph.block(blockIndex); 3708 if (!block) 3709 continue; 3710 ASSERT(block->variablesAtHead.numberOfLocals() == m_graph.block(0)->variablesAtHead.numberOfLocals()); 3711 ASSERT(block->variablesAtHead.numberOfArguments() == m_graph.block(0)->variablesAtHead.numberOfArguments()); 3712 ASSERT(block->variablesAtTail.numberOfLocals() == m_graph.block(0)->variablesAtHead.numberOfLocals()); 3713 ASSERT(block->variablesAtTail.numberOfArguments() == m_graph.block(0)->variablesAtHead.numberOfArguments()); 3714 } 3715 3716 m_graph.m_localVars = m_numLocals; 3717 m_graph.m_parameterSlots = m_parameterSlots; 3718 3719 return true; 3720} 3721 3722bool parse(Graph& graph) 3723{ 3724 SamplingRegion samplingRegion("DFG Parsing"); 3725 return ByteCodeParser(graph).parse(); 3726} 3727 3728} } // namespace JSC::DFG 3729 3730#endif 3731