Changeset 165141 in webkit
- Timestamp:
- Mar 5, 2014, 4:29:17 PM (11 years ago)
- Location:
- trunk
- Files:
-
- 8 added
- 34 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r165138 r165141 1 2014-03-05 Oliver Hunt <[email protected]> 2 3 Support caching of custom setters 4 https://bugs.webkit.org/show_bug.cgi?id=129519 5 6 Reviewed by Filip Pizlo. 7 8 Add test cases. 9 10 * js/regress/assign-custom-setter-expected.txt: Added. 11 * js/regress/assign-custom-setter-polymorphic-expected.txt: Added. 12 * js/regress/assign-custom-setter-polymorphic.html: Added. 13 * js/regress/assign-custom-setter.html: Added. 14 * js/regress/script-tests/assign-custom-setter-polymorphic.js: Added. 15 (test): 16 * js/regress/script-tests/assign-custom-setter.js: Added. 17 (test): 18 1 19 2014-03-05 David Kilzer <[email protected]> 2 20 -
trunk/Source/JavaScriptCore/ChangeLog
r165135 r165141 1 2014-03-03 Oliver Hunt <[email protected]> 2 3 Support caching of custom setters 4 https://bugs.webkit.org/show_bug.cgi?id=129519 5 6 Reviewed by Filip Pizlo. 7 8 This patch adds caching of assignment to properties that 9 are backed by C functions. This provides most of the leg 10 work required to start supporting setters, and resolves 11 the remaining regressions from moving DOM properties up 12 the prototype chain. 13 14 * JavaScriptCore.xcodeproj/project.pbxproj: 15 * bytecode/PolymorphicPutByIdList.cpp: 16 (JSC::PutByIdAccess::visitWeak): 17 (JSC::PolymorphicPutByIdList::PolymorphicPutByIdList): 18 (JSC::PolymorphicPutByIdList::from): 19 * bytecode/PolymorphicPutByIdList.h: 20 (JSC::PutByIdAccess::transition): 21 (JSC::PutByIdAccess::replace): 22 (JSC::PutByIdAccess::customSetter): 23 (JSC::PutByIdAccess::isCustom): 24 (JSC::PutByIdAccess::oldStructure): 25 (JSC::PutByIdAccess::chain): 26 (JSC::PutByIdAccess::stubRoutine): 27 * bytecode/PutByIdStatus.cpp: 28 (JSC::PutByIdStatus::computeForStubInfo): 29 (JSC::PutByIdStatus::computeFor): 30 (JSC::PutByIdStatus::dump): 31 * bytecode/PutByIdStatus.h: 32 (JSC::PutByIdStatus::PutByIdStatus): 33 (JSC::PutByIdStatus::takesSlowPath): 34 (JSC::PutByIdStatus::makesCalls): 35 * bytecode/StructureStubInfo.h: 36 * dfg/DFGAbstractInterpreterInlines.h: 37 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 38 * dfg/DFGByteCodeParser.cpp: 39 (JSC::DFG::ByteCodeParser::emitPutById): 40 (JSC::DFG::ByteCodeParser::handlePutById): 41 * dfg/DFGClobberize.h: 42 (JSC::DFG::clobberize): 43 * dfg/DFGCommon.h: 44 * dfg/DFGConstantFoldingPhase.cpp: 45 (JSC::DFG::ConstantFoldingPhase::foldConstants): 46 * dfg/DFGFixupPhase.cpp: 47 (JSC::DFG::FixupPhase::fixupNode): 48 * dfg/DFGNode.h: 49 (JSC::DFG::Node::hasIdentifier): 50 * dfg/DFGNodeType.h: 51 * dfg/DFGPredictionPropagationPhase.cpp: 52 (JSC::DFG::PredictionPropagationPhase::propagate): 53 * dfg/DFGSafeToExecute.h: 54 (JSC::DFG::safeToExecute): 55 * dfg/DFGSpeculativeJIT.cpp: 56 (JSC::DFG::SpeculativeJIT::compileIn): 57 * dfg/DFGSpeculativeJIT.h: 58 * dfg/DFGSpeculativeJIT32_64.cpp: 59 (JSC::DFG::SpeculativeJIT::cachedGetById): 60 (JSC::DFG::SpeculativeJIT::cachedPutById): 61 (JSC::DFG::SpeculativeJIT::compile): 62 * dfg/DFGSpeculativeJIT64.cpp: 63 (JSC::DFG::SpeculativeJIT::cachedGetById): 64 (JSC::DFG::SpeculativeJIT::cachedPutById): 65 (JSC::DFG::SpeculativeJIT::compile): 66 * jit/CCallHelpers.h: 67 (JSC::CCallHelpers::setupArgumentsWithExecState): 68 * jit/JITInlineCacheGenerator.cpp: 69 (JSC::JITByIdGenerator::JITByIdGenerator): 70 (JSC::JITPutByIdGenerator::JITPutByIdGenerator): 71 * jit/JITInlineCacheGenerator.h: 72 (JSC::JITGetByIdGenerator::JITGetByIdGenerator): 73 * jit/JITOperations.cpp: 74 * jit/JITOperations.h: 75 * jit/JITPropertyAccess.cpp: 76 (JSC::JIT::emit_op_get_by_id): 77 (JSC::JIT::emit_op_put_by_id): 78 * jit/JITPropertyAccess32_64.cpp: 79 (JSC::JIT::emit_op_get_by_id): 80 (JSC::JIT::emit_op_put_by_id): 81 * jit/Repatch.cpp: 82 (JSC::tryCacheGetByID): 83 (JSC::tryBuildGetByIDList): 84 (JSC::emitCustomSetterStub): 85 (JSC::tryCachePutByID): 86 (JSC::tryBuildPutByIdList): 87 * jit/SpillRegistersMode.h: Added. 88 * llint/LLIntSlowPaths.cpp: 89 (JSC::LLInt::LLINT_SLOW_PATH_DECL): 90 * runtime/Lookup.h: 91 (JSC::putEntry): 92 * runtime/PutPropertySlot.h: 93 (JSC::PutPropertySlot::setCacheableCustomProperty): 94 (JSC::PutPropertySlot::customSetter): 95 (JSC::PutPropertySlot::isCacheablePut): 96 (JSC::PutPropertySlot::isCacheableCustomProperty): 97 (JSC::PutPropertySlot::cachedOffset): 98 1 99 2014-03-05 Mark Hahnenberg <[email protected]> 2 100 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r165074 r165141 1163 1163 A78507D617CBC6FD0011F6E7 /* MapData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78507D417CBC6FD0011F6E7 /* MapData.cpp */; }; 1164 1164 A78507D717CBC6FD0011F6E7 /* MapData.h in Headers */ = {isa = PBXBuildFile; fileRef = A78507D517CBC6FD0011F6E7 /* MapData.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1165 A785F6BC18C553FE00F10626 /* SpillRegistersMode.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1165 1166 A78853F917972629001440E4 /* IntendedStructureChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A78853F717972629001440E4 /* IntendedStructureChain.cpp */; }; 1166 1167 A78853FA17972629001440E4 /* IntendedStructureChain.h in Headers */ = {isa = PBXBuildFile; fileRef = A78853F817972629001440E4 /* IntendedStructureChain.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 2802 2803 A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyDescriptor.cpp; sourceTree = "<group>"; }; 2803 2804 A7FCC26C17A0B6AA00786D1A /* FTLSwitchCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLSwitchCase.h; path = ftl/FTLSwitchCase.h; sourceTree = "<group>"; }; 2805 A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SpillRegistersMode.h; sourceTree = "<group>"; }; 2804 2806 A8A4748D151A8306004123FF /* libWTF.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libWTF.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2805 2807 A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallbackObjectFunctions.h; sourceTree = "<group>"; }; … … 3470 3472 A7386553118697B400540279 /* ThunkGenerators.h */, 3471 3473 65987F2F16828A7E003C2F8D /* UnusedPointer.h */, 3474 A7FF647A18C52E8500B55307 /* SpillRegistersMode.h */, 3472 3475 ); 3473 3476 path = jit; … … 5524 5527 BC18C4540E16F5CD00B34460 /* PropertyNameArray.h in Headers */, 5525 5528 0FF7168C15A3B235008F5DAA /* PropertyOffset.h in Headers */, 5529 A785F6BC18C553FE00F10626 /* SpillRegistersMode.h in Headers */, 5526 5530 BC18C4550E16F5CD00B34460 /* PropertySlot.h in Headers */, 5527 5531 0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */, -
trunk/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.cpp
r164971 r165141 78 78 return false; 79 79 break; 80 case CustomSetter: 81 if (!Heap::isMarked(m_oldStructure.get())) 82 return false; 83 if (m_chain && !Heap::isMarked(m_chain.get())) 84 return false; 85 break; 80 86 default: 81 87 RELEASE_ASSERT_NOT_REACHED(); … … 89 95 : m_kind(putKind) 90 96 { 91 m_list.append(PutByIdAccess::fromStructureStubInfo(stubInfo)); 97 if (stubInfo.accessType != access_unset) 98 m_list.append(PutByIdAccess::fromStructureStubInfo(stubInfo)); 92 99 } 93 100 … … 99 106 100 107 ASSERT(stubInfo.accessType == access_put_by_id_replace 101 || stubInfo.accessType == access_put_by_id_transition_normal 102 || stubInfo.accessType == access_put_by_id_transition_direct); 108 || stubInfo.accessType == access_put_by_id_transition_normal 109 || stubInfo.accessType == access_put_by_id_transition_direct 110 || stubInfo.accessType == access_unset); 103 111 104 112 PolymorphicPutByIdList* result = -
trunk/Source/JavaScriptCore/bytecode/PolymorphicPutByIdList.h
r164971 r165141 33 33 #include "Opcode.h" 34 34 #include "PutKind.h" 35 #include "PutPropertySlot.h" 35 36 #include "Structure.h" 36 37 #include <wtf/Vector.h> … … 46 47 Invalid, 47 48 Transition, 48 Replace 49 Replace, 50 CustomSetter 49 51 }; 50 52 … … 67 69 result.m_newStructure.set(vm, owner, newStructure); 68 70 result.m_chain.set(vm, owner, chain); 71 result.m_customSetter = 0; 69 72 result.m_stubRoutine = stubRoutine; 70 73 return result; 71 74 } 72 75 73 76 static PutByIdAccess replace( 74 77 VM& vm, … … 80 83 result.m_type = Replace; 81 84 result.m_oldStructure.set(vm, owner, structure); 85 result.m_customSetter = 0; 82 86 result.m_stubRoutine = stubRoutine; 83 87 return result; 84 88 } 89 90 91 static PutByIdAccess customSetter( 92 VM& vm, 93 JSCell* owner, 94 Structure* structure, 95 StructureChain* chain, 96 PutPropertySlot::PutValueFunc customSetter, 97 PassRefPtr<JITStubRoutine> stubRoutine) 98 { 99 PutByIdAccess result; 100 result.m_oldStructure.set(vm, owner, structure); 101 result.m_type = CustomSetter; 102 if (chain) 103 result.m_chain.set(vm, owner, chain); 104 result.m_customSetter = customSetter; 105 result.m_stubRoutine = stubRoutine; 106 return result; 107 } 85 108 86 109 static PutByIdAccess fromStructureStubInfo(StructureStubInfo&); … … 93 116 bool isTransition() const { return m_type == Transition; } 94 117 bool isReplace() const { return m_type == Replace; } 118 bool isCustom() const { return m_type == CustomSetter; } 95 119 96 120 Structure* oldStructure() const … … 98 122 // Using this instead of isSet() to make this assertion robust against the possibility 99 123 // of additional access types being added. 100 ASSERT(isTransition() || isReplace() );124 ASSERT(isTransition() || isReplace() || isCustom()); 101 125 102 126 return m_oldStructure.get(); … … 117 141 StructureChain* chain() const 118 142 { 119 ASSERT(isTransition() );143 ASSERT(isTransition() || isCustom()); 120 144 return m_chain.get(); 121 145 } … … 123 147 JITStubRoutine* stubRoutine() const 124 148 { 125 ASSERT(isTransition() || isReplace() );149 ASSERT(isTransition() || isReplace() || isCustom()); 126 150 return m_stubRoutine.get(); 127 151 } 128 152 153 PutPropertySlot::PutValueFunc customSetter() const { ASSERT(isCustom()); return m_customSetter; } 154 129 155 bool visitWeak() const; 130 156 … … 136 162 WriteBarrier<Structure> m_newStructure; 137 163 WriteBarrier<StructureChain> m_chain; 164 PutPropertySlot::PutValueFunc m_customSetter; 138 165 RefPtr<JITStubRoutine> m_stubRoutine; 139 166 }; -
trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp
r165129 r165141 206 206 break; 207 207 } 208 case PutByIdAccess::CustomSetter: 209 return PutByIdStatus(MakesCalls); 208 210 209 211 default: … … 266 268 PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue); 267 269 if (isValidOffset(offset)) { 270 if (attributes & CustomAccessor) 271 return PutByIdStatus(MakesCalls); 272 268 273 if (attributes & (Accessor | ReadOnly)) 269 274 return PutByIdStatus(TakesSlowPath); … … 343 348 out.print("(TakesSlowPath)"); 344 349 return; 350 case MakesCalls: 351 out.print("(MakesCalls)"); 352 return; 345 353 } 346 354 -
trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.h
r165129 r165141 48 48 Simple, 49 49 // It's known to often take slow path. 50 TakesSlowPath 50 TakesSlowPath, 51 // It's known to take paths that make calls. 52 MakesCalls 51 53 }; 52 54 … … 59 61 : m_state(state) 60 62 { 61 ASSERT(m_state == NoInformation || m_state == TakesSlowPath );63 ASSERT(m_state == NoInformation || m_state == TakesSlowPath || m_state == MakesCalls); 62 64 } 63 65 … … 78 80 bool operator!() const { return m_state == NoInformation; } 79 81 bool isSimple() const { return m_state == Simple; } 80 bool takesSlowPath() const { return m_state == TakesSlowPath; } 82 bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; } 83 bool makesCalls() const { return m_state == MakesCalls; } 81 84 82 85 size_t numVariants() const { return m_variants.size(); } -
trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h
r164747 r165141 34 34 #include "PolymorphicAccessStructureList.h" 35 35 #include "RegisterSet.h" 36 #include "SpillRegistersMode.h" 36 37 #include "Structure.h" 37 38 #include "StructureStubClearingWatchpoint.h" … … 194 195 195 196 struct { 196 int8_t registersFlushed;197 SpillRegistersMode spillMode : 8; 197 198 int8_t baseGPR; 198 199 #if USE(JSVALUE32_64) -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r165099 r165141 1738 1738 1739 1739 case PutById: 1740 case PutByIdFlush: 1740 1741 case PutByIdDirect: 1741 1742 node->setCanExit(true); -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r164620 r165141 181 181 const GetByIdStatus&); 182 182 void emitPutById( 183 Node* base, unsigned identifierNumber, Node* value, bool isDirect);183 Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&, bool isDirect); 184 184 void handlePutById( 185 185 Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus&, … … 1944 1944 1945 1945 void ByteCodeParser::emitPutById( 1946 Node* base, unsigned identifierNumber, Node* value, bool isDirect)1946 Node* base, unsigned identifierNumber, Node* value, const PutByIdStatus& putByIdStatus, bool isDirect) 1947 1947 { 1948 1948 if (isDirect) 1949 1949 addToGraph(PutByIdDirect, OpInfo(identifierNumber), base, value); 1950 1950 else 1951 addToGraph( PutById, OpInfo(identifierNumber), base, value);1951 addToGraph(putByIdStatus.makesCalls() ? PutByIdFlush : PutById, OpInfo(identifierNumber), base, value); 1952 1952 } 1953 1953 … … 1959 1959 if (!putByIdStatus.isSet()) 1960 1960 addToGraph(ForceOSRExit); 1961 emitPutById(base, identifierNumber, value, isDirect);1961 emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); 1962 1962 return; 1963 1963 } … … 1965 1965 if (putByIdStatus.numVariants() > 1) { 1966 1966 if (!isFTL(m_graph.m_plan.mode)) { 1967 emitPutById(base, identifierNumber, value, isDirect);1967 emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); 1968 1968 return; 1969 1969 } … … 2002 2002 } 2003 2003 2004 ASSERT(variant.kind() == PutByIdVariant::Transition); 2004 if (variant.kind() != PutByIdVariant::Transition) { 2005 emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); 2006 return; 2007 } 2008 2005 2009 if (variant.structureChain() && !variant.structureChain()->isStillValid()) { 2006 emitPutById(base, identifierNumber, value, isDirect);2010 emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); 2007 2011 return; 2008 2012 } -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r164764 r165141 197 197 case GetByIdFlush: 198 198 case PutById: 199 case PutByIdFlush: 199 200 case PutByIdDirect: 200 201 case ArrayPush: -
trunk/Source/JavaScriptCore/dfg/DFGCommon.h
r164424 r165141 96 96 #endif 97 97 } 98 99 enum SpillRegistersMode { NeedToSpill, DontSpill };100 98 101 99 enum NoResultTag { NoResult }; -
trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
r164620 r165141 225 225 226 226 case PutById: 227 case PutByIdFlush: 227 228 case PutByIdDirect: { 228 229 NodeOrigin origin = node->origin; -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r165099 r165141 852 852 853 853 case PutById: 854 case PutByIdFlush: 854 855 case PutByIdDirect: { 855 856 fixEdge<CellUse>(node->child1()); -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r165099 r165141 655 655 case GetByIdFlush: 656 656 case PutById: 657 case PutByIdFlush: 657 658 case PutByIdDirect: 658 659 return true; -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r164620 r165141 147 147 macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ 148 148 macro(PutById, NodeMustGenerate | NodeClobbersWorld) \ 149 macro(PutByIdFlush, NodeMustGenerate | NodeMustGenerate | NodeClobbersWorld) \ 149 150 macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \ 150 151 macro(CheckStructure, NodeMustGenerate) \ -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r164620 r165141 551 551 case Throw: 552 552 case PutById: 553 case PutByIdFlush: 553 554 case PutByIdDirect: 554 555 case PutByOffset: -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r165099 r165141 156 156 case GetByIdFlush: 157 157 case PutById: 158 case PutByIdFlush: 158 159 case PutByIdDirect: 159 160 case CheckStructure: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r165135 r165141 881 881 stubInfo->patch.valueGPR = static_cast<int8_t>(resultGPR); 882 882 stubInfo->patch.usedRegisters = usedRegisters(); 883 stubInfo->patch. registersFlushed = false;883 stubInfo->patch.spillMode = NeedToSpill; 884 884 885 885 m_jit.addIn(InRecord(jump, done, slowPath.get(), stubInfo)); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r165135 r165141 718 718 #if USE(JSVALUE64) 719 719 void cachedGetById(CodeOrigin, GPRReg baseGPR, GPRReg resultGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill); 720 void cachedPutById(CodeOrigin, GPRReg base, GPRReg value, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump() );720 void cachedPutById(CodeOrigin, GPRReg base, GPRReg value, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill); 721 721 #elif USE(JSVALUE32_64) 722 722 void cachedGetById(CodeOrigin, GPRReg baseTagGPROrNone, GPRReg basePayloadGPR, GPRReg resultTagGPR, GPRReg resultPayloadGPR, unsigned identifierNumber, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill); 723 void cachedPutById(CodeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump() );723 void cachedPutById(CodeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind, JITCompiler::Jump slowPathTarget = JITCompiler::Jump(), SpillRegistersMode = NeedToSpill); 724 724 #endif 725 725 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r165135 r165141 175 175 m_jit.codeBlock(), codeOrigin, usedRegisters(), 176 176 JSValueRegs(baseTagGPROrNone, basePayloadGPR), 177 JSValueRegs(resultTagGPR, resultPayloadGPR), spillMode != NeedToSpill);177 JSValueRegs(resultTagGPR, resultPayloadGPR), spillMode); 178 178 179 179 gen.generateFastPath(m_jit); … … 202 202 } 203 203 204 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget )204 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg basePayloadGPR, GPRReg valueTagGPR, GPRReg valuePayloadGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode) 205 205 { 206 206 JITPutByIdGenerator gen( 207 207 m_jit.codeBlock(), codeOrigin, usedRegisters(), 208 208 JSValueRegs::payloadOnly(basePayloadGPR), JSValueRegs(valueTagGPR, valuePayloadGPR), 209 scratchGPR, false, m_jit.ecmaModeFor(codeOrigin), putKind);209 scratchGPR, spillMode, m_jit.ecmaModeFor(codeOrigin), putKind); 210 210 211 211 gen.generateFastPath(m_jit); … … 3919 3919 break; 3920 3920 } 3921 3922 case PutByIdFlush: { 3923 SpeculateCellOperand base(this, node->child1()); 3924 JSValueOperand value(this, node->child2()); 3925 GPRTemporary scratch(this); 3926 3927 GPRReg baseGPR = base.gpr(); 3928 GPRReg valueTagGPR = value.tagGPR(); 3929 GPRReg valuePayloadGPR = value.payloadGPR(); 3930 GPRReg scratchGPR = scratch.gpr(); 3931 flushRegisters(); 3932 3933 cachedPutById(node->origin.semantic, baseGPR, valueTagGPR, valuePayloadGPR, scratchGPR, node->identifierNumber(), NotDirect, MacroAssembler::Jump(), DontSpill); 3934 3935 noResult(node); 3936 break; 3937 } 3921 3938 3922 3939 case PutById: { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r165135 r165141 38 38 #include "JSCInlines.h" 39 39 #include "ObjectPrototype.h" 40 #include "SpillRegistersMode.h" 40 41 41 42 namespace JSC { namespace DFG { … … 192 193 JITGetByIdGenerator gen( 193 194 m_jit.codeBlock(), codeOrigin, usedRegisters(), JSValueRegs(baseGPR), 194 JSValueRegs(resultGPR), spillMode != NeedToSpill);195 JSValueRegs(resultGPR), spillMode); 195 196 gen.generateFastPath(m_jit); 196 197 … … 208 209 } 209 210 210 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget )211 void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget, SpillRegistersMode spillMode) 211 212 { 212 213 JITPutByIdGenerator gen( 213 214 m_jit.codeBlock(), codeOrigin, usedRegisters(), JSValueRegs(baseGPR), 214 JSValueRegs(valueGPR), scratchGPR, false, m_jit.ecmaModeFor(codeOrigin), putKind); 215 JSValueRegs(valueGPR), scratchGPR, spillMode, m_jit.ecmaModeFor(codeOrigin), putKind); 216 215 217 gen.generateFastPath(m_jit); 216 218 … … 4249 4251 break; 4250 4252 } 4253 4254 case PutByIdFlush: { 4255 SpeculateCellOperand base(this, node->child1()); 4256 JSValueOperand value(this, node->child2()); 4257 GPRTemporary scratch(this); 4258 4259 GPRReg baseGPR = base.gpr(); 4260 GPRReg valueGPR = value.gpr(); 4261 GPRReg scratchGPR = scratch.gpr(); 4262 flushRegisters(); 4263 4264 cachedPutById(node->origin.semantic, baseGPR, valueGPR, scratchGPR, node->identifierNumber(), NotDirect, MacroAssembler::Jump(), DontSpill); 4265 4266 noResult(node); 4267 break; 4268 } 4251 4269 4252 4270 case PutById: { -
trunk/Source/JavaScriptCore/jit/CCallHelpers.h
r164631 r165141 372 372 addCallArgument(arg3); 373 373 addCallArgument(arg4); 374 } 375 376 ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImmPtr arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5) 377 { 378 resetCallArguments(); 379 addCallArgument(GPRInfo::callFrameRegister); 380 addCallArgument(arg1); 381 addCallArgument(arg2); 382 addCallArgument(arg3); 383 addCallArgument(arg4); 384 addCallArgument(arg5); 374 385 } 375 386 -
trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp
r164764 r165141 50 50 JITByIdGenerator::JITByIdGenerator( 51 51 CodeBlock* codeBlock, CodeOrigin codeOrigin, const RegisterSet& usedRegisters, 52 JSValueRegs base, JSValueRegs value, bool registersFlushed)52 JSValueRegs base, JSValueRegs value, SpillRegistersMode spillMode) 53 53 : JITInlineCacheGenerator(codeBlock, codeOrigin) 54 54 , m_base(base) 55 55 , m_value(value) 56 56 { 57 m_stubInfo->patch. registersFlushed = registersFlushed;57 m_stubInfo->patch.spillMode = spillMode; 58 58 m_stubInfo->patch.usedRegisters = usedRegisters; 59 59 … … 130 130 JITPutByIdGenerator::JITPutByIdGenerator( 131 131 CodeBlock* codeBlock, CodeOrigin codeOrigin, const RegisterSet& usedRegisters, 132 JSValueRegs base, JSValueRegs value, GPRReg scratch, bool registersFlushed,132 JSValueRegs base, JSValueRegs value, GPRReg scratch, SpillRegistersMode spillMode, 133 133 ECMAMode ecmaMode, PutKind putKind) 134 : JITByIdGenerator(codeBlock, codeOrigin, usedRegisters, base, value, registersFlushed)134 : JITByIdGenerator(codeBlock, codeOrigin, usedRegisters, base, value, spillMode) 135 135 , m_scratch(scratch) 136 136 , m_ecmaMode(ecmaMode) -
trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h
r164764 r165141 58 58 JITByIdGenerator( 59 59 CodeBlock*, CodeOrigin, const RegisterSet&, JSValueRegs base, JSValueRegs value, 60 bool registersFlushed);60 SpillRegistersMode spillMode); 61 61 62 62 public: … … 96 96 97 97 JITGetByIdGenerator( 98 99 JSValueRegs base, JSValueRegs value, bool registersFlushed)100 : JITByIdGenerator(codeBlock, codeOrigin, usedRegisters, base, value, registersFlushed)98 CodeBlock* codeBlock, CodeOrigin codeOrigin, const RegisterSet& usedRegisters, 99 JSValueRegs base, JSValueRegs value, SpillRegistersMode spillMode) 100 : JITByIdGenerator(codeBlock, codeOrigin, usedRegisters, base, value, spillMode) 101 101 { 102 102 } … … 111 111 JITPutByIdGenerator( 112 112 CodeBlock*, CodeOrigin, const RegisterSet& usedRegisters, JSValueRegs base, 113 JSValueRegs value, GPRReg scratch, bool registersFlushed, ECMAMode, PutKind);113 JSValueRegs, GPRReg scratch, SpillRegistersMode spillMode, ECMAMode, PutKind); 114 114 115 115 void generateFastPath(MacroAssembler&); -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r165005 r165141 1731 1731 // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. 1732 1732 if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) { 1733 if (slot.isCacheable () && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) {1733 if (slot.isCacheablePut() && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) { 1734 1734 ConcurrentJITLocker locker(codeBlock->m_lock); 1735 1735 pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure()); -
trunk/Source/JavaScriptCore/jit/JITOperations.h
r164630 r165141 36 36 #include "MacroAssembler.h" 37 37 #include "PutKind.h" 38 #include "SpillRegistersMode.h" 38 39 #include "StructureStubInfo.h" 39 40 #include "VariableWatchpointSet.h" 41 40 42 41 43 namespace JSC { -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
r165135 r165141 522 522 JITGetByIdGenerator gen( 523 523 m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(), 524 JSValueRegs(regT0), JSValueRegs(regT0), true);524 JSValueRegs(regT0), JSValueRegs(regT0), DontSpill); 525 525 gen.generateFastPath(*this); 526 526 addSlowCase(gen.slowPathJump()); … … 568 568 JITPutByIdGenerator gen( 569 569 m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(), 570 JSValueRegs(regT0), JSValueRegs(regT1), regT2, true, m_codeBlock->ecmaMode(),570 JSValueRegs(regT0), JSValueRegs(regT1), regT2, DontSpill, m_codeBlock->ecmaMode(), 571 571 direct ? Direct : NotDirect); 572 572 -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
r164764 r165141 479 479 JITGetByIdGenerator gen( 480 480 m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(), 481 JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), true);481 JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), DontSpill); 482 482 gen.generateFastPath(*this); 483 483 addSlowCase(gen.slowPathJump()); … … 528 528 m_codeBlock, CodeOrigin(m_bytecodeOffset), RegisterSet::specialRegisters(), 529 529 JSValueRegs::payloadOnly(regT0), JSValueRegs(regT3, regT2), 530 regT1, true, m_codeBlock->ecmaMode(), direct ? Direct : NotDirect);530 regT1, DontSpill, m_codeBlock->ecmaMode(), direct ? Direct : NotDirect); 531 531 532 532 gen.generateFastPath(*this); -
trunk/Source/JavaScriptCore/jit/Repatch.cpp
r165135 r165141 450 450 return false; 451 451 452 if ( !stubInfo.patch.registersFlushed) {452 if (stubInfo.patch.spillMode == NeedToSpill) { 453 453 // We cannot do as much inline caching if the registers were not flushed prior to this GetById. In particular, 454 454 // non-Value cached properties require planting calls, which requires registers to have been flushed. Thus, … … 552 552 553 553 if (slot.slotBase() == baseValue) { 554 if ( !stubInfo.patch.registersFlushed) {554 if (stubInfo.patch.spillMode == NeedToSpill) { 555 555 // We cannot do as much inline caching if the registers were not flushed prior to this GetById. In particular, 556 556 // non-Value cached properties require planting calls, which requires registers to have been flushed. Thus, … … 703 703 return false; 704 704 705 if ( !stubInfo.patch.registersFlushed) {705 if (stubInfo.patch.spillMode == NeedToSpill) { 706 706 // We cannot do as much inline caching if the registers were not flushed prior to this GetById. In particular, 707 707 // non-Value cached properties require planting calls, which requires registers to have been flushed. Thus, … … 1130 1130 } 1131 1131 1132 static void emitCustomSetterStub(ExecState* exec, const PutPropertySlot& slot, 1133 StructureStubInfo& stubInfo, Structure* structure, StructureChain* prototypeChain, 1134 CodeLocationLabel failureLabel, RefPtr<JITStubRoutine>& stubRoutine) 1135 { 1136 VM* vm = &exec->vm(); 1137 ASSERT(stubInfo.patch.spillMode == DontSpill); 1138 GPRReg baseGPR = static_cast<GPRReg>(stubInfo.patch.baseGPR); 1139 #if USE(JSVALUE32_64) 1140 GPRReg valueTagGPR = static_cast<GPRReg>(stubInfo.patch.valueTagGPR); 1141 #endif 1142 GPRReg valueGPR = static_cast<GPRReg>(stubInfo.patch.valueGPR); 1143 TempRegisterSet tempRegisters(stubInfo.patch.usedRegisters); 1144 1145 CCallHelpers stubJit(vm); 1146 GPRReg scratchGPR = tempRegisters.getFreeGPR(); 1147 RELEASE_ASSERT(scratchGPR != InvalidGPRReg); 1148 RELEASE_ASSERT(scratchGPR != baseGPR); 1149 RELEASE_ASSERT(scratchGPR != valueGPR); 1150 MacroAssembler::JumpList failureCases; 1151 failureCases.append(branchStructure(stubJit, 1152 MacroAssembler::NotEqual, 1153 MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()), 1154 structure)); 1155 1156 if (prototypeChain) { 1157 for (WriteBarrier<Structure>* it = prototypeChain->head(); *it; ++it) 1158 addStructureTransitionCheck((*it)->storedPrototype(), exec->codeBlock(), stubInfo, stubJit, failureCases, scratchGPR); 1159 } 1160 1161 // typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value); 1162 #if USE(JSVALUE64) 1163 stubJit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(slot.base()), baseGPR, valueGPR); 1164 #else 1165 stubJit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(slot.base()), baseGPR, MacroAssembler::TrustedImm32(JSValue::CellTag), valueGPR, valueTagGPR); 1166 #endif 1167 1168 // Need to make sure that whenever this call is made in the future, we remember the 1169 // place that we made it from. It just so happens to be the place that we are at 1170 // right now! 1171 stubJit.store32(MacroAssembler::TrustedImm32(exec->locationAsRawBits()), 1172 CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount))); 1173 stubJit.storePtr(GPRInfo::callFrameRegister, &vm->topCallFrame); 1174 1175 MacroAssembler::Call setterCall = stubJit.call(); 1176 1177 MacroAssembler::Jump success = stubJit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck); 1178 1179 stubJit.setupArguments(CCallHelpers::TrustedImmPtr(vm), GPRInfo::callFrameRegister); 1180 1181 MacroAssembler::Call handlerCall = stubJit.call(); 1182 1183 stubJit.jumpToExceptionHandler(); 1184 LinkBuffer patchBuffer(*vm, &stubJit, exec->codeBlock()); 1185 1186 patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone)); 1187 patchBuffer.link(failureCases, failureLabel); 1188 patchBuffer.link(setterCall, FunctionPtr(slot.customSetter())); 1189 patchBuffer.link(handlerCall, lookupExceptionHandler); 1190 1191 stubRoutine = createJITStubRoutine( 1192 FINALIZE_CODE_FOR(exec->codeBlock(), patchBuffer, ("PutById custom setter stub for %s, return point %p", 1193 toCString(*exec->codeBlock()).data(), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone).executableAddress())), *vm, exec->codeBlock()->ownerExecutable(), structure); 1194 } 1195 1196 1132 1197 static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier& ident, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind) 1133 1198 { … … 1141 1206 Structure* oldStructure = structure->previousID(); 1142 1207 1143 if (!slot.isCacheable ())1208 if (!slot.isCacheablePut() && !slot.isCacheableCustomProperty()) 1144 1209 return false; 1145 1210 if (!structure->propertyAccessesAreCacheable()) … … 1147 1212 1148 1213 // Optimize self access. 1149 if (slot.base() == baseValue ) {1214 if (slot.base() == baseValue && slot.isCacheablePut()) { 1150 1215 if (slot.type() == PutPropertySlot::NewProperty) { 1151 1216 if (structure->isDictionary()) … … 1194 1259 return true; 1195 1260 } 1261 if (slot.isCacheableCustomProperty() && stubInfo.patch.spillMode == DontSpill) { 1262 RefPtr<JITStubRoutine> stubRoutine; 1263 1264 StructureChain* prototypeChain = 0; 1265 if (baseValue != slot.base()) { 1266 PropertyOffset offsetIgnored; 1267 if (normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), ident, offsetIgnored) == InvalidPrototypeChain) 1268 return false; 1269 1270 prototypeChain = structure->prototypeChain(exec); 1271 } 1272 PolymorphicPutByIdList* list; 1273 list = PolymorphicPutByIdList::from(putKind, stubInfo); 1274 1275 emitCustomSetterStub(exec, slot, stubInfo, 1276 structure, prototypeChain, 1277 stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase), 1278 stubRoutine); 1279 1280 list->addAccess(PutByIdAccess::customSetter(*vm, codeBlock->ownerExecutable(), structure, prototypeChain, slot.customSetter(), stubRoutine)); 1281 1282 RepatchBuffer repatchBuffer(codeBlock); 1283 repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump), CodeLocationLabel(stubRoutine->code().code())); 1284 repatchCall(repatchBuffer, stubInfo.callReturnLocation, appropriateListBuildingPutByIdFunction(slot, putKind)); 1285 RELEASE_ASSERT(!list->isFull()); 1286 return true; 1287 } 1196 1288 1197 1289 return false; … … 1218 1310 Structure* oldStructure = structure->previousID(); 1219 1311 1220 if (!slot.isCacheable()) 1221 return false; 1312 1313 if (!slot.isCacheablePut() && !slot.isCacheableCustomProperty()) 1314 return false; 1315 1222 1316 if (!structure->propertyAccessesAreCacheable()) 1223 1317 return false; 1224 1318 1225 1319 // Optimize self access. 1226 if (slot.base() == baseValue ) {1320 if (slot.base() == baseValue && slot.isCacheablePut()) { 1227 1321 PolymorphicPutByIdList* list; 1228 1322 RefPtr<JITStubRoutine> stubRoutine; … … 1286 1380 } 1287 1381 1382 if (slot.isCacheableCustomProperty() && stubInfo.patch.spillMode == DontSpill) { 1383 RefPtr<JITStubRoutine> stubRoutine; 1384 StructureChain* prototypeChain = 0; 1385 if (baseValue != slot.base()) { 1386 PropertyOffset offsetIgnored; 1387 if (normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), propertyName, offsetIgnored) == InvalidPrototypeChain) 1388 return false; 1389 1390 prototypeChain = structure->prototypeChain(exec); 1391 } 1392 PolymorphicPutByIdList* list; 1393 list = PolymorphicPutByIdList::from(putKind, stubInfo); 1394 1395 emitCustomSetterStub(exec, slot, stubInfo, 1396 structure, prototypeChain, 1397 CodeLocationLabel(list->currentSlowPathTarget()), 1398 stubRoutine); 1399 1400 list->addAccess(PutByIdAccess::customSetter(*vm, codeBlock->ownerExecutable(), structure, prototypeChain, slot.customSetter(), stubRoutine)); 1401 1402 RepatchBuffer repatchBuffer(codeBlock); 1403 repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump), CodeLocationLabel(stubRoutine->code().code())); 1404 if (list->isFull()) 1405 repatchCall(repatchBuffer, stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind)); 1406 1407 return true; 1408 } 1288 1409 return false; 1289 1410 } -
trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
r164630 r165141 629 629 if (!LLINT_ALWAYS_ACCESS_SLOW 630 630 && baseValue.isCell() 631 && slot.isCacheable ()) {631 && slot.isCacheablePut()) { 632 632 633 633 JSCell* baseCell = baseValue.asCell(); … … 1411 1411 // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. 1412 1412 if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) { 1413 if (slot.isCacheable () && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) {1413 if (slot.isCacheablePut() && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) { 1414 1414 ConcurrentJITLocker locker(codeBlock->m_lock); 1415 1415 pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure()); -
trunk/Source/JavaScriptCore/runtime/Lookup.h
r163960 r165141 307 307 } else if (!(entry->attributes() & ReadOnly)) { 308 308 entry->propertyPutter()(exec, base, JSValue::encode(slot.thisValue()), JSValue::encode(value)); 309 slot.setC ustomProperty(base, entry->propertyPutter());309 slot.setCacheableCustomProperty(base, entry->propertyPutter()); 310 310 } else if (slot.isStrictMode()) 311 311 throwTypeError(exec, StrictModeReadonlyPropertyWriteError); -
trunk/Source/JavaScriptCore/runtime/PutPropertySlot.h
r162741 r165141 39 39 class PutPropertySlot { 40 40 public: 41 enum Type { Uncachable, ExistingProperty, NewProperty, CustomProperty };41 enum Type { Uncachable, ExistingProperty, NewProperty, CustomProperty, CacheableCustomProperty }; 42 42 enum Context { UnknownContext, PutById, PutByIdEval }; 43 43 typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value); … … 73 73 m_putFunction = function; 74 74 } 75 75 76 void setCacheableCustomProperty(JSObject* base, PutValueFunc function) 77 { 78 m_type = CacheableCustomProperty; 79 m_base = base; 80 m_putFunction = function; 81 } 82 PutValueFunc customSetter() const { return m_putFunction; } 83 76 84 Context context() const { return static_cast<Context>(m_context); } 77 85 … … 81 89 82 90 bool isStrictMode() const { return m_isStrictMode; } 83 bool isCacheable() const { return m_type != Uncachable && m_type != CustomProperty; } 91 bool isCacheablePut() const { return m_type == NewProperty || m_type == ExistingProperty; } 92 bool isCacheableCustomProperty() const { return m_type == CacheableCustomProperty; } 93 84 94 PropertyOffset cachedOffset() const 85 95 { 86 ASSERT(isCacheable ());96 ASSERT(isCacheablePut()); 87 97 return m_offset; 88 98 } -
trunk/Source/WebCore/ChangeLog
r165138 r165141 1 2014-03-05 Oliver Hunt <[email protected]> 2 3 Support caching of custom setters 4 https://bugs.webkit.org/show_bug.cgi?id=129519 5 6 Reviewed by Filip Pizlo. 7 8 Add forwarding header 9 10 Tests: js/regress/assign-custom-setter-polymorphic.html 11 js/regress/assign-custom-setter.html 12 13 * ForwardingHeaders/jit/SpillRegistersMode.h: Added. 14 1 15 2014-03-05 David Kilzer <[email protected]> 2 16
Note:
See TracChangeset
for help on using the changeset viewer.