Changeset 185240 in webkit
- Timestamp:
- Jun 4, 2015 10:20:45 PM (9 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 2 added
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r185239 r185240 1 2015-06-04 Benjamin Poulain <bpoulain@apple.com> 2 3 [JSC] Always track out-of-bounds array access explicitly instead of relying on the slow case 4 https://bugs.webkit.org/show_bug.cgi?id=145673 5 6 Reviewed by Geoffrey Garen. 7 8 Previously, we were deciding to use out-of-bounds speculation based on two informations: 9 -Explicitly detected out-of-bounds accesses tracked on ArrayProfile. 10 -The number of time we took the slow cases in the baseline JIT. 11 12 The heuristic based on slow cases was a little too fragile. 13 14 In some cases, we were running into that limit just because the indexing type changes between 15 two values (typically Int32Array and DoubleArray). Sometimes we were just unlucky on what 16 we used for the inline cache. 17 18 In Kraken, this was hurting us on "audio-beat-detection" and "audio-fft". The array types we see 19 change between Int32 and Double. We run into the slow path a bit but never hit 20 out-of-bounds. 21 22 By the time we compile in DFG, we have stable Double Arrays but we speculate out-of-bounds based 23 on the number of slow cases we took. Because of that, we start boxing the double on GetByVal, 24 using DoubleRep, etc. adding a ton of overhead over otherwise very simple operations. 25 26 WebXPRT was also suffering from this problem but the other way arround: we were missing 27 the out-of-bounds accesses due to changes in indexing types, we were below the threshold 28 of slow-path access, thus we predicted in-bounds accesses for code that was doing plenty 29 of out-of-bands. 30 31 32 This patch fixes the problem by tracking the out-of-bounds access explicitly any time we go 33 into the slow path in baseline JIT. Since we no longer miss any out-of-bounds, we can remove 34 the slow-path heuristic. 35 36 There is new additional special case in the C code regarding out-of-bounds: Arguments access. 37 Mispredicting out-of-bounds accesses on arguments is a disaster for performance, so those are 38 tracked in the way DFG expect it. 39 40 41 There are a few important cases that are still not covered optimally: 42 -PutByVal on Arguments. 43 -Get/Put ByVal on TypedArray. 44 Those are simply not used by DFG in any way. TypedArrays should probably be looked at in the future. 45 46 * bytecode/ArrayProfile.cpp: 47 (JSC::ArrayProfile::computeUpdatedPrediction): 48 The inline-cache repatch cases now update the ArrayProfile information. This has no value in baseline 49 JIT but it helps avoiding one recompile in DFG for the missing ArrayProfile information. 50 51 * bytecode/ArrayProfile.h: 52 (JSC::ArrayProfile::setOutOfBounds): 53 * dfg/DFGByteCodeParser.cpp: 54 (JSC::DFG::ByteCodeParser::getArrayMode): 55 (JSC::DFG::ByteCodeParser::parseBlock): 56 (JSC::DFG::ByteCodeParser::getArrayModeConsideringSlowPath): Deleted. 57 * jit/CCallHelpers.h: 58 (JSC::CCallHelpers::setupArgumentsWithExecState): 59 * jit/JIT.h: 60 * jit/JITInlines.h: 61 (JSC::JIT::callOperation): 62 * jit/JITOpcodes.cpp: 63 (JSC::JIT::emitSlow_op_has_indexed_property): 64 * jit/JITOpcodes32_64.cpp: 65 (JSC::JIT::emitSlow_op_has_indexed_property): 66 * jit/JITOperations.cpp: 67 (JSC::canUseFastArgumentAccess): 68 This is not my favorite part of this patch. 69 70 I tried having JSObject::canGetIndexQuickly() handle arguments which would put everything 71 on the generic path. Unfortunately, that code is very performance sensitive and some benchmarks were 72 impacted by over 10% 73 74 I left JSObject::canGetIndexQuickly() alone, and I added the canUseFastArgumentAccess() mirroring 75 how DFG uses out-of-bounds for Arguments. 76 77 (JSC::getByVal): 78 * jit/JITOperations.h: 79 * jit/JITPropertyAccess.cpp: 80 (JSC::JIT::emitSlow_op_get_by_val): 81 (JSC::JIT::emitSlow_op_put_by_val): 82 * jit/JITPropertyAccess32_64.cpp: 83 (JSC::JIT::emitSlow_op_get_by_val): 84 (JSC::JIT::emitSlow_op_put_by_val): 85 * runtime/JSPromiseFunctions.cpp: 86 * tests/stress/get-by-val-out-of-bounds-basics.js: Added. 87 (opaqueGetByValOnInt32ArrayEarlyOutOfBounds): 88 (testInt32ArrayEarlyOutOfBounds): 89 (testIndexingTypeChangesOnInt32Array): 90 (opaqueGetByValOnStringArrayHotOutOfBounds): 91 (testStringArrayHotOutOfBounds): 92 (testIndexingTypeChangesOnStringArray): 93 (opaqueGetByValOnStringAndInt32ArrayHotOutOfBounds): 94 (testStringAndInt32ArrayHotOutOfBounds): 95 (opaqueGetByValOnDoubleArrayHotOutOfBounds): 96 * tests/stress/put-by-val-out-of-bounds-basics.js: Added. 97 (opaquePutByValOnInt32ArrayEarlyOutOfBounds): 98 (testInt32ArrayEarlyOutOfBounds): 99 (opaquePutByValOnStringArrayHotOutOfBounds): 100 (testStringArrayHotOutOfBounds): 101 1 102 2015-06-03 Filip Pizlo <fpizlo@apple.com> 2 103 -
trunk/Source/JavaScriptCore/bytecode/ArrayProfile.cpp
r183450 r185240 95 95 } 96 96 97 void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker& , CodeBlock* codeBlock)97 void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker& locker, CodeBlock* codeBlock) 98 98 { 99 99 if (!m_lastSeenStructureID) … … 101 101 102 102 Structure* lastSeenStructure = codeBlock->heap()->structureIDTable().get(m_lastSeenStructureID); 103 computeUpdatedPrediction(locker, codeBlock, lastSeenStructure); 104 m_lastSeenStructureID = 0; 105 } 106 107 void ArrayProfile::computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock* codeBlock, Structure* lastSeenStructure) 108 { 103 109 m_observedArrayModes |= arrayModeFromStructure(lastSeenStructure); 104 110 … … 115 121 && !globalObject->isOriginalTypedArrayStructure(lastSeenStructure)) 116 122 m_usesOriginalArrayStructures = false; 117 m_lastSeenStructureID = 0;118 123 } 119 124 -
trunk/Source/JavaScriptCore/bytecode/ArrayProfile.h
r183450 r185240 210 210 ArrayModes* addressOfArrayModes() { return &m_observedArrayModes; } 211 211 bool* addressOfMayStoreToHole() { return &m_mayStoreToHole; } 212 213 void setOutOfBounds() { m_outOfBounds = true; } 212 214 bool* addressOfOutOfBounds() { return &m_outOfBounds; } 213 215 … … 218 220 219 221 void computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock*); 222 void computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock*, Structure* lastSeenStructure); 220 223 221 224 ArrayModes observedArrayModes(const ConcurrentJITLocker&) const { return m_observedArrayModes; } -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r185042 r185240 746 746 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 747 747 profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock); 748 return ArrayMode::fromObserved(locker, profile, action, false); 748 bool makeSafe = profile->outOfBounds(locker); 749 return ArrayMode::fromObserved(locker, profile, action, makeSafe); 749 750 } 750 751 … … 752 753 { 753 754 return getArrayMode(profile, Array::Read); 754 }755 756 ArrayMode getArrayModeConsideringSlowPath(ArrayProfile* profile, Array::Action action)757 {758 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);759 760 profile->computeUpdatedPrediction(locker, m_inlineStackTop->m_profiledBlock);761 762 bool makeSafe =763 m_inlineStackTop->m_profiledBlock->likelyToTakeSlowCase(m_currentIndex)764 || profile->outOfBounds(locker);765 766 ArrayMode result = ArrayMode::fromObserved(locker, profile, action, makeSafe);767 768 return result;769 755 } 770 756 … … 3100 3086 3101 3087 Node* base = get(VirtualRegister(currentInstruction[2].u.operand)); 3102 ArrayMode arrayMode = getArrayMode ConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Read);3088 ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read); 3103 3089 Node* property = get(VirtualRegister(currentInstruction[3].u.operand)); 3104 3090 Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property); … … 3112 3098 Node* base = get(VirtualRegister(currentInstruction[1].u.operand)); 3113 3099 3114 ArrayMode arrayMode = getArrayMode ConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Write);3100 ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Write); 3115 3101 3116 3102 Node* property = get(VirtualRegister(currentInstruction[2].u.operand)); … … 3865 3851 case op_has_indexed_property: { 3866 3852 Node* base = get(VirtualRegister(currentInstruction[2].u.operand)); 3867 ArrayMode arrayMode = getArrayMode ConsideringSlowPath(currentInstruction[4].u.arrayProfile, Array::Read);3853 ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read); 3868 3854 Node* property = get(VirtualRegister(currentInstruction[3].u.operand)); 3869 3855 Node* hasIterableProperty = addToGraph(HasIndexedProperty, OpInfo(arrayMode.asWord()), base, property); -
trunk/Source/JavaScriptCore/jit/CCallHelpers.h
r184324 r185240 733 733 addCallArgument(arg5); 734 734 addCallArgument(arg6); 735 } 736 737 ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, TrustedImmPtr arg7) 738 { 739 resetCallArguments(); 740 addCallArgument(GPRInfo::callFrameRegister); 741 addCallArgument(arg1); 742 addCallArgument(arg2); 743 addCallArgument(arg3); 744 addCallArgument(arg4); 745 addCallArgument(arg5); 746 addCallArgument(arg6); 747 addCallArgument(arg7); 735 748 } 736 749 … … 1467 1480 } 1468 1481 1482 ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, TrustedImmPtr arg5) 1483 { 1484 poke(arg5, POKE_ARGUMENT_OFFSET + 1); 1485 poke(arg4, POKE_ARGUMENT_OFFSET); 1486 setupArgumentsWithExecState(arg1, arg2, arg3); 1487 } 1488 1469 1489 ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, GPRReg arg3, GPRReg arg4) 1470 1490 { … … 1721 1741 ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5, TrustedImm32 arg6) 1722 1742 { 1743 poke(arg6, POKE_ARGUMENT_OFFSET + 2); 1744 poke(arg5, POKE_ARGUMENT_OFFSET + 1); 1745 poke(arg4, POKE_ARGUMENT_OFFSET); 1746 setupArgumentsWithExecState(arg1, arg2, arg3); 1747 } 1748 1749 ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5, GPRReg arg6, TrustedImmPtr arg7) 1750 { 1751 poke(arg7, POKE_ARGUMENT_OFFSET + 3); 1723 1752 poke(arg6, POKE_ARGUMENT_OFFSET + 2); 1724 1753 poke(arg5, POKE_ARGUMENT_OFFSET + 1); … … 1829 1858 { 1830 1859 setupThreeStubArgsGPR<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3, GPRInfo::argumentGPR4>(arg1, arg3, arg4); 1860 } 1861 1862 ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4) 1863 { 1864 setupThreeStubArgsGPR<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg1, arg2, arg3); 1865 move(arg4, GPRInfo::argumentGPR4); 1866 move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0); 1831 1867 } 1832 1868 -
trunk/Source/JavaScriptCore/jit/JIT.h
r184828 r185240 703 703 MacroAssembler::Call callOperation(J_JITOperation_EJIdc, int, GPRReg, const Identifier*); 704 704 MacroAssembler::Call callOperation(J_JITOperation_EJJ, int, GPRReg, GPRReg); 705 MacroAssembler::Call callOperation(J_JITOperation_EJJAp, int, GPRReg, GPRReg, ArrayProfile*); 705 706 MacroAssembler::Call callOperation(C_JITOperation_EJsc, GPRReg); 706 707 MacroAssembler::Call callOperation(J_JITOperation_EJscC, int, GPRReg, JSCell*); … … 744 745 #endif 745 746 MacroAssembler::Call callOperation(V_JITOperation_EJJJ, RegisterID, RegisterID, RegisterID); 747 MacroAssembler::Call callOperation(V_JITOperation_EJJJAp, RegisterID, RegisterID, RegisterID, ArrayProfile*); 746 748 MacroAssembler::Call callOperation(V_JITOperation_EJZJ, RegisterID, int32_t, RegisterID); 747 749 MacroAssembler::Call callOperation(V_JITOperation_EJZ, RegisterID, int32_t); … … 759 761 MacroAssembler::Call callOperation(J_JITOperation_EJIdc, int, GPRReg, GPRReg, const Identifier*); 760 762 MacroAssembler::Call callOperation(J_JITOperation_EJJ, int, GPRReg, GPRReg, GPRReg, GPRReg); 763 MacroAssembler::Call callOperation(J_JITOperation_EJJAp, int, GPRReg, GPRReg, GPRReg, GPRReg, ArrayProfile*); 761 764 MacroAssembler::Call callOperation(P_JITOperation_EJS, GPRReg, GPRReg, size_t); 762 765 MacroAssembler::Call callOperation(S_JITOperation_EJ, RegisterID, RegisterID); … … 765 768 MacroAssembler::Call callOperation(V_JITOperation_EJ, RegisterID, RegisterID); 766 769 MacroAssembler::Call callOperation(V_JITOperation_EJJJ, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID); 770 MacroAssembler::Call callOperation(V_JITOperation_EJJJAp, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, RegisterID, ArrayProfile*); 767 771 MacroAssembler::Call callOperation(V_JITOperation_EJZ, RegisterID, RegisterID, int32_t); 768 772 MacroAssembler::Call callOperation(V_JITOperation_EJZJ, RegisterID, RegisterID, int32_t, RegisterID, RegisterID); -
trunk/Source/JavaScriptCore/jit/JITInlines.h
r184828 r185240 400 400 } 401 401 402 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJAp operation, RegisterID regOp1, RegisterID regOp2, RegisterID regOp3, ArrayProfile* arrayProfile) 403 { 404 setupArgumentsWithExecState(regOp1, regOp2, regOp3, TrustedImmPtr(arrayProfile)); 405 return appendCallWithExceptionCheck(operation); 406 } 407 402 408 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EZJ operation, int dst, GPRReg arg) 403 409 { … … 439 445 { 440 446 setupArgumentsWithExecState(arg1, arg2); 447 return appendCallWithExceptionCheckSetJSValueResult(operation, dst); 448 } 449 450 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJAp operation, int dst, GPRReg arg1, GPRReg arg2, ArrayProfile* arrayProfile) 451 { 452 setupArgumentsWithExecState(arg1, arg2, TrustedImmPtr(arrayProfile)); 441 453 return appendCallWithExceptionCheckSetJSValueResult(operation, dst); 442 454 } … … 571 583 } 572 584 585 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(J_JITOperation_EJJAp operation, int dst, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload, ArrayProfile* arrayProfile) 586 { 587 setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG arg1Payload, arg1Tag, SH4_32BIT_DUMMY_ARG arg2Payload, arg2Tag, TrustedImmPtr(arrayProfile)); 588 return appendCallWithExceptionCheckSetJSValueResult(operation, dst); 589 } 590 573 591 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(JIT::WithProfileTag, J_JITOperation_EJJ operation, int dst, GPRReg arg1Tag, GPRReg arg1Payload, GPRReg arg2Tag, GPRReg arg2Payload) 574 592 { … … 628 646 { 629 647 setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG regOp1Payload, regOp1Tag, SH4_32BIT_DUMMY_ARG regOp2Payload, regOp2Tag, regOp3Payload, regOp3Tag); 648 return appendCallWithExceptionCheck(operation); 649 } 650 651 ALWAYS_INLINE MacroAssembler::Call JIT::callOperation(V_JITOperation_EJJJAp operation, RegisterID regOp1Tag, RegisterID regOp1Payload, RegisterID regOp2Tag, RegisterID regOp2Payload, RegisterID regOp3Tag, RegisterID regOp3Payload, ArrayProfile* arrayProfile) 652 { 653 setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG regOp1Payload, regOp1Tag, SH4_32BIT_DUMMY_ARG regOp2Payload, regOp2Tag, regOp3Payload, regOp3Tag, TrustedImmPtr(arrayProfile)); 630 654 return appendCallWithExceptionCheck(operation); 631 655 } -
trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp
r184328 r185240 1126 1126 linkSlowCaseIfNotJSCell(iter, base); // base cell check 1127 1127 linkSlowCase(iter); // base array check 1128 1129 Jump skipProfiling = jump();1130 1131 1128 linkSlowCase(iter); // vector length check 1132 1129 linkSlowCase(iter); // empty value 1133 1130 1134 emitArrayProfileOutOfBoundsSpecialCase(profile);1135 1136 skipProfiling.link(this);1137 1138 1131 Label slowPath = label(); 1139 1132 1140 1133 emitGetVirtualRegister(base, regT0); 1141 1134 emitGetVirtualRegister(property, regT1); 1142 Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT0, regT1 );1135 Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT0, regT1, profile); 1143 1136 1144 1137 m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath; -
trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
r184328 r185240 1123 1123 linkSlowCaseIfNotJSCell(iter, base); // base cell check 1124 1124 linkSlowCase(iter); // base array check 1125 1126 Jump skipProfiling = jump();1127 1128 1125 linkSlowCase(iter); // vector length check 1129 1126 linkSlowCase(iter); // empty value 1130 1131 emitArrayProfileOutOfBoundsSpecialCase(profile); 1132 1133 skipProfiling.link(this); 1134 1127 1135 1128 Label slowPath = label(); 1136 1129 1137 1130 emitLoad(base, regT1, regT0); 1138 1131 emitLoad(property, regT3, regT2); 1139 Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2 );1132 Call call = callOperation(operationHasIndexedPropertyDefault, dst, regT1, regT0, regT3, regT2, profile); 1140 1133 1141 1134 m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath; -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r185160 r185240 36 36 #include "DFGWorklist.h" 37 37 #include "Debugger.h" 38 #include "DirectArguments.h" 38 39 #include "Error.h" 39 40 #include "ErrorHandlingScope.h" … … 57 58 #include "Repatch.h" 58 59 #include "RepatchBuffer.h" 60 #include "ScopedArguments.h" 59 61 #include "TestRunnerUtils.h" 60 62 #include "TypeProfilerLog.h" … … 498 500 } 499 501 500 static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value )502 static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value, ArrayProfile* arrayProfile) 501 503 { 502 504 VM& vm = callFrame->vm(); … … 507 509 if (object->canSetIndexQuickly(i)) 508 510 object->setIndexQuickly(callFrame->vm(), i, value); 509 else 511 else { 512 arrayProfile->setOutOfBounds(); 510 513 object->methodTable(vm)->putByIndex(object, callFrame, i, value, callFrame->codeBlock()->isStrictMode()); 514 } 511 515 } else 512 516 baseValue.putByIndex(callFrame, i, value, callFrame->codeBlock()->isStrictMode()); … … 520 524 } 521 525 522 static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value )526 static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value, ArrayProfile* arrayProfile) 523 527 { 524 528 bool isStrictMode = callFrame->codeBlock()->isStrictMode(); 525 529 if (LIKELY(subscript.isUInt32())) { 526 530 // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices. 527 ASSERT(isIndex(subscript.asUInt32())); 528 baseObject->putDirectIndex(callFrame, subscript.asUInt32(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); 531 uint32_t index = subscript.asUInt32(); 532 ASSERT(isIndex(index)); 533 if (baseObject->canSetIndexQuicklyForPutDirect(index)) { 534 baseObject->setIndexQuickly(callFrame->vm(), index, value); 535 return; 536 } 537 538 arrayProfile->setOutOfBounds(); 539 baseObject->putDirectIndex(callFrame, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); 529 540 return; 530 541 } … … 551 562 } 552 563 } 553 void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue )564 void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile) 554 565 { 555 566 VM& vm = exec->vm(); … … 570 581 ASSERT(!byValInfo.stubRoutine); 571 582 572 if (hasOptimizableIndexing(object->structure(vm))) { 583 Structure* structure = object->structure(vm); 584 if (hasOptimizableIndexing(structure)) { 573 585 // Attempt to optimize. 574 JITArrayMode arrayMode = jitArrayModeForStructure( object->structure(vm));586 JITArrayMode arrayMode = jitArrayModeForStructure(structure); 575 587 if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) { 588 CodeBlock* codeBlock = exec->codeBlock(); 589 ConcurrentJITLocker locker(codeBlock->m_lock); 590 arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); 591 576 592 JIT::compilePutByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); 577 593 didOptimize = true; … … 593 609 } 594 610 595 putByVal(exec, baseValue, subscript, value );596 } 597 598 void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue )611 putByVal(exec, baseValue, subscript, value, arrayProfile); 612 } 613 614 void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile) 599 615 { 600 616 VM& vm = callFrame->vm(); … … 614 630 ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1); 615 631 ASSERT(!byValInfo.stubRoutine); 616 617 if (hasOptimizableIndexing(object->structure(vm))) { 632 633 Structure* structure = object->structure(vm); 634 if (hasOptimizableIndexing(structure)) { 618 635 // Attempt to optimize. 619 JITArrayMode arrayMode = jitArrayModeForStructure( object->structure(vm));636 JITArrayMode arrayMode = jitArrayModeForStructure(structure); 620 637 if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) { 638 CodeBlock* codeBlock = callFrame->codeBlock(); 639 ConcurrentJITLocker locker(codeBlock->m_lock); 640 arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); 641 621 642 JIT::compileDirectPutByVal(&vm, callFrame->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); 622 643 didOptimize = true; … … 637 658 } 638 659 } 639 directPutByVal(callFrame, object, subscript, value );640 } 641 642 void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue )660 directPutByVal(callFrame, object, subscript, value, arrayProfile); 661 } 662 663 void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile) 643 664 { 644 665 VM& vm = exec->vm(); … … 649 670 JSValue value = JSValue::decode(encodedValue); 650 671 651 putByVal(exec, baseValue, subscript, value );652 } 653 654 655 void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue )672 putByVal(exec, baseValue, subscript, value, arrayProfile); 673 } 674 675 676 void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile) 656 677 { 657 678 VM& vm = exec->vm(); … … 662 683 JSValue value = JSValue::decode(encodedValue); 663 684 RELEASE_ASSERT(baseValue.isObject()); 664 directPutByVal(exec, asObject(baseValue), subscript, value );685 directPutByVal(exec, asObject(baseValue), subscript, value, arrayProfile); 665 686 } 666 687 … … 1481 1502 } 1482 1503 1483 static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ReturnAddressPtr returnAddress) 1504 static bool canAccessArgumentIndexQuickly(JSObject& object, uint32_t index) 1505 { 1506 switch (object.structure()->typeInfo().type()) { 1507 case DirectArgumentsType: { 1508 DirectArguments* directArguments = jsCast<DirectArguments*>(&object); 1509 if (directArguments->canAccessArgumentIndexQuicklyInDFG(index)) 1510 return true; 1511 break; 1512 } 1513 case ScopedArgumentsType: { 1514 ScopedArguments* scopedArguments = jsCast<ScopedArguments*>(&object); 1515 if (scopedArguments->canAccessArgumentIndexQuicklyInDFG(index)) 1516 return true; 1517 break; 1518 } 1519 default: 1520 break; 1521 } 1522 return false; 1523 } 1524 1525 static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ArrayProfile* arrayProfile, ReturnAddressPtr returnAddress) 1484 1526 { 1485 1527 if (LIKELY(baseValue.isCell() && subscript.isString())) { … … 1496 1538 if (subscript.isUInt32()) { 1497 1539 uint32_t i = subscript.asUInt32(); 1498 if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) { 1499 ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString)); 1500 return asString(baseValue)->getIndex(exec, i); 1501 } 1540 if (isJSString(baseValue)) { 1541 if (asString(baseValue)->canGetIndex(i)) { 1542 ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString)); 1543 return asString(baseValue)->getIndex(exec, i); 1544 } 1545 arrayProfile->setOutOfBounds(); 1546 } else if (baseValue.isObject()) { 1547 JSObject* object = asObject(baseValue); 1548 if (object->canGetIndexQuickly(i)) 1549 return object->getIndexQuickly(i); 1550 1551 if (!canAccessArgumentIndexQuickly(*object, i)) 1552 arrayProfile->setOutOfBounds(); 1553 } 1554 1502 1555 return baseValue.get(exec, i); 1503 1556 } … … 1514 1567 extern "C" { 1515 1568 1516 EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript )1569 EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile) 1517 1570 { 1518 1571 VM& vm = exec->vm(); … … 1521 1574 JSValue subscript = JSValue::decode(encodedSubscript); 1522 1575 1523 JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS));1576 JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS)); 1524 1577 return JSValue::encode(result); 1525 1578 } 1526 1579 1527 EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript )1580 EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile) 1528 1581 { 1529 1582 VM& vm = exec->vm(); … … 1544 1597 if (hasOptimizableIndexing(object->structure(vm))) { 1545 1598 // Attempt to optimize. 1546 JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm)); 1599 Structure* structure = object->structure(vm); 1600 JITArrayMode arrayMode = jitArrayModeForStructure(structure); 1547 1601 if (arrayMode != byValInfo.arrayMode) { 1602 // If we reached this case, we got an interesting array mode we did not expect when we compiled. 1603 // Let's update the profile to do better next time. 1604 CodeBlock* codeBlock = exec->codeBlock(); 1605 ConcurrentJITLocker locker(codeBlock->m_lock); 1606 arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); 1607 1548 1608 JIT::compileGetByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode); 1549 1609 didOptimize = true; … … 1565 1625 } 1566 1626 1567 JSValue result = getByVal(exec, baseValue, subscript, ReturnAddressPtr(OUR_RETURN_ADDRESS));1627 JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS)); 1568 1628 return JSValue::encode(result); 1569 1629 } 1570 1630 1571 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript )1631 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile) 1572 1632 { 1573 1633 VM& vm = exec->vm(); … … 1608 1668 } 1609 1669 } 1610 1611 return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32()))); 1612 } 1613 1614 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) 1670 1671 uint32_t index = subscript.asUInt32(); 1672 if (object->canGetIndexQuickly(index)) 1673 return JSValue::encode(JSValue(JSValue::JSTrue)); 1674 1675 if (!canAccessArgumentIndexQuickly(*object, index)) 1676 arrayProfile->setOutOfBounds(); 1677 return JSValue::encode(jsBoolean(object->hasProperty(exec, index))); 1678 } 1679 1680 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile) 1615 1681 { 1616 1682 VM& vm = exec->vm(); … … 1623 1689 1624 1690 JSObject* object = asObject(baseValue); 1691 uint32_t index = subscript.asUInt32(); 1692 if (object->canGetIndexQuickly(index)) 1693 return JSValue::encode(JSValue(JSValue::JSTrue)); 1694 1695 if (!canAccessArgumentIndexQuickly(*object, index)) 1696 arrayProfile->setOutOfBounds(); 1625 1697 return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32()))); 1626 1698 } -
trunk/Source/JavaScriptCore/jit/JITOperations.h
r185160 r185240 58 58 A: JSArray* 59 59 Aap: ArrayAllocationProfile* 60 Ap: ArrayProfile* 60 61 C: JSCell* 61 62 Cb: CodeBlock* … … 112 113 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJIdc)(ExecState*, EncodedJSValue, const Identifier*); 113 114 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJ)(ExecState*, EncodedJSValue, EncodedJSValue); 115 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJJAp)(ExecState*, EncodedJSValue, EncodedJSValue, ArrayProfile*); 114 116 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJssZ)(ExecState*, JSString*, int32_t); 115 117 typedef EncodedJSValue JIT_OPERATION (*J_JITOperation_EJP)(ExecState*, EncodedJSValue, void*); … … 192 194 typedef void JIT_OPERATION (*V_JITOperation_EJIdJJ)(ExecState*, EncodedJSValue, Identifier*, EncodedJSValue, EncodedJSValue); 193 195 typedef void JIT_OPERATION (*V_JITOperation_EJJJ)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue); 196 typedef void JIT_OPERATION (*V_JITOperation_EJJJAp)(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*); 194 197 typedef void JIT_OPERATION (*V_JITOperation_EJPP)(ExecState*, EncodedJSValue, void*, void*); 195 198 typedef void JIT_OPERATION (*V_JITOperation_EJZJ)(ExecState*, EncodedJSValue, int32_t, EncodedJSValue); … … 256 259 void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl*) WTF_INTERNAL; 257 260 void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState*, JSObject*, Structure*, PropertyOffset, EncodedJSValue) WTF_INTERNAL; 258 void JIT_OPERATION operationPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue ) WTF_INTERNAL;259 void JIT_OPERATION operationDirectPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue ) WTF_INTERNAL;260 void JIT_OPERATION operationPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue ) WTF_INTERNAL;261 void JIT_OPERATION operationDirectPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue ) WTF_INTERNAL;261 void JIT_OPERATION operationPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL; 262 void JIT_OPERATION operationDirectPutByVal(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL; 263 void JIT_OPERATION operationPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL; 264 void JIT_OPERATION operationDirectPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL; 262 265 EncodedJSValue JIT_OPERATION operationCallEval(ExecState*, ExecState*) WTF_INTERNAL; 263 266 char* JIT_OPERATION operationLinkCall(ExecState*, CallLinkInfo*) WTF_INTERNAL; … … 316 319 EncodedJSValue JIT_OPERATION operationCheckHasInstance(ExecState*, EncodedJSValue, EncodedJSValue baseVal) WTF_INTERNAL; 317 320 JSCell* JIT_OPERATION operationCreateActivation(ExecState*, JSScope* currentScope) WTF_INTERNAL; 318 EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript ) WTF_INTERNAL;319 EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript ) WTF_INTERNAL;321 EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL; 322 EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL; 320 323 EncodedJSValue JIT_OPERATION operationGetByValString(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript) WTF_INTERNAL; 321 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript ) WTF_INTERNAL;322 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript ) WTF_INTERNAL;324 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL; 325 EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState*, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile*) WTF_INTERNAL; 323 326 EncodedJSValue JIT_OPERATION operationDeleteById(ExecState*, EncodedJSValue base, const Identifier*) WTF_INTERNAL; 324 327 JSCell* JIT_OPERATION operationGetPNames(ExecState*, JSObject*) WTF_INTERNAL; -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
r184324 r185240 218 218 nonCell.link(this); 219 219 220 Jump skipProfiling = jump();221 222 220 linkSlowCase(iter); // vector length check 223 221 linkSlowCase(iter); // empty value 224 222 225 emitArrayProfileOutOfBoundsSpecialCase(profile);226 227 skipProfiling.link(this);228 229 223 Label slowPath = label(); 230 224 231 225 emitGetVirtualRegister(base, regT0); 232 226 emitGetVirtualRegister(property, regT1); 233 Call call = callOperation(operationGetByValDefault, dst, regT0, regT1 );227 Call call = callOperation(operationGetByValDefault, dst, regT0, regT1, profile); 234 228 235 229 m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath; … … 431 425 emitGetVirtualRegister(value, regT2); 432 426 bool isDirect = m_interpreter->getOpcodeID(currentInstruction->u.opcode) == op_put_by_val_direct; 433 Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT0, regT1, regT2 );427 Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT0, regT1, regT2, profile); 434 428 435 429 m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath; -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
r184960 r185240 258 258 notString.link(this); 259 259 nonCell.link(this); 260 261 Jump skipProfiling = jump();262 260 263 261 linkSlowCase(iter); // vector length check 264 262 linkSlowCase(iter); // empty value 265 263 266 emitArrayProfileOutOfBoundsSpecialCase(profile);267 268 skipProfiling.link(this);269 270 264 Label slowPath = label(); 271 265 272 266 emitLoad(base, regT1, regT0); 273 267 emitLoad(property, regT3, regT2); 274 Call call = callOperation(operationGetByValDefault, dst, regT1, regT0, regT3, regT2 );268 Call call = callOperation(operationGetByValDefault, dst, regT1, regT0, regT3, regT2, profile); 275 269 276 270 m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath; … … 465 459 addCallArgument(regT1); 466 460 addCallArgument(regT0); 461 addCallArgument(TrustedImmPtr(profile)); 467 462 Call call = appendCallWithExceptionCheck(isDirect ? operationDirectPutByVal : operationPutByVal); 468 463 #else … … 472 467 emitLoad(property, regT3, regT0); 473 468 emitLoad(value, regT5, regT4); 474 Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT2, regT1, regT3, regT0, regT5, regT4 );469 Call call = callOperation(isDirect ? operationDirectPutByVal : operationPutByVal, regT2, regT1, regT3, regT0, regT5, regT4, profile); 475 470 #endif 476 471 -
trunk/Source/JavaScriptCore/runtime/DirectArguments.h
r181993 r185240 76 76 return i < m_length && (!m_overrides || !m_overrides.get()[i]); 77 77 } 78 78 79 bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const 80 { 81 return i < m_length && !overrodeThings(); 82 } 83 79 84 JSValue getIndexQuickly(uint32_t i) const 80 85 { -
trunk/Source/JavaScriptCore/runtime/JSPromiseFunctions.cpp
r173410 r185240 30 30 31 31 #include "Error.h" 32 #include "JSCJSValueInlines.h" 33 #include "JSCellInlines.h" 32 #include "JSCInlines.h" 34 33 #include "JSPromise.h" 35 34 #include "JSPromiseConstructor.h" -
trunk/Source/JavaScriptCore/runtime/ScopedArguments.h
r181993 r185240 81 81 return !!overflowStorage()[i - namedLength].get(); 82 82 } 83 84 bool canAccessArgumentIndexQuicklyInDFG(uint32_t i) const 85 { 86 return canAccessIndexQuickly(i); 87 } 83 88 84 89 JSValue getIndexQuickly(uint32_t i) const
Note: See TracChangeset
for help on using the changeset viewer.