1047 static void emitCustomSetterStub(ExecState* exec, const PutPropertySlot& slot,
1048 StructureStubInfo& stubInfo, Structure* structure, StructureChain* prototypeChain,
1049 CodeLocationLabel failureLabel, RefPtr<JITStubRoutine>& stubRoutine)
1050 {
1051 VM* vm = &exec->vm();
1052 ASSERT(stubInfo.patch.spillMode == DontSpill);
1053 GPRReg baseGPR = static_cast<GPRReg>(stubInfo.patch.baseGPR);
1054 #if USE(JSVALUE32_64)
1055 GPRReg valueTagGPR = static_cast<GPRReg>(stubInfo.patch.valueTagGPR);
1056 #endif
1057 GPRReg valueGPR = static_cast<GPRReg>(stubInfo.patch.valueGPR);
1058 TempRegisterSet tempRegisters(stubInfo.patch.usedRegisters);
1059
1060 CCallHelpers stubJit(vm);
1061 GPRReg scratchGPR = tempRegisters.getFreeGPR();
1062 RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
1063 RELEASE_ASSERT(scratchGPR != baseGPR);
1064 RELEASE_ASSERT(scratchGPR != valueGPR);
1065 MacroAssembler::JumpList failureCases;
1066 failureCases.append(branchStructure(stubJit,
1067 MacroAssembler::NotEqual,
1068 MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()),
1069 structure));
1070
1071 if (prototypeChain) {
1072 for (WriteBarrier<Structure>* it = prototypeChain->head(); *it; ++it)
1073 addStructureTransitionCheck((*it)->storedPrototype(), exec->codeBlock(), stubInfo, stubJit, failureCases, scratchGPR);
1074 }
1075
1076 // typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value);
1077 #if USE(JSVALUE64)
1078 stubJit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(slot.base()), baseGPR, valueGPR);
1079 #else
1080 stubJit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(slot.base()), baseGPR, MacroAssembler::TrustedImm32(JSValue::CellTag), valueGPR, valueTagGPR);
1081 #endif
1082
1083 // Need to make sure that whenever this call is made in the future, we remember the
1084 // place that we made it from. It just so happens to be the place that we are at
1085 // right now!
1086 stubJit.store32(MacroAssembler::TrustedImm32(exec->locationAsRawBits()),
1087 CCallHelpers::tagFor(static_cast<VirtualRegister>(JSStack::ArgumentCount)));
1088 stubJit.storePtr(GPRInfo::callFrameRegister, &vm->topCallFrame);
1089
1090 MacroAssembler::Call setterCall = stubJit.call();
1091
1092 MacroAssembler::Jump success = stubJit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
1093
1094 stubJit.setupArguments(CCallHelpers::TrustedImmPtr(vm), GPRInfo::callFrameRegister);
1095
1096 MacroAssembler::Call handlerCall = stubJit.call();
1097
1098 stubJit.jumpToExceptionHandler();
1099 LinkBuffer patchBuffer(*vm, &stubJit, exec->codeBlock());
1100
1101 patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone));
1102 patchBuffer.link(failureCases, failureLabel);
1103 patchBuffer.link(setterCall, FunctionPtr(slot.customSetter()));
1104 patchBuffer.link(handlerCall, lookupExceptionHandler);
1105
1106 stubRoutine = FINALIZE_CODE_FOR_GC_AWARE_STUB(
1107 exec->codeBlock(), patchBuffer, true, nullptr,
1108 ("PutById custom setter stub for %s, return point %p",
1109 toCString(*exec->codeBlock()).data(),
1110 stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone).executableAddress()));
1111 }
1112
1113