2 * Copyright (C) 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGRepatch.h"
31 #include "DFGJITCodeGenerator.h"
32 #include "LinkBuffer.h"
33 #include "Operations.h"
34 #include "RepatchBuffer.h"
36 namespace JSC { namespace DFG {
38 static void dfgRepatchCall(CodeBlock* codeblock, CodeLocationCall call, FunctionPtr newCalleeFunction)
40 RepatchBuffer repatchBuffer(codeblock);
41 repatchBuffer.relink(call, newCalleeFunction);
44 static void dfgRepatchByIdSelfAccess(CodeBlock* codeBlock, StructureStubInfo& stubInfo, Structure* structure, size_t offset, const FunctionPtr &slowPathFunction, bool compact)
46 RepatchBuffer repatchBuffer(codeBlock);
48 // Only optimize once!
49 repatchBuffer.relink(stubInfo.callReturnLocation, slowPathFunction);
51 // Patch the structure check & the offset of the load.
52 repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelPtrAtOffset(-(intptr_t)stubInfo.u.unset.deltaCheckImmToCall), structure);
54 repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabelCompactAtOffset(stubInfo.u.unset.deltaCallToLoadOrStore), sizeof(JSValue) * offset);
56 repatchBuffer.repatch(stubInfo.callReturnLocation.dataLabel32AtOffset(stubInfo.u.unset.deltaCallToLoadOrStore), sizeof(JSValue) * offset);
59 static void emitRestoreScratch(MacroAssembler& stubJit, bool needToRestoreScratch, GPRReg scratchGPR, MacroAssembler::Jump& success, MacroAssembler::Jump& fail, MacroAssembler::JumpList failureCases)
61 if (needToRestoreScratch) {
62 stubJit.pop(scratchGPR);
64 success = stubJit.jump();
66 // link failure cases here, so we can pop scratchGPR, and then jump back.
67 failureCases.link(&stubJit);
69 stubJit.pop(scratchGPR);
71 fail = stubJit.jump();
75 success = stubJit.jump();
78 static void linkRestoreScratch(LinkBuffer& patchBuffer, bool needToRestoreScratch, MacroAssembler::Jump success, MacroAssembler::Jump fail, MacroAssembler::JumpList failureCases, CodeLocationLabel successLabel, CodeLocationLabel slowCaseBegin)
80 patchBuffer.link(success, successLabel);
82 if (needToRestoreScratch) {
83 patchBuffer.link(fail, slowCaseBegin);
87 // link failure cases directly back to normal path
88 patchBuffer.link(failureCases, slowCaseBegin);
91 static void linkRestoreScratch(LinkBuffer& patchBuffer, bool needToRestoreScratch, StructureStubInfo& stubInfo, MacroAssembler::Jump success, MacroAssembler::Jump fail, MacroAssembler::JumpList failureCases)
93 linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase));
96 static void generateProtoChainAccessStub(ExecState* exec, StructureStubInfo& stubInfo, StructureChain* chain, size_t count, size_t offset, Structure* structure, CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel, MacroAssemblerCodeRef& stubRoutine)
98 JSGlobalData* globalData = &exec->globalData();
100 MacroAssembler stubJit;
102 GPRReg baseGPR = static_cast<GPRReg>(stubInfo.baseGPR);
103 GPRReg resultGPR = static_cast<GPRReg>(stubInfo.valueGPR);
104 GPRReg scratchGPR = static_cast<GPRReg>(stubInfo.scratchGPR);
105 bool needToRestoreScratch = false;
107 if (scratchGPR == InvalidGPRReg) {
108 scratchGPR = JITCodeGenerator::selectScratchGPR(baseGPR, resultGPR);
109 stubJit.push(scratchGPR);
110 needToRestoreScratch = true;
113 MacroAssembler::JumpList failureCases;
115 failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(structure)));
117 Structure* currStructure = structure;
118 WriteBarrier<Structure>* it = chain->head();
119 JSObject* protoObject = 0;
120 for (unsigned i = 0; i < count; ++i, ++it) {
121 protoObject = asObject(currStructure->prototypeForLookup(exec));
122 stubJit.move(MacroAssembler::TrustedImmPtr(protoObject), scratchGPR);
123 failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(scratchGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(protoObject->structure())));
124 currStructure = it->get();
127 if (protoObject->structure()->isUsingInlineStorage())
128 stubJit.loadPtr(MacroAssembler::Address(scratchGPR, JSObject::offsetOfInlineStorage() + offset * sizeof(JSValue)), resultGPR);
130 stubJit.loadPtr(protoObject->addressOfPropertyAtOffset(offset), resultGPR);
132 MacroAssembler::Jump success, fail;
134 emitRestoreScratch(stubJit, needToRestoreScratch, scratchGPR, success, fail, failureCases);
136 LinkBuffer patchBuffer(*globalData, &stubJit);
138 linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel);
140 stubRoutine = patchBuffer.finalizeCode();
143 static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
145 // FIXME: Write a test that proves we need to check for recursion here just
146 // like the interpreter does, then add a check for recursion.
148 CodeBlock* codeBlock = exec->codeBlock();
149 JSGlobalData* globalData = &exec->globalData();
151 if (isJSArray(globalData, baseValue) && propertyName == exec->propertyNames().length) {
152 GPRReg baseGPR = static_cast<GPRReg>(stubInfo.baseGPR);
153 GPRReg resultGPR = static_cast<GPRReg>(stubInfo.valueGPR);
154 GPRReg scratchGPR = static_cast<GPRReg>(stubInfo.scratchGPR);
155 bool needToRestoreScratch = false;
157 MacroAssembler stubJit;
159 if (scratchGPR == InvalidGPRReg) {
160 scratchGPR = JITCodeGenerator::selectScratchGPR(baseGPR, resultGPR);
161 stubJit.push(scratchGPR);
162 needToRestoreScratch = true;
165 MacroAssembler::JumpList failureCases;
167 failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(globalData->jsArrayVPtr)));
169 stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), scratchGPR);
170 stubJit.load32(MacroAssembler::Address(scratchGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), scratchGPR);
171 failureCases.append(stubJit.branch32(MacroAssembler::LessThan, scratchGPR, MacroAssembler::TrustedImm32(0)));
173 stubJit.orPtr(GPRInfo::tagTypeNumberRegister, scratchGPR, resultGPR);
175 MacroAssembler::Jump success, fail;
177 emitRestoreScratch(stubJit, needToRestoreScratch, scratchGPR, success, fail, failureCases);
179 LinkBuffer patchBuffer(*globalData, &stubJit);
181 linkRestoreScratch(patchBuffer, needToRestoreScratch, stubInfo, success, fail, failureCases);
183 stubInfo.stubRoutine = patchBuffer.finalizeCode();
185 RepatchBuffer repatchBuffer(codeBlock);
186 repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code()));
187 repatchBuffer.relink(stubInfo.callReturnLocation, operationGetById);
192 // FIXME: should support length access for String.
194 // FIXME: Cache property access for immediates.
195 if (!baseValue.isCell())
197 JSCell* baseCell = baseValue.asCell();
198 Structure* structure = baseCell->structure();
199 if (!slot.isCacheable())
201 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching())
204 // Optimize self access.
205 if (slot.slotBase() == baseValue) {
206 if ((slot.cachedPropertyType() != PropertySlot::Value) || ((slot.cachedOffset() * sizeof(JSValue)) > (unsigned)MacroAssembler::MaximumCompactPtrAlignedAddressOffset))
209 dfgRepatchByIdSelfAccess(codeBlock, stubInfo, structure, slot.cachedOffset(), operationGetByIdBuildList, true);
210 stubInfo.initGetByIdSelf(*globalData, codeBlock->ownerExecutable(), structure);
214 if (structure->isDictionary())
217 // FIXME: optimize getters and setters
218 if (slot.cachedPropertyType() != PropertySlot::Value)
221 size_t offset = slot.cachedOffset();
222 size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset);
226 StructureChain* prototypeChain = structure->prototypeChain(exec);
228 ASSERT(slot.slotBase().isObject());
230 generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase), stubInfo.stubRoutine);
232 RepatchBuffer repatchBuffer(codeBlock);
233 repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code()));
234 repatchBuffer.relink(stubInfo.callReturnLocation, operationGetByIdProtoBuildList);
236 stubInfo.initGetByIdChain(*globalData, codeBlock->ownerExecutable(), structure, prototypeChain);
240 void dfgRepatchGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
242 bool cached = tryCacheGetByID(exec, baseValue, propertyName, slot, stubInfo);
244 dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationGetById);
247 static void dfgRepatchGetMethodFast(JSGlobalData* globalData, CodeBlock* codeBlock, MethodCallLinkInfo& methodInfo, JSObject* callee, Structure* structure, JSObject* slotBaseObject)
249 ScriptExecutable* owner = codeBlock->ownerExecutable();
251 RepatchBuffer repatchBuffer(codeBlock);
253 // Only optimize once!
254 repatchBuffer.relink(methodInfo.callReturnLocation, operationGetByIdOptimize);
256 methodInfo.cachedStructure.set(*globalData, owner, structure);
257 methodInfo.cachedPrototypeStructure.set(*globalData, owner, slotBaseObject->structure());
258 methodInfo.cachedPrototype.set(*globalData, owner, slotBaseObject);
259 methodInfo.cachedFunction.set(*globalData, owner, callee);
262 static bool tryCacheGetMethod(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, MethodCallLinkInfo& methodInfo)
264 CodeBlock* codeBlock = exec->codeBlock();
265 JSGlobalData* globalData = &exec->globalData();
267 Structure* structure;
269 JSObject* slotBaseObject;
270 if (baseValue.isCell()
271 && slot.isCacheableValue()
272 && !(structure = baseValue.asCell()->structure())->isUncacheableDictionary()
273 && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(exec, propertyName, specific)
276 JSObject* callee = asObject(specific);
278 // Since we're accessing a prototype in a loop, it's a good bet that it
279 // should not be treated as a dictionary.
280 if (slotBaseObject->structure()->isDictionary())
281 slotBaseObject->flattenDictionaryObject(exec->globalData());
283 if (slot.slotBase() == structure->prototypeForLookup(exec)) {
284 dfgRepatchGetMethodFast(globalData, codeBlock, methodInfo, callee, structure, slotBaseObject);
288 if (slot.slotBase() == baseValue) {
289 dfgRepatchGetMethodFast(globalData, codeBlock, methodInfo, callee, structure, exec->scopeChain()->globalObject->methodCallDummy());
297 void dfgRepatchGetMethod(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, MethodCallLinkInfo& methodInfo)
299 bool cached = tryCacheGetMethod(exec, baseValue, propertyName, slot, methodInfo);
301 dfgRepatchCall(exec->codeBlock(), methodInfo.callReturnLocation, operationGetByIdOptimize);
304 static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier&, const PropertySlot& slot, StructureStubInfo& stubInfo)
306 if (!baseValue.isCell()
307 || !slot.isCacheable()
308 || baseValue.asCell()->structure()->isUncacheableDictionary()
309 || slot.slotBase() != baseValue
310 || slot.cachedPropertyType() != PropertySlot::Value
311 || (slot.cachedOffset() * sizeof(JSValue)) > (unsigned)MacroAssembler::MaximumCompactPtrAlignedAddressOffset)
314 CodeBlock* codeBlock = exec->codeBlock();
315 JSCell* baseCell = baseValue.asCell();
316 Structure* structure = baseCell->structure();
317 JSGlobalData* globalData = &exec->globalData();
319 ASSERT(slot.slotBase().isObject());
321 PolymorphicAccessStructureList* polymorphicStructureList;
324 if (stubInfo.accessType == access_get_by_id_self) {
325 ASSERT(!stubInfo.stubRoutine);
326 polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), MacroAssemblerCodeRef::createSelfManagedCodeRef(stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase)), stubInfo.u.getByIdSelf.baseObjectStructure.get());
327 stubInfo.initGetByIdSelfList(polymorphicStructureList, 1);
329 polymorphicStructureList = stubInfo.u.getByIdSelfList.structureList;
330 listIndex = stubInfo.u.getByIdSelfList.listSize;
333 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
334 stubInfo.u.getByIdSelfList.listSize++;
336 GPRReg baseGPR = static_cast<GPRReg>(stubInfo.baseGPR);
337 GPRReg resultGPR = static_cast<GPRReg>(stubInfo.valueGPR);
339 MacroAssembler stubJit;
341 MacroAssembler::Jump wrongStruct = stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(structure));
343 if (structure->isUsingInlineStorage())
344 stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue)), resultGPR);
346 stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
347 stubJit.loadPtr(MacroAssembler::Address(resultGPR, slot.cachedOffset() * sizeof(JSValue)), resultGPR);
350 MacroAssembler::Jump success = stubJit.jump();
352 LinkBuffer patchBuffer(*globalData, &stubJit);
354 CodeLocationLabel lastProtoBegin = CodeLocationLabel(polymorphicStructureList->list[listIndex - 1].stubRoutine.code());
355 ASSERT(!!lastProtoBegin);
357 patchBuffer.link(wrongStruct, lastProtoBegin);
358 patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone));
360 MacroAssemblerCodeRef stubRoutine = patchBuffer.finalizeCode();
362 polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure);
364 CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck);
365 RepatchBuffer repatchBuffer(codeBlock);
366 repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine.code()));
368 if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1))
375 void dfgBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
377 bool dontChangeCall = tryBuildGetByIDList(exec, baseValue, propertyName, slot, stubInfo);
379 dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationGetById);
382 static bool tryBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
384 if (!baseValue.isCell()
385 || !slot.isCacheable()
386 || baseValue.asCell()->structure()->isDictionary()
387 || baseValue.asCell()->structure()->typeInfo().prohibitsPropertyCaching()
388 || slot.slotBase() == baseValue
389 || slot.cachedPropertyType() != PropertySlot::Value)
392 ASSERT(slot.slotBase().isObject());
394 size_t offset = slot.cachedOffset();
395 size_t count = normalizePrototypeChain(exec, baseValue, slot.slotBase(), propertyName, offset);
399 Structure* structure = baseValue.asCell()->structure();
400 StructureChain* prototypeChain = structure->prototypeChain(exec);
401 CodeBlock* codeBlock = exec->codeBlock();
402 JSGlobalData* globalData = &exec->globalData();
404 PolymorphicAccessStructureList* polymorphicStructureList;
407 if (stubInfo.accessType == access_get_by_id_chain) {
408 ASSERT(!!stubInfo.stubRoutine);
409 polymorphicStructureList = new PolymorphicAccessStructureList(*globalData, codeBlock->ownerExecutable(), stubInfo.stubRoutine, stubInfo.u.getByIdChain.baseObjectStructure.get(), stubInfo.u.getByIdChain.chain.get());
410 stubInfo.stubRoutine = MacroAssemblerCodeRef();
411 stubInfo.initGetByIdProtoList(polymorphicStructureList, 1);
413 ASSERT(stubInfo.accessType = access_get_by_id_proto_list);
414 polymorphicStructureList = stubInfo.u.getByIdProtoList.structureList;
415 listIndex = stubInfo.u.getByIdProtoList.listSize;
418 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
419 stubInfo.u.getByIdProtoList.listSize++;
421 CodeLocationLabel lastProtoBegin = CodeLocationLabel(polymorphicStructureList->list[listIndex - 1].stubRoutine.code());
422 ASSERT(!!lastProtoBegin);
424 MacroAssemblerCodeRef stubRoutine;
426 generateProtoChainAccessStub(exec, stubInfo, prototypeChain, count, offset, structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone), lastProtoBegin, stubRoutine);
428 polymorphicStructureList->list[listIndex].set(*globalData, codeBlock->ownerExecutable(), stubRoutine, structure);
430 CodeLocationJump jumpLocation = stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck);
431 RepatchBuffer repatchBuffer(codeBlock);
432 repatchBuffer.relink(jumpLocation, CodeLocationLabel(stubRoutine.code()));
434 if (listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1))
441 void dfgBuildGetByIDProtoList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
443 bool dontChangeCall = tryBuildGetByIDProtoList(exec, baseValue, propertyName, slot, stubInfo);
445 dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationGetById);
448 static V_DFGOperation_EJJI appropriatePutByIdFunction(const PutPropertySlot &slot, PutKind putKind)
450 if (slot.isStrictMode()) {
451 if (putKind == Direct)
452 return operationPutByIdDirectStrict;
453 return operationPutByIdStrict;
455 if (putKind == Direct)
456 return operationPutByIdDirectNonStrict;
457 return operationPutByIdNonStrict;
460 static void testPrototype(MacroAssembler &stubJit, GPRReg scratchGPR, JSValue prototype, MacroAssembler::JumpList& failureCases)
462 if (prototype.isNull())
465 ASSERT(prototype.isCell());
467 stubJit.move(MacroAssembler::TrustedImmPtr(prototype.asCell()), scratchGPR);
468 failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(scratchGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(prototype.asCell()->structure())));
471 static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier&, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
473 CodeBlock* codeBlock = exec->codeBlock();
474 JSGlobalData* globalData = &exec->globalData();
476 if (!baseValue.isCell())
478 JSCell* baseCell = baseValue.asCell();
479 Structure* structure = baseCell->structure();
480 Structure* oldStructure = structure->previousID();
482 if (!slot.isCacheable())
484 if (structure->isUncacheableDictionary())
487 // Optimize self access.
488 if (slot.base() == baseValue) {
489 if (slot.type() == PutPropertySlot::NewProperty) {
490 if (structure->isDictionary())
493 // skip optimizing the case where we need a realloc
494 if (oldStructure->propertyStorageCapacity() != structure->propertyStorageCapacity())
497 normalizePrototypeChain(exec, baseCell);
499 StructureChain* prototypeChain = structure->prototypeChain(exec);
501 GPRReg baseGPR = static_cast<GPRReg>(stubInfo.baseGPR);
502 GPRReg valueGPR = static_cast<GPRReg>(stubInfo.valueGPR);
503 GPRReg scratchGPR = static_cast<GPRReg>(stubInfo.scratchGPR);
504 bool needToRestoreScratch = false;
506 ASSERT(scratchGPR != baseGPR);
508 MacroAssembler stubJit;
510 MacroAssembler::JumpList failureCases;
512 if (scratchGPR == InvalidGPRReg) {
513 scratchGPR = JITCodeGenerator::selectScratchGPR(baseGPR, valueGPR);
514 stubJit.push(scratchGPR);
515 needToRestoreScratch = true;
518 failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(oldStructure)));
520 testPrototype(stubJit, scratchGPR, oldStructure->storedPrototype(), failureCases);
522 if (putKind == NotDirect) {
523 for (WriteBarrier<Structure>* it = prototypeChain->head(); *it; ++it)
524 testPrototype(stubJit, scratchGPR, (*it)->storedPrototype(), failureCases);
527 JITCodeGenerator::writeBarrier(stubJit, baseGPR, scratchGPR, WriteBarrierForPropertyAccess);
529 stubJit.storePtr(MacroAssembler::TrustedImmPtr(structure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
530 if (structure->isUsingInlineStorage())
531 stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue)));
533 stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
534 stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue)));
537 MacroAssembler::Jump success;
538 MacroAssembler::Jump failure;
540 if (needToRestoreScratch) {
541 stubJit.pop(scratchGPR);
542 success = stubJit.jump();
544 failureCases.link(&stubJit);
545 stubJit.pop(scratchGPR);
546 failure = stubJit.jump();
548 success = stubJit.jump();
550 LinkBuffer patchBuffer(*globalData, &stubJit);
551 patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone));
552 if (needToRestoreScratch)
553 patchBuffer.link(failure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase));
555 patchBuffer.link(failureCases, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase));
557 stubInfo.stubRoutine = patchBuffer.finalizeCode();
559 RepatchBuffer repatchBuffer(codeBlock);
560 repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck), CodeLocationLabel(stubInfo.stubRoutine.code()));
561 repatchBuffer.relink(stubInfo.callReturnLocation, appropriatePutByIdFunction(slot, putKind));
563 stubInfo.initPutByIdTransition(*globalData, codeBlock->ownerExecutable(), oldStructure, structure, prototypeChain);
568 dfgRepatchByIdSelfAccess(codeBlock, stubInfo, structure, slot.cachedOffset(), appropriatePutByIdFunction(slot, putKind), false);
569 stubInfo.initPutByIdReplace(*globalData, codeBlock->ownerExecutable(), structure);
573 // FIXME: should support the transition case!
577 void dfgRepatchPutByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
579 bool cached = tryCachePutByID(exec, baseValue, propertyName, slot, stubInfo, putKind);
581 dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, appropriatePutByIdFunction(slot, putKind));
584 void dfgLinkFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock, JSFunction* callee, MacroAssemblerCodePtr codePtr, CodeSpecializationKind kind)
586 CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock();
588 RepatchBuffer repatchBuffer(callerCodeBlock);
590 if (!calleeCodeBlock || static_cast<int>(exec->argumentCountIncludingThis()) == calleeCodeBlock->m_numParameters) {
591 ASSERT(!callLinkInfo.isLinked());
592 callLinkInfo.callee.set(exec->callerFrame()->globalData(), callLinkInfo.hotPathBegin, callerCodeBlock->ownerExecutable(), callee);
593 repatchBuffer.relink(callLinkInfo.hotPathOther, codePtr);
596 calleeCodeBlock->linkIncomingCall(&callLinkInfo);
599 if (kind == CodeForCall) {
600 repatchBuffer.relink(CodeLocationCall(callLinkInfo.callReturnLocation), operationVirtualCall);
603 ASSERT(kind == CodeForConstruct);
604 repatchBuffer.relink(CodeLocationCall(callLinkInfo.callReturnLocation), operationVirtualConstruct);
607 } } // namespace JSC::DFG