2 * Copyright (C) 2008 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.
31 #include "CodeBlock.h"
32 #include "JITInlineMethods.h"
34 #include "JSFunction.h"
35 #include "Interpreter.h"
36 #include "ResultType.h"
37 #include "SamplingTool.h"
47 #if !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
49 void JIT::compileGetByIdHotPath(int resultVReg
, int baseVReg
, Identifier
* ident
, unsigned)
51 // As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be patched.
52 // Additionally, for get_by_id we need patch the offset of the branch to the slow case (we patch this to jump
53 // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label
54 // to jump back to if one of these trampolies finds a match.
56 emitGetVirtualRegister(baseVReg
, X86::eax
);
58 emitPutJITStubArg(X86::eax
, 1);
59 emitPutJITStubArgConstant(ident
, 2);
60 emitCTICall(Interpreter::cti_op_get_by_id_generic
);
61 emitPutVirtualRegister(resultVReg
);
65 void JIT::compileGetByIdSlowCase(int, int, Identifier
*, Vector
<SlowCaseEntry
>::iterator
&, unsigned)
70 void JIT::compilePutByIdHotPath(int baseVReg
, Identifier
* ident
, int valueVReg
, unsigned)
72 // In order to be able to patch both the Structure, and the object offset, we store one pointer,
73 // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code
74 // such that the Structure & offset are always at the same distance from this.
76 emitGetVirtualRegisters(baseVReg
, X86::eax
, valueVReg
, X86::edx
);
78 emitPutJITStubArgConstant(ident
, 2);
79 emitPutJITStubArg(X86::eax
, 1);
80 emitPutJITStubArg(X86::edx
, 3);
81 emitCTICall(Interpreter::cti_op_put_by_id_generic
);
84 void JIT::compilePutByIdSlowCase(int, Identifier
*, int, Vector
<SlowCaseEntry
>::iterator
&, unsigned)
91 void JIT::compileGetByIdHotPath(int resultVReg
, int baseVReg
, Identifier
*, unsigned propertyAccessInstructionIndex
)
93 // As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be patched.
94 // Additionally, for get_by_id we need patch the offset of the branch to the slow case (we patch this to jump
95 // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label
96 // to jump back to if one of these trampolies finds a match.
98 emitGetVirtualRegister(baseVReg
, X86::eax
);
100 emitJumpSlowCaseIfNotJSCell(X86::eax
, baseVReg
);
102 Label
hotPathBegin(this);
103 m_propertyAccessCompilationInfo
[propertyAccessInstructionIndex
].hotPathBegin
= hotPathBegin
;
105 DataLabelPtr structureToCompare
;
106 Jump structureCheck
= jnePtrWithPatch(Address(X86::eax
, FIELD_OFFSET(JSCell
, m_structure
)), structureToCompare
, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure
)));
107 addSlowCase(structureCheck
);
108 ASSERT(differenceBetween(hotPathBegin
, structureToCompare
) == patchOffsetGetByIdStructure
);
109 ASSERT(differenceBetween(hotPathBegin
, structureCheck
) == patchOffsetGetByIdBranchToSlowCase
);
111 loadPtr(Address(X86::eax
, FIELD_OFFSET(JSObject
, m_propertyStorage
)), X86::eax
);
112 DataLabel32 displacementLabel
= loadPtrWithAddressOffsetPatch(Address(X86::eax
, patchGetByIdDefaultOffset
), X86::eax
);
113 ASSERT(differenceBetween(hotPathBegin
, displacementLabel
) == patchOffsetGetByIdPropertyMapOffset
);
115 Label
putResult(this);
116 ASSERT(differenceBetween(hotPathBegin
, putResult
) == patchOffsetGetByIdPutResult
);
117 emitPutVirtualRegister(resultVReg
);
121 void JIT::compileGetByIdSlowCase(int resultVReg
, int baseVReg
, Identifier
* ident
, Vector
<SlowCaseEntry
>::iterator
& iter
, unsigned propertyAccessInstructionIndex
)
123 // As for the hot path of get_by_id, above, we ensure that we can use an architecture specific offset
124 // so that we only need track one pointer into the slow case code - we track a pointer to the location
125 // of the call (which we can use to look up the patch information), but should a array-length or
126 // prototype access trampoline fail we want to bail out back to here. To do so we can subtract back
127 // the distance from the call to the head of the slow case.
129 linkSlowCaseIfNotJSCell(iter
, baseVReg
);
133 Label
coldPathBegin(this);
135 emitPutJITStubArg(X86::eax
, 1);
136 emitPutJITStubArgConstant(ident
, 2);
137 Jump call
= emitCTICall(Interpreter::cti_op_get_by_id
);
138 emitPutVirtualRegister(resultVReg
);
140 ASSERT(differenceBetween(coldPathBegin
, call
) == patchOffsetGetByIdSlowCaseCall
);
142 // Track the location of the call; this will be used to recover patch information.
143 m_propertyAccessCompilationInfo
[propertyAccessInstructionIndex
].callReturnLocation
= call
;
146 void JIT::compilePutByIdHotPath(int baseVReg
, Identifier
*, int valueVReg
, unsigned propertyAccessInstructionIndex
)
148 // In order to be able to patch both the Structure, and the object offset, we store one pointer,
149 // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code
150 // such that the Structure & offset are always at the same distance from this.
152 emitGetVirtualRegisters(baseVReg
, X86::eax
, valueVReg
, X86::edx
);
154 // Jump to a slow case if either the base object is an immediate, or if the Structure does not match.
155 emitJumpSlowCaseIfNotJSCell(X86::eax
, baseVReg
);
157 Label
hotPathBegin(this);
158 m_propertyAccessCompilationInfo
[propertyAccessInstructionIndex
].hotPathBegin
= hotPathBegin
;
160 // It is important that the following instruction plants a 32bit immediate, in order that it can be patched over.
161 DataLabelPtr structureToCompare
;
162 addSlowCase(jnePtrWithPatch(Address(X86::eax
, FIELD_OFFSET(JSCell
, m_structure
)), structureToCompare
, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure
))));
163 ASSERT(differenceBetween(hotPathBegin
, structureToCompare
) == patchOffsetPutByIdStructure
);
165 // Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used.
166 loadPtr(Address(X86::eax
, FIELD_OFFSET(JSObject
, m_propertyStorage
)), X86::eax
);
167 DataLabel32 displacementLabel
= storePtrWithAddressOffsetPatch(X86::edx
, Address(X86::eax
, patchGetByIdDefaultOffset
));
168 ASSERT(differenceBetween(hotPathBegin
, displacementLabel
) == patchOffsetPutByIdPropertyMapOffset
);
171 void JIT::compilePutByIdSlowCase(int baseVReg
, Identifier
* ident
, int, Vector
<SlowCaseEntry
>::iterator
& iter
, unsigned propertyAccessInstructionIndex
)
173 linkSlowCaseIfNotJSCell(iter
, baseVReg
);
176 emitPutJITStubArgConstant(ident
, 2);
177 emitPutJITStubArg(X86::eax
, 1);
178 emitPutJITStubArg(X86::edx
, 3);
179 Jump call
= emitCTICall(Interpreter::cti_op_put_by_id
);
181 // Track the location of the call; this will be used to recover patch information.
182 m_propertyAccessCompilationInfo
[propertyAccessInstructionIndex
].callReturnLocation
= call
;
185 static JSObject
* resizePropertyStorage(JSObject
* baseObject
, int32_t oldSize
, int32_t newSize
)
187 baseObject
->allocatePropertyStorage(oldSize
, newSize
);
191 static inline bool transitionWillNeedStorageRealloc(Structure
* oldStructure
, Structure
* newStructure
)
193 return oldStructure
->propertyStorageCapacity() != newStructure
->propertyStorageCapacity();
196 void JIT::privateCompilePutByIdTransition(StructureStubInfo
* stubInfo
, Structure
* oldStructure
, Structure
* newStructure
, size_t cachedOffset
, StructureChain
* chain
, void* returnAddress
)
198 JumpList failureCases
;
199 // Check eax is an object of the right Structure.
200 failureCases
.append(emitJumpIfNotJSCell(X86::eax
));
201 failureCases
.append(jnePtr(Address(X86::eax
, FIELD_OFFSET(JSCell
, m_structure
)), ImmPtr(oldStructure
)));
202 JumpList successCases
;
205 loadPtr(Address(X86::eax
, FIELD_OFFSET(JSCell
, m_structure
)), X86::ecx
);
206 // proto(ecx) = baseObject->structure()->prototype()
207 failureCases
.append(jne32(Address(X86::ecx
, FIELD_OFFSET(Structure
, m_typeInfo
) + FIELD_OFFSET(TypeInfo
, m_type
)), Imm32(ObjectType
)));
209 loadPtr(Address(X86::ecx
, FIELD_OFFSET(Structure
, m_prototype
)), X86::ecx
);
211 // ecx = baseObject->m_structure
212 for (RefPtr
<Structure
>* it
= chain
->head(); *it
; ++it
) {
213 // null check the prototype
214 successCases
.append(jePtr(X86::ecx
, ImmPtr(JSValuePtr::encode(jsNull()))));
216 // Check the structure id
217 failureCases
.append(jnePtr(Address(X86::ecx
, FIELD_OFFSET(JSCell
, m_structure
)), ImmPtr(it
->get())));
219 loadPtr(Address(X86::ecx
, FIELD_OFFSET(JSCell
, m_structure
)), X86::ecx
);
220 failureCases
.append(jne32(Address(X86::ecx
, FIELD_OFFSET(Structure
, m_typeInfo
) + FIELD_OFFSET(TypeInfo
, m_type
)), Imm32(ObjectType
)));
221 loadPtr(Address(X86::ecx
, FIELD_OFFSET(Structure
, m_prototype
)), X86::ecx
);
224 successCases
.link(this);
228 // emit a call only if storage realloc is needed
229 if (transitionWillNeedStorageRealloc(oldStructure
, newStructure
)) {
232 move(Imm32(newStructure
->propertyStorageCapacity()), X86::edx
);
233 move(Imm32(oldStructure
->propertyStorageCapacity()), X86::esi
);
234 move(X86::eax
, X86::edi
);
237 push(Imm32(newStructure
->propertyStorageCapacity()));
238 push(Imm32(oldStructure
->propertyStorageCapacity()));
241 addPtr(Imm32(3 * sizeof(void*)), X86::esp
);
243 emitGetJITStubArg(3, X86::edx
);
247 // Assumes m_refCount can be decremented easily, refcount decrement is safe as
248 // codeblock should ensure oldStructure->m_refCount > 0
249 sub32(Imm32(1), AbsoluteAddress(oldStructure
->addressOfCount()));
250 add32(Imm32(1), AbsoluteAddress(newStructure
->addressOfCount()));
251 storePtr(ImmPtr(newStructure
), Address(X86::eax
, FIELD_OFFSET(JSCell
, m_structure
)));
254 loadPtr(Address(X86::eax
, FIELD_OFFSET(JSObject
, m_propertyStorage
)), X86::eax
);
255 storePtr(X86::edx
, Address(X86::eax
, cachedOffset
* sizeof(JSValuePtr
)));
260 bool plantedFailureJump
= false;
261 if (!failureCases
.empty()) {
262 failureCases
.link(this);
263 restoreArgumentReferenceForTrampoline();
264 failureJump
= jump();
265 plantedFailureJump
= true;
268 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
269 PatchBuffer
patchBuffer(code
);
271 if (plantedFailureJump
)
272 patchBuffer
.link(failureJump
, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail
));
274 if (transitionWillNeedStorageRealloc(oldStructure
, newStructure
))
275 patchBuffer
.link(callTarget
, reinterpret_cast<void*>(resizePropertyStorage
));
277 stubInfo
->stubRoutine
= code
;
279 Jump::patch(returnAddress
, code
);
282 void JIT::patchGetByIdSelf(StructureStubInfo
* stubInfo
, Structure
* structure
, size_t cachedOffset
, void* returnAddress
)
284 // We don't want to patch more than once - in future go to cti_op_get_by_id_generic.
285 // Should probably go to Interpreter::cti_op_get_by_id_fail, but that doesn't do anything interesting right now.
286 Jump::patch(returnAddress
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail
));
288 // Patch the offset into the propoerty map to load from, then patch the Structure to look for.
289 void* structureAddress
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdStructure
);
290 void* displacementAddress
= reinterpret_cast<void*>(reinterpret_cast<intptr_t>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdPropertyMapOffset
);
291 DataLabelPtr::patch(structureAddress
, structure
);
292 DataLabel32::patch(displacementAddress
, cachedOffset
* sizeof(JSValuePtr
));
295 void JIT::patchPutByIdReplace(StructureStubInfo
* stubInfo
, Structure
* structure
, size_t cachedOffset
, void* returnAddress
)
297 // We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
298 // Should probably go to Interpreter::cti_op_put_by_id_fail, but that doesn't do anything interesting right now.
299 Jump::patch(returnAddress
, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_generic
));
301 // Patch the offset into the propoerty map to load from, then patch the Structure to look for.
302 void* structureAddress
= reinterpret_cast<char*>(stubInfo
->hotPathBegin
) + patchOffsetPutByIdStructure
;
303 void* displacementAddress
= reinterpret_cast<char*>(stubInfo
->hotPathBegin
) + patchOffsetPutByIdPropertyMapOffset
;
304 DataLabelPtr::patch(structureAddress
, structure
);
305 DataLabel32::patch(displacementAddress
, cachedOffset
* sizeof(JSValuePtr
));
308 void JIT::privateCompilePatchGetArrayLength(void* returnAddress
)
310 StructureStubInfo
* stubInfo
= &m_codeBlock
->getStubInfo(returnAddress
);
312 // We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
313 Jump::patch(returnAddress
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_array_fail
));
315 // Check eax is an array
316 Jump failureCases1
= jnePtr(Address(X86::eax
), ImmPtr(m_interpreter
->m_jsArrayVptr
));
318 // Checks out okay! - get the length from the storage
319 loadPtr(Address(X86::eax
, FIELD_OFFSET(JSArray
, m_storage
)), X86::ecx
);
320 load32(Address(X86::ecx
, FIELD_OFFSET(ArrayStorage
, m_length
)), X86::ecx
);
322 Jump failureCases2
= ja32(X86::ecx
, Imm32(JSImmediate::maxImmediateInt
));
324 emitFastArithIntToImmNoCheck(X86::ecx
, X86::eax
);
325 Jump success
= jump();
327 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
328 PatchBuffer
patchBuffer(code
);
330 // Use the patch information to link the failure cases back to the original slow case routine.
331 void* slowCaseBegin
= reinterpret_cast<char*>(stubInfo
->callReturnLocation
) - patchOffsetGetByIdSlowCaseCall
;
332 patchBuffer
.link(failureCases1
, slowCaseBegin
);
333 patchBuffer
.link(failureCases2
, slowCaseBegin
);
335 // On success return back to the hot patch code, at a point it will perform the store to dest for us.
336 void* hotPathPutResult
= reinterpret_cast<char*>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdPutResult
;
337 patchBuffer
.link(success
, hotPathPutResult
);
339 // Track the stub we have created so that it will be deleted later.
340 stubInfo
->stubRoutine
= code
;
342 // Finally patch the jump to sow case back in the hot path to jump here instead.
343 void* jumpLocation
= reinterpret_cast<char*>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdBranchToSlowCase
;
344 Jump::patch(jumpLocation
, code
);
347 void JIT::privateCompileGetByIdSelf(StructureStubInfo
* stubInfo
, Structure
* structure
, size_t cachedOffset
, void* returnAddress
)
349 // Check eax is an object of the right Structure.
350 Jump failureCases1
= emitJumpIfNotJSCell(X86::eax
);
351 Jump failureCases2
= checkStructure(X86::eax
, structure
);
353 // Checks out okay! - getDirectOffset
354 loadPtr(Address(X86::eax
, FIELD_OFFSET(JSObject
, m_propertyStorage
)), X86::eax
);
355 loadPtr(Address(X86::eax
, cachedOffset
* sizeof(JSValuePtr
)), X86::eax
);
358 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
359 PatchBuffer
patchBuffer(code
);
361 patchBuffer
.link(failureCases1
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail
));
362 patchBuffer
.link(failureCases2
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail
));
364 stubInfo
->stubRoutine
= code
;
366 Jump::patch(returnAddress
, code
);
369 void JIT::privateCompileGetByIdProto(StructureStubInfo
* stubInfo
, Structure
* structure
, Structure
* prototypeStructure
, size_t cachedOffset
, void* returnAddress
, CallFrame
* callFrame
)
371 #if USE(CTI_REPATCH_PIC)
372 // We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
373 Jump::patch(returnAddress
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list
));
375 // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
376 // referencing the prototype object - let's speculatively load it's table nice and early!)
377 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
378 PropertyStorage
* protoPropertyStorage
= &protoObject
->m_propertyStorage
;
379 loadPtr(static_cast<void*>(protoPropertyStorage
), X86::edx
);
381 // Check eax is an object of the right Structure.
382 Jump failureCases1
= checkStructure(X86::eax
, structure
);
384 // Check the prototype object's Structure had not changed.
385 Structure
** prototypeStructureAddress
= &(protoObject
->m_structure
);
387 move(ImmPtr(prototypeStructure
), X86::ebx
);
388 Jump failureCases2
= jnePtr(X86::ebx
, AbsoluteAddress(prototypeStructureAddress
));
390 Jump failureCases2
= jnePtr(AbsoluteAddress(prototypeStructureAddress
), ImmPtr(prototypeStructure
));
393 // Checks out okay! - getDirectOffset
394 loadPtr(Address(X86::edx
, cachedOffset
* sizeof(JSValuePtr
)), X86::eax
);
396 Jump success
= jump();
398 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
399 PatchBuffer
patchBuffer(code
);
401 // Use the patch information to link the failure cases back to the original slow case routine.
402 void* slowCaseBegin
= reinterpret_cast<char*>(stubInfo
->callReturnLocation
) - patchOffsetGetByIdSlowCaseCall
;
403 patchBuffer
.link(failureCases1
, slowCaseBegin
);
404 patchBuffer
.link(failureCases2
, slowCaseBegin
);
406 // On success return back to the hot patch code, at a point it will perform the store to dest for us.
407 intptr_t successDest
= reinterpret_cast<intptr_t>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdPutResult
;
408 patchBuffer
.link(success
, reinterpret_cast<void*>(successDest
));
410 // Track the stub we have created so that it will be deleted later.
411 stubInfo
->stubRoutine
= code
;
413 // Finally patch the jump to slow case back in the hot path to jump here instead.
414 void* jumpLocation
= reinterpret_cast<char*>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdBranchToSlowCase
;
415 Jump::patch(jumpLocation
, code
);
417 // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
418 // referencing the prototype object - let's speculatively load it's table nice and early!)
419 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
420 PropertyStorage
* protoPropertyStorage
= &protoObject
->m_propertyStorage
;
421 loadPtr(protoPropertyStorage
, X86::edx
);
423 // Check eax is an object of the right Structure.
424 Jump failureCases1
= emitJumpIfNotJSCell(X86::eax
);
425 Jump failureCases2
= checkStructure(X86::eax
, structure
);
427 // Check the prototype object's Structure had not changed.
428 Structure
** prototypeStructureAddress
= &(protoObject
->m_structure
);
429 Jump failureCases3
= jnePtr(AbsoluteAddress(prototypeStructureAddress
), ImmPtr(prototypeStructure
));
431 // Checks out okay! - getDirectOffset
432 loadPtr(Address(X86::edx
, cachedOffset
* sizeof(JSValuePtr
)), X86::eax
);
436 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
437 PatchBuffer
patchBuffer(code
);
439 patchBuffer
.link(failureCases1
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail
));
440 patchBuffer
.link(failureCases2
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail
));
441 patchBuffer
.link(failureCases3
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail
));
443 stubInfo
->stubRoutine
= code
;
445 Jump::patch(returnAddress
, code
);
449 #if USE(CTI_REPATCH_PIC)
450 void JIT::privateCompileGetByIdSelfList(StructureStubInfo
* stubInfo
, PolymorphicAccessStructureList
* polymorphicStructures
, int currentIndex
, Structure
* structure
, size_t cachedOffset
)
452 Jump failureCase
= checkStructure(X86::eax
, structure
);
453 loadPtr(Address(X86::eax
, FIELD_OFFSET(JSObject
, m_propertyStorage
)), X86::eax
);
454 loadPtr(Address(X86::eax
, cachedOffset
* sizeof(JSValuePtr
)), X86::eax
);
455 Jump success
= jump();
457 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
459 PatchBuffer
patchBuffer(code
);
461 // Use the patch information to link the failure cases back to the original slow case routine.
462 void* lastProtoBegin
= polymorphicStructures
->list
[currentIndex
- 1].stubRoutine
;
464 lastProtoBegin
= reinterpret_cast<char*>(stubInfo
->callReturnLocation
) - patchOffsetGetByIdSlowCaseCall
;
466 patchBuffer
.link(failureCase
, lastProtoBegin
);
468 // On success return back to the hot patch code, at a point it will perform the store to dest for us.
469 intptr_t successDest
= reinterpret_cast<intptr_t>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdPutResult
;
470 patchBuffer
.link(success
, reinterpret_cast<void*>(successDest
));
473 polymorphicStructures
->list
[currentIndex
].set(code
, structure
);
475 // Finally patch the jump to slow case back in the hot path to jump here instead.
476 void* jumpLocation
= reinterpret_cast<char*>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdBranchToSlowCase
;
477 Jump::patch(jumpLocation
, code
);
480 void JIT::privateCompileGetByIdProtoList(StructureStubInfo
* stubInfo
, PolymorphicAccessStructureList
* prototypeStructures
, int currentIndex
, Structure
* structure
, Structure
* prototypeStructure
, size_t cachedOffset
, CallFrame
* callFrame
)
482 // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
483 // referencing the prototype object - let's speculatively load it's table nice and early!)
484 JSObject
* protoObject
= asObject(structure
->prototypeForLookup(callFrame
));
485 PropertyStorage
* protoPropertyStorage
= &protoObject
->m_propertyStorage
;
486 loadPtr(protoPropertyStorage
, X86::edx
);
488 // Check eax is an object of the right Structure.
489 Jump failureCases1
= checkStructure(X86::eax
, structure
);
491 // Check the prototype object's Structure had not changed.
492 Structure
** prototypeStructureAddress
= &(protoObject
->m_structure
);
494 move(ImmPtr(prototypeStructure
), X86::ebx
);
495 Jump failureCases2
= jnePtr(X86::ebx
, AbsoluteAddress(prototypeStructureAddress
));
497 Jump failureCases2
= jnePtr(AbsoluteAddress(prototypeStructureAddress
), ImmPtr(prototypeStructure
));
500 // Checks out okay! - getDirectOffset
501 loadPtr(Address(X86::edx
, cachedOffset
* sizeof(JSValuePtr
)), X86::eax
);
503 Jump success
= jump();
505 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
506 PatchBuffer
patchBuffer(code
);
508 // Use the patch information to link the failure cases back to the original slow case routine.
509 void* lastProtoBegin
= prototypeStructures
->list
[currentIndex
- 1].stubRoutine
;
510 patchBuffer
.link(failureCases1
, lastProtoBegin
);
511 patchBuffer
.link(failureCases2
, lastProtoBegin
);
513 // On success return back to the hot patch code, at a point it will perform the store to dest for us.
514 intptr_t successDest
= reinterpret_cast<intptr_t>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdPutResult
;
515 patchBuffer
.link(success
, reinterpret_cast<void*>(successDest
));
518 prototypeStructure
->ref();
519 prototypeStructures
->list
[currentIndex
].set(code
, structure
, prototypeStructure
);
521 // Finally patch the jump to slow case back in the hot path to jump here instead.
522 void* jumpLocation
= reinterpret_cast<char*>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdBranchToSlowCase
;
523 Jump::patch(jumpLocation
, code
);
526 void JIT::privateCompileGetByIdChainList(StructureStubInfo
* stubInfo
, PolymorphicAccessStructureList
* prototypeStructures
, int currentIndex
, Structure
* structure
, StructureChain
* chain
, size_t count
, size_t cachedOffset
, CallFrame
* callFrame
)
530 JumpList bucketsOfFail
;
532 // Check eax is an object of the right Structure.
533 Jump baseObjectCheck
= checkStructure(X86::eax
, structure
);
534 bucketsOfFail
.append(baseObjectCheck
);
536 Structure
* currStructure
= structure
;
537 RefPtr
<Structure
>* chainEntries
= chain
->head();
538 JSObject
* protoObject
= 0;
539 for (unsigned i
= 0; i
< count
; ++i
) {
540 protoObject
= asObject(currStructure
->prototypeForLookup(callFrame
));
541 currStructure
= chainEntries
[i
].get();
543 // Check the prototype object's Structure had not changed.
544 Structure
** prototypeStructureAddress
= &(protoObject
->m_structure
);
546 move(ImmPtr(currStructure
), X86::ebx
);
547 bucketsOfFail
.append(jnePtr(X86::ebx
, AbsoluteAddress(prototypeStructureAddress
)));
549 bucketsOfFail
.append(jnePtr(AbsoluteAddress(prototypeStructureAddress
), ImmPtr(currStructure
)));
554 PropertyStorage
* protoPropertyStorage
= &protoObject
->m_propertyStorage
;
555 loadPtr(protoPropertyStorage
, X86::edx
);
556 loadPtr(Address(X86::edx
, cachedOffset
* sizeof(JSValuePtr
)), X86::eax
);
557 Jump success
= jump();
559 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
560 PatchBuffer
patchBuffer(code
);
562 // Use the patch information to link the failure cases back to the original slow case routine.
563 void* lastProtoBegin
= prototypeStructures
->list
[currentIndex
- 1].stubRoutine
;
565 patchBuffer
.link(bucketsOfFail
, lastProtoBegin
);
567 // On success return back to the hot patch code, at a point it will perform the store to dest for us.
568 intptr_t successDest
= reinterpret_cast<intptr_t>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdPutResult
;
569 patchBuffer
.link(success
, reinterpret_cast<void*>(successDest
));
571 // Track the stub we have created so that it will be deleted later.
574 prototypeStructures
->list
[currentIndex
].set(code
, structure
, chain
);
576 // Finally patch the jump to slow case back in the hot path to jump here instead.
577 void* jumpLocation
= reinterpret_cast<char*>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdBranchToSlowCase
;
578 Jump::patch(jumpLocation
, code
);
582 void JIT::privateCompileGetByIdChain(StructureStubInfo
* stubInfo
, Structure
* structure
, StructureChain
* chain
, size_t count
, size_t cachedOffset
, void* returnAddress
, CallFrame
* callFrame
)
584 #if USE(CTI_REPATCH_PIC)
585 // We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
586 Jump::patch(returnAddress
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list
));
590 JumpList bucketsOfFail
;
592 // Check eax is an object of the right Structure.
593 bucketsOfFail
.append(checkStructure(X86::eax
, structure
));
595 Structure
* currStructure
= structure
;
596 RefPtr
<Structure
>* chainEntries
= chain
->head();
597 JSObject
* protoObject
= 0;
598 for (unsigned i
= 0; i
< count
; ++i
) {
599 protoObject
= asObject(currStructure
->prototypeForLookup(callFrame
));
600 currStructure
= chainEntries
[i
].get();
602 // Check the prototype object's Structure had not changed.
603 Structure
** prototypeStructureAddress
= &(protoObject
->m_structure
);
605 move(ImmPtr(currStructure
), X86::ebx
);
606 bucketsOfFail
.append(jnePtr(X86::ebx
, AbsoluteAddress(prototypeStructureAddress
)));
608 bucketsOfFail
.append(jnePtr(AbsoluteAddress(prototypeStructureAddress
), ImmPtr(currStructure
)));
613 PropertyStorage
* protoPropertyStorage
= &protoObject
->m_propertyStorage
;
614 loadPtr(protoPropertyStorage
, X86::edx
);
615 loadPtr(Address(X86::edx
, cachedOffset
* sizeof(JSValuePtr
)), X86::eax
);
616 Jump success
= jump();
618 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
619 PatchBuffer
patchBuffer(code
);
621 // Use the patch information to link the failure cases back to the original slow case routine.
622 void* slowCaseBegin
= reinterpret_cast<char*>(stubInfo
->callReturnLocation
) - patchOffsetGetByIdSlowCaseCall
;
624 patchBuffer
.link(bucketsOfFail
, slowCaseBegin
);
626 // On success return back to the hot patch code, at a point it will perform the store to dest for us.
627 intptr_t successDest
= reinterpret_cast<intptr_t>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdPutResult
;
628 patchBuffer
.link(success
, reinterpret_cast<void*>(successDest
));
630 // Track the stub we have created so that it will be deleted later.
631 stubInfo
->stubRoutine
= code
;
633 // Finally patch the jump to slow case back in the hot path to jump here instead.
634 void* jumpLocation
= reinterpret_cast<char*>(stubInfo
->hotPathBegin
) + patchOffsetGetByIdBranchToSlowCase
;
635 Jump::patch(jumpLocation
, code
);
639 JumpList bucketsOfFail
;
641 // Check eax is an object of the right Structure.
642 bucketsOfFail
.append(emitJumpIfNotJSCell(X86::eax
));
643 bucketsOfFail
.append(checkStructure(X86::eax
, structure
));
645 Structure
* currStructure
= structure
;
646 RefPtr
<Structure
>* chainEntries
= chain
->head();
647 JSObject
* protoObject
= 0;
648 for (unsigned i
= 0; i
< count
; ++i
) {
649 protoObject
= asObject(currStructure
->prototypeForLookup(callFrame
));
650 currStructure
= chainEntries
[i
].get();
652 // Check the prototype object's Structure had not changed.
653 Structure
** prototypeStructureAddress
= &(protoObject
->m_structure
);
655 move(ImmPtr(currStructure
), X86::ebx
);
656 bucketsOfFail
.append(jnePtr(X86::ebx
, AbsoluteAddress(prototypeStructureAddress
)));
658 bucketsOfFail
.append(jnePtr(AbsoluteAddress(prototypeStructureAddress
), ImmPtr(currStructure
)));
663 PropertyStorage
* protoPropertyStorage
= &protoObject
->m_propertyStorage
;
664 loadPtr(protoPropertyStorage
, X86::edx
);
665 loadPtr(Address(X86::edx
, cachedOffset
* sizeof(JSValuePtr
)), X86::eax
);
668 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
670 patchBuffer
.link(bucketsOfFail
, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail
));
672 stubInfo
->stubRoutine
= code
;
674 Jump::patch(returnAddress
, code
);
678 void JIT::privateCompilePutByIdReplace(StructureStubInfo
* stubInfo
, Structure
* structure
, size_t cachedOffset
, void* returnAddress
)
680 // Check eax is an object of the right Structure.
681 Jump failureCases1
= emitJumpIfNotJSCell(X86::eax
);
682 Jump failureCases2
= checkStructure(X86::eax
, structure
);
684 // checks out okay! - putDirectOffset
685 loadPtr(Address(X86::eax
, FIELD_OFFSET(JSObject
, m_propertyStorage
)), X86::eax
);
686 storePtr(X86::edx
, Address(X86::eax
, cachedOffset
* sizeof(JSValuePtr
)));
689 void* code
= m_assembler
.executableCopy(m_codeBlock
->executablePool());
690 PatchBuffer
patchBuffer(code
);
692 patchBuffer
.link(failureCases1
, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail
));
693 patchBuffer
.link(failureCases2
, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail
));
695 stubInfo
->stubRoutine
= code
;
697 Jump::patch(returnAddress
, code
);
704 #endif // ENABLE(JIT)