1 /*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26 #include "config.h"
27 #include "JIT.h"
28
29 #if ENABLE(JIT)
30
31 #include "CodeBlock.h"
32 #include "JITInlineMethods.h"
33 #include "JSArray.h"
34 #include "JSFunction.h"
35 #include "Interpreter.h"
36 #include "ResultType.h"
37 #include "SamplingTool.h"
38
39 #ifndef NDEBUG
40 #include <stdio.h>
41 #endif
42
43 using namespace std;
44
45 namespace JSC {
46
47 #if !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
48
compileGetByIdHotPath(int resultVReg,int baseVReg,Identifier * ident,unsigned)49 void JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier* ident, unsigned)
50 {
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.
55
56 emitGetVirtualRegister(baseVReg, X86::eax);
57
58 emitPutJITStubArg(X86::eax, 1);
59 emitPutJITStubArgConstant(ident, 2);
60 emitCTICall(Interpreter::cti_op_get_by_id_generic);
61 emitPutVirtualRegister(resultVReg);
62 }
63
64
compileGetByIdSlowCase(int,int,Identifier *,Vector<SlowCaseEntry>::iterator &,unsigned)65 void JIT::compileGetByIdSlowCase(int, int, Identifier*, Vector<SlowCaseEntry>::iterator&, unsigned)
66 {
67 ASSERT_NOT_REACHED();
68 }
69
compilePutByIdHotPath(int baseVReg,Identifier * ident,int valueVReg,unsigned)70 void JIT::compilePutByIdHotPath(int baseVReg, Identifier* ident, int valueVReg, unsigned)
71 {
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.
75
76 emitGetVirtualRegisters(baseVReg, X86::eax, valueVReg, X86::edx);
77
78 emitPutJITStubArgConstant(ident, 2);
79 emitPutJITStubArg(X86::eax, 1);
80 emitPutJITStubArg(X86::edx, 3);
81 emitCTICall(Interpreter::cti_op_put_by_id_generic);
82 }
83
compilePutByIdSlowCase(int,Identifier *,int,Vector<SlowCaseEntry>::iterator &,unsigned)84 void JIT::compilePutByIdSlowCase(int, Identifier*, int, Vector<SlowCaseEntry>::iterator&, unsigned)
85 {
86 ASSERT_NOT_REACHED();
87 }
88
89 #else
90
91 void JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier*, unsigned propertyAccessInstructionIndex)
92 {
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.
97
98 emitGetVirtualRegister(baseVReg, X86::eax);
99
100 emitJumpSlowCaseIfNotJSCell(X86::eax, baseVReg);
101
102 Label hotPathBegin(this);
103 m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin;
104
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);
110
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);
114
115 Label putResult(this);
116 ASSERT(differenceBetween(hotPathBegin, putResult) == patchOffsetGetByIdPutResult);
117 emitPutVirtualRegister(resultVReg);
118 }
119
120
121 void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, unsigned propertyAccessInstructionIndex)
122 {
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.
128
129 linkSlowCaseIfNotJSCell(iter, baseVReg);
130 linkSlowCase(iter);
131
132 #ifndef NDEBUG
133 Label coldPathBegin(this);
134 #endif
135 emitPutJITStubArg(X86::eax, 1);
136 emitPutJITStubArgConstant(ident, 2);
137 Jump call = emitCTICall(Interpreter::cti_op_get_by_id);
138 emitPutVirtualRegister(resultVReg);
139
140 ASSERT(differenceBetween(coldPathBegin, call) == patchOffsetGetByIdSlowCaseCall);
141
142 // Track the location of the call; this will be used to recover patch information.
143 m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
144 }
145
146 void JIT::compilePutByIdHotPath(int baseVReg, Identifier*, int valueVReg, unsigned propertyAccessInstructionIndex)
147 {
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.
151
152 emitGetVirtualRegisters(baseVReg, X86::eax, valueVReg, X86::edx);
153
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);
156
157 Label hotPathBegin(this);
158 m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin;
159
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);
164
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);
169 }
170
171 void JIT::compilePutByIdSlowCase(int baseVReg, Identifier* ident, int, Vector<SlowCaseEntry>::iterator& iter, unsigned propertyAccessInstructionIndex)
172 {
173 linkSlowCaseIfNotJSCell(iter, baseVReg);
174 linkSlowCase(iter);
175
176 emitPutJITStubArgConstant(ident, 2);
177 emitPutJITStubArg(X86::eax, 1);
178 emitPutJITStubArg(X86::edx, 3);
179 Jump call = emitCTICall(Interpreter::cti_op_put_by_id);
180
181 // Track the location of the call; this will be used to recover patch information.
182 m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
183 }
184
185 static JSObject* resizePropertyStorage(JSObject* baseObject, int32_t oldSize, int32_t newSize)
186 {
187 baseObject->allocatePropertyStorage(oldSize, newSize);
188 return baseObject;
189 }
190
191 static inline bool transitionWillNeedStorageRealloc(Structure* oldStructure, Structure* newStructure)
192 {
193 return oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity();
194 }
195
196 void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, void* returnAddress)
197 {
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;
203
204 // ecx = baseObject
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)));
208
209 loadPtr(Address(X86::ecx, FIELD_OFFSET(Structure, m_prototype)), X86::ecx);
210
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()))));
215
216 // Check the structure id
217 failureCases.append(jnePtr(Address(X86::ecx, FIELD_OFFSET(JSCell, m_structure)), ImmPtr(it->get())));
218
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);
222 }
223
224 successCases.link(this);
225
226 Jump callTarget;
227
228 // emit a call only if storage realloc is needed
229 if (transitionWillNeedStorageRealloc(oldStructure, newStructure)) {
230 pop(X86::ebx);
231 #if PLATFORM(X86_64)
232 move(Imm32(newStructure->propertyStorageCapacity()), X86::edx);
233 move(Imm32(oldStructure->propertyStorageCapacity()), X86::esi);
234 move(X86::eax, X86::edi);
235 callTarget = call();
236 #else
237 push(Imm32(newStructure->propertyStorageCapacity()));
238 push(Imm32(oldStructure->propertyStorageCapacity()));
239 push(X86::eax);
240 callTarget = call();
241 addPtr(Imm32(3 * sizeof(void*)), X86::esp);
242 #endif
243 emitGetJITStubArg(3, X86::edx);
244 push(X86::ebx);
245 }
246
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)));
252
253 // write the value
254 loadPtr(Address(X86::eax, FIELD_OFFSET(JSObject, m_propertyStorage)), X86::eax);
255 storePtr(X86::edx, Address(X86::eax, cachedOffset * sizeof(JSValuePtr)));
256
257 ret();
258
259 Jump failureJump;
260 bool plantedFailureJump = false;
261 if (!failureCases.empty()) {
262 failureCases.link(this);
263 restoreArgumentReferenceForTrampoline();
264 failureJump = jump();
265 plantedFailureJump = true;
266 }
267
268 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
269 PatchBuffer patchBuffer(code);
270
271 if (plantedFailureJump)
272 patchBuffer.link(failureJump, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail));
273
274 if (transitionWillNeedStorageRealloc(oldStructure, newStructure))
275 patchBuffer.link(callTarget, reinterpret_cast<void*>(resizePropertyStorage));
276
277 stubInfo->stubRoutine = code;
278
279 Jump::patch(returnAddress, code);
280 }
281
282 void JIT::patchGetByIdSelf(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
283 {
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));
287
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));
293 }
294
295 void JIT::patchPutByIdReplace(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
296 {
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));
300
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));
306 }
307
308 void JIT::privateCompilePatchGetArrayLength(void* returnAddress)
309 {
310 StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress);
311
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));
314
315 // Check eax is an array
316 Jump failureCases1 = jnePtr(Address(X86::eax), ImmPtr(m_interpreter->m_jsArrayVptr));
317
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);
321
322 Jump failureCases2 = ja32(X86::ecx, Imm32(JSImmediate::maxImmediateInt));
323
324 emitFastArithIntToImmNoCheck(X86::ecx, X86::eax);
325 Jump success = jump();
326
327 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
328 PatchBuffer patchBuffer(code);
329
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);
334
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);
338
339 // Track the stub we have created so that it will be deleted later.
340 stubInfo->stubRoutine = code;
341
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);
345 }
346
347 void JIT::privateCompileGetByIdSelf(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
348 {
349 // Check eax is an object of the right Structure.
350 Jump failureCases1 = emitJumpIfNotJSCell(X86::eax);
351 Jump failureCases2 = checkStructure(X86::eax, structure);
352
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);
356 ret();
357
358 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
359 PatchBuffer patchBuffer(code);
360
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));
363
364 stubInfo->stubRoutine = code;
365
366 Jump::patch(returnAddress, code);
367 }
368
369 void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, void* returnAddress, CallFrame* callFrame)
370 {
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));
374
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);
380
381 // Check eax is an object of the right Structure.
382 Jump failureCases1 = checkStructure(X86::eax, structure);
383
384 // Check the prototype object's Structure had not changed.
385 Structure** prototypeStructureAddress = &(protoObject->m_structure);
386 #if PLATFORM(X86_64)
387 move(ImmPtr(prototypeStructure), X86::ebx);
388 Jump failureCases2 = jnePtr(X86::ebx, AbsoluteAddress(prototypeStructureAddress));
389 #else
390 Jump failureCases2 = jnePtr(AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
391 #endif
392
393 // Checks out okay! - getDirectOffset
394 loadPtr(Address(X86::edx, cachedOffset * sizeof(JSValuePtr)), X86::eax);
395
396 Jump success = jump();
397
398 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
399 PatchBuffer patchBuffer(code);
400
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);
405
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));
409
410 // Track the stub we have created so that it will be deleted later.
411 stubInfo->stubRoutine = code;
412
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);
416 #else
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);
422
423 // Check eax is an object of the right Structure.
424 Jump failureCases1 = emitJumpIfNotJSCell(X86::eax);
425 Jump failureCases2 = checkStructure(X86::eax, structure);
426
427 // Check the prototype object's Structure had not changed.
428 Structure** prototypeStructureAddress = &(protoObject->m_structure);
429 Jump failureCases3 = jnePtr(AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
430
431 // Checks out okay! - getDirectOffset
432 loadPtr(Address(X86::edx, cachedOffset * sizeof(JSValuePtr)), X86::eax);
433
434 ret();
435
436 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
437 PatchBuffer patchBuffer(code);
438
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));
442
443 stubInfo->stubRoutine = code;
444
445 Jump::patch(returnAddress, code);
446 #endif
447 }
448
449 #if USE(CTI_REPATCH_PIC)
450 void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, size_t cachedOffset)
451 {
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();
456
457 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
458 ASSERT(code);
459 PatchBuffer patchBuffer(code);
460
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;
463 if (!lastProtoBegin)
464 lastProtoBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - patchOffsetGetByIdSlowCaseCall;
465
466 patchBuffer.link(failureCase, lastProtoBegin);
467
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));
471
472 structure->ref();
473 polymorphicStructures->list[currentIndex].set(code, structure);
474
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);
478 }
479
480 void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame)
481 {
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);
487
488 // Check eax is an object of the right Structure.
489 Jump failureCases1 = checkStructure(X86::eax, structure);
490
491 // Check the prototype object's Structure had not changed.
492 Structure** prototypeStructureAddress = &(protoObject->m_structure);
493 #if PLATFORM(X86_64)
494 move(ImmPtr(prototypeStructure), X86::ebx);
495 Jump failureCases2 = jnePtr(X86::ebx, AbsoluteAddress(prototypeStructureAddress));
496 #else
497 Jump failureCases2 = jnePtr(AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
498 #endif
499
500 // Checks out okay! - getDirectOffset
501 loadPtr(Address(X86::edx, cachedOffset * sizeof(JSValuePtr)), X86::eax);
502
503 Jump success = jump();
504
505 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
506 PatchBuffer patchBuffer(code);
507
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);
512
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));
516
517 structure->ref();
518 prototypeStructure->ref();
519 prototypeStructures->list[currentIndex].set(code, structure, prototypeStructure);
520
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);
524 }
525
526 void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, CallFrame* callFrame)
527 {
528 ASSERT(count);
529
530 JumpList bucketsOfFail;
531
532 // Check eax is an object of the right Structure.
533 Jump baseObjectCheck = checkStructure(X86::eax, structure);
534 bucketsOfFail.append(baseObjectCheck);
535
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();
542
543 // Check the prototype object's Structure had not changed.
544 Structure** prototypeStructureAddress = &(protoObject->m_structure);
545 #if PLATFORM(X86_64)
546 move(ImmPtr(currStructure), X86::ebx);
547 bucketsOfFail.append(jnePtr(X86::ebx, AbsoluteAddress(prototypeStructureAddress)));
548 #else
549 bucketsOfFail.append(jnePtr(AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
550 #endif
551 }
552 ASSERT(protoObject);
553
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();
558
559 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
560 PatchBuffer patchBuffer(code);
561
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;
564
565 patchBuffer.link(bucketsOfFail, lastProtoBegin);
566
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));
570
571 // Track the stub we have created so that it will be deleted later.
572 structure->ref();
573 chain->ref();
574 prototypeStructures->list[currentIndex].set(code, structure, chain);
575
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);
579 }
580 #endif
581
582 void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame)
583 {
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));
587
588 ASSERT(count);
589
590 JumpList bucketsOfFail;
591
592 // Check eax is an object of the right Structure.
593 bucketsOfFail.append(checkStructure(X86::eax, structure));
594
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();
601
602 // Check the prototype object's Structure had not changed.
603 Structure** prototypeStructureAddress = &(protoObject->m_structure);
604 #if PLATFORM(X86_64)
605 move(ImmPtr(currStructure), X86::ebx);
606 bucketsOfFail.append(jnePtr(X86::ebx, AbsoluteAddress(prototypeStructureAddress)));
607 #else
608 bucketsOfFail.append(jnePtr(AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
609 #endif
610 }
611 ASSERT(protoObject);
612
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();
617
618 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
619 PatchBuffer patchBuffer(code);
620
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;
623
624 patchBuffer.link(bucketsOfFail, slowCaseBegin);
625
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));
629
630 // Track the stub we have created so that it will be deleted later.
631 stubInfo->stubRoutine = code;
632
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);
636 #else
637 ASSERT(count);
638
639 JumpList bucketsOfFail;
640
641 // Check eax is an object of the right Structure.
642 bucketsOfFail.append(emitJumpIfNotJSCell(X86::eax));
643 bucketsOfFail.append(checkStructure(X86::eax, structure));
644
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();
651
652 // Check the prototype object's Structure had not changed.
653 Structure** prototypeStructureAddress = &(protoObject->m_structure);
654 #if PLATFORM(X86_64)
655 move(ImmPtr(currStructure), X86::ebx);
656 bucketsOfFail.append(jnePtr(X86::ebx, AbsoluteAddress(prototypeStructureAddress)));
657 #else
658 bucketsOfFail.append(jnePtr(AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
659 #endif
660 }
661 ASSERT(protoObject);
662
663 PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
664 loadPtr(protoPropertyStorage, X86::edx);
665 loadPtr(Address(X86::edx, cachedOffset * sizeof(JSValuePtr)), X86::eax);
666 ret();
667
668 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
669
670 patchBuffer.link(bucketsOfFail, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
671
672 stubInfo->stubRoutine = code;
673
674 Jump::patch(returnAddress, code);
675 #endif
676 }
677
678 void JIT::privateCompilePutByIdReplace(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
679 {
680 // Check eax is an object of the right Structure.
681 Jump failureCases1 = emitJumpIfNotJSCell(X86::eax);
682 Jump failureCases2 = checkStructure(X86::eax, structure);
683
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)));
687 ret();
688
689 void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
690 PatchBuffer patchBuffer(code);
691
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));
694
695 stubInfo->stubRoutine = code;
696
697 Jump::patch(returnAddress, code);
698 }
699
700 #endif
701
702 } // namespace JSC
703
704 #endif // ENABLE(JIT)
705