574214b238b1d3b66aff98f9452cc2d58f244f2c
[WebKit-https.git] / JavaScriptCore / jit / JITPropertyAccess.cpp
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
49 void JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier* ident, unsigned i, unsigned propertyAccessInstructionIndex)
50 {
51     // As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be repatched.
52     // Additionally, for get_by_id we need repatch the offset of the branch to the slow case (we repatch 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, i);
57
58 #ifdef NDEBUG
59     UNUSED_PARAM(propertyAccessInstructionIndex);
60 #endif
61     ASSERT(m_codeBlock->propertyAccessInstruction(propertyAccessInstructionIndex).bytecodeIndex == i);
62
63 #ifndef NDEBUG
64     JmpDst coldPathBegin = __ label();
65 #endif        
66     emitPutCTIArg(X86::eax, 0);
67     emitPutCTIArgConstant(reinterpret_cast<unsigned>(ident), 4);
68     JmpSrc call = emitCTICall(i, Interpreter::cti_op_get_by_id_generic);
69     ASSERT(X86Assembler::getDifferenceBetweenLabels(coldPathBegin, call) == repatchOffsetGetByIdSlowCaseCall);
70     emitPutVirtualRegister(resultVReg);
71
72     // Track the location of the call; this will be used to recover repatch information.
73     ASSERT(m_codeBlock->propertyAccessInstruction(propertyAccessInstructionIndex).bytecodeIndex == i);
74     m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
75 }
76
77
78 void JIT::compileGetByIdSlowCase(int, int, Identifier*, unsigned, Vector<SlowCaseEntry>::iterator&, unsigned)
79 {
80     ASSERT_NOT_REACHED();
81 }
82
83 void JIT::compilePutByIdHotPath(int baseVReg, Identifier* ident, int valueVReg, unsigned i, unsigned propertyAccessInstructionIndex)
84 {
85     // In order to be able to repatch both the Structure, and the object offset, we store one pointer,
86     // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code
87     // such that the Structure & offset are always at the same distance from this.
88
89     emitGetVirtualRegisters(baseVReg, X86::eax, valueVReg, X86::edx, i);
90
91     emitPutCTIArgConstant(reinterpret_cast<unsigned>(ident), 4);
92     emitPutCTIArg(X86::eax, 0);
93     emitPutCTIArg(X86::edx, 8);
94     JmpSrc call = emitCTICall(i, Interpreter::cti_op_put_by_id_generic);
95
96     // Track the location of the call; this will be used to recover repatch information.
97     ASSERT(m_codeBlock->propertyAccessInstruction(propertyAccessInstructionIndex).bytecodeIndex == i);
98     m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
99 }
100
101 void JIT::compilePutByIdSlowCase(int, Identifier*, int, unsigned, Vector<SlowCaseEntry>::iterator&, unsigned)
102 {
103     ASSERT_NOT_REACHED();
104 }
105
106 #else
107
108 void JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier*, unsigned i, unsigned propertyAccessInstructionIndex)
109 {
110     // As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be repatched.
111     // Additionally, for get_by_id we need repatch the offset of the branch to the slow case (we repatch this to jump
112     // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label
113     // to jump back to if one of these trampolies finds a match.
114
115     emitGetVirtualRegister(baseVReg, X86::eax, i);
116
117     ASSERT(m_codeBlock->propertyAccessInstruction(propertyAccessInstructionIndex).bytecodeIndex == i);
118
119     emitJumpSlowCaseIfNotJSCell(X86::eax, i, baseVReg);
120
121     JmpDst hotPathBegin = __ label();
122     m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin;
123
124     __ cmpl_i32m(repatchGetByIdDefaultStructure, FIELD_OFFSET(JSCell, m_structure), X86::eax);
125     ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetGetByIdStructure);
126     m_slowCases.append(SlowCaseEntry(__ jne(), i));
127     ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetGetByIdBranchToSlowCase);
128
129     __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
130     __ movl_mr(repatchGetByIdDefaultOffset, X86::eax, X86::eax);
131     ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetGetByIdPropertyMapOffset);
132     emitPutVirtualRegister(resultVReg);
133 }
134
135
136 void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, unsigned i, Vector<SlowCaseEntry>::iterator& iter, unsigned propertyAccessInstructionIndex)
137 {
138     // As for the hot path of get_by_id, above, we ensure that we can use an architecture specific offset
139     // so that we only need track one pointer into the slow case code - we track a pointer to the location
140     // of the call (which we can use to look up the repatch information), but should a array-length or
141     // prototype access trampoline fail we want to bail out back to here.  To do so we can subtract back
142     // the distance from the call to the head of the slow case.
143
144     if (linkSlowCaseIfNotJSCell(iter, baseVReg))
145         ++iter;
146     __ link(iter->from, __ label());
147
148 #ifndef NDEBUG
149     JmpDst coldPathBegin = __ label();
150 #endif
151     emitPutCTIArg(X86::eax, 0);
152     emitPutCTIArgConstant(reinterpret_cast<unsigned>(ident), 4);
153     JmpSrc call = emitCTICall(i, Interpreter::cti_op_get_by_id);
154     ASSERT(X86Assembler::getDifferenceBetweenLabels(coldPathBegin, call) == repatchOffsetGetByIdSlowCaseCall);
155     emitPutVirtualRegister(resultVReg);
156
157     // Track the location of the call; this will be used to recover repatch information.
158     ASSERT(m_codeBlock->propertyAccessInstruction(propertyAccessInstructionIndex).bytecodeIndex == i);
159     m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
160 }
161
162 void JIT::compilePutByIdHotPath(int baseVReg, Identifier*, int valueVReg, unsigned i, unsigned propertyAccessInstructionIndex)
163 {
164     // In order to be able to repatch both the Structure, and the object offset, we store one pointer,
165     // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code
166     // such that the Structure & offset are always at the same distance from this.
167
168     emitGetVirtualRegisters(baseVReg, X86::eax, valueVReg, X86::edx, i);
169
170     ASSERT(m_codeBlock->propertyAccessInstruction(propertyAccessInstructionIndex).bytecodeIndex == i);
171
172     // Jump to a slow case if either the base object is an immediate, or if the Structure does not match.
173     emitJumpSlowCaseIfNotJSCell(X86::eax, i, baseVReg);
174
175     JmpDst hotPathBegin = __ label();
176     m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin;
177
178     // It is important that the following instruction plants a 32bit immediate, in order that it can be patched over.
179     __ cmpl_i32m(repatchGetByIdDefaultStructure, FIELD_OFFSET(JSCell, m_structure), X86::eax);
180     ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetPutByIdStructure);
181     m_slowCases.append(SlowCaseEntry(__ jne(), i));
182
183     // Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used.
184     __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
185     __ movl_rm(X86::edx, repatchGetByIdDefaultOffset, X86::eax);
186     ASSERT(X86Assembler::getDifferenceBetweenLabels(hotPathBegin, __ label()) == repatchOffsetPutByIdPropertyMapOffset);
187 }
188
189 void JIT::compilePutByIdSlowCase(int baseVReg, Identifier* ident, int, unsigned i, Vector<SlowCaseEntry>::iterator& iter, unsigned propertyAccessInstructionIndex)
190 {
191     if (linkSlowCaseIfNotJSCell(iter, baseVReg))
192         ++iter;
193     __ link(iter->from, __ label());
194
195     emitPutCTIArgConstant(reinterpret_cast<unsigned>(ident), 4);
196     emitPutCTIArg(X86::eax, 0);
197     emitPutCTIArg(X86::edx, 8);
198     JmpSrc call = emitCTICall(i, Interpreter::cti_op_put_by_id);
199
200     // Track the location of the call; this will be used to recover repatch information.
201     ASSERT(m_codeBlock->propertyAccessInstruction(propertyAccessInstructionIndex).bytecodeIndex == i);
202     m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
203 }
204
205 #endif
206
207 static JSObject* resizePropertyStorage(JSObject* baseObject, size_t oldSize, size_t newSize)
208 {
209     baseObject->allocatePropertyStorageInline(oldSize, newSize);
210     return baseObject;
211 }
212
213 static inline bool transitionWillNeedStorageRealloc(Structure* oldStructure, Structure* newStructure)
214 {
215     return oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity();
216 }
217
218 void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, void* returnAddress)
219 {
220     Vector<JmpSrc, 16> failureCases;
221     // Check eax is an object of the right Structure.
222     __ testl_i32r(JSImmediate::TagMask, X86::eax);
223     failureCases.append(__ jne());
224     __ cmpl_i32m(reinterpret_cast<uint32_t>(oldStructure), FIELD_OFFSET(JSCell, m_structure), X86::eax);
225     failureCases.append(__ jne());
226     Vector<JmpSrc> successCases;
227
228     //  ecx = baseObject
229     __ movl_mr(FIELD_OFFSET(JSCell, m_structure), X86::eax, X86::ecx);
230     // proto(ecx) = baseObject->structure()->prototype()
231     __ cmpl_i32m(ObjectType, FIELD_OFFSET(Structure, m_typeInfo) + FIELD_OFFSET(TypeInfo, m_type), X86::ecx);
232     failureCases.append(__ jne());
233     __ movl_mr(FIELD_OFFSET(Structure, m_prototype), X86::ecx, X86::ecx);
234     
235     // ecx = baseObject->m_structure
236     for (RefPtr<Structure>* it = chain->head(); *it; ++it) {
237         // null check the prototype
238         __ cmpl_i32r(asInteger(jsNull()), X86::ecx);
239         successCases.append(__ je());
240
241         // Check the structure id
242         __ cmpl_i32m(reinterpret_cast<uint32_t>(it->get()), FIELD_OFFSET(JSCell, m_structure), X86::ecx);
243         failureCases.append(__ jne());
244         
245         __ movl_mr(FIELD_OFFSET(JSCell, m_structure), X86::ecx, X86::ecx);
246         __ cmpl_i32m(ObjectType, FIELD_OFFSET(Structure, m_typeInfo) + FIELD_OFFSET(TypeInfo, m_type), X86::ecx);
247         failureCases.append(__ jne());
248         __ movl_mr(FIELD_OFFSET(Structure, m_prototype), X86::ecx, X86::ecx);
249     }
250
251     failureCases.append(__ jne());
252     for (unsigned i = 0; i < successCases.size(); ++i)
253         __ link(successCases[i], __ label());
254
255     JmpSrc callTarget;
256
257     // emit a call only if storage realloc is needed
258     if (transitionWillNeedStorageRealloc(oldStructure, newStructure)) {
259         __ pushl_r(X86::edx);
260         __ pushl_i32(newStructure->propertyStorageCapacity());
261         __ pushl_i32(oldStructure->propertyStorageCapacity());
262         __ pushl_r(X86::eax);
263         callTarget = __ call();
264         __ addl_i32r(3 * sizeof(void*), X86::esp);
265         __ popl_r(X86::edx);
266     }
267
268     // Assumes m_refCount can be decremented easily, refcount decrement is safe as 
269     // codeblock should ensure oldStructure->m_refCount > 0
270     __ subl_i8m(1, reinterpret_cast<void*>(oldStructure));
271     __ addl_i8m(1, reinterpret_cast<void*>(newStructure));
272     __ movl_i32m(reinterpret_cast<uint32_t>(newStructure), FIELD_OFFSET(JSCell, m_structure), X86::eax);
273
274     // write the value
275     __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
276     __ movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
277
278     __ ret();
279     
280     JmpSrc failureJump;
281     if (failureCases.size()) {
282         for (unsigned i = 0; i < failureCases.size(); ++i)
283             __ link(failureCases[i], __ label());
284         restoreArgumentReferenceForTrampoline();
285         failureJump = __ jmp();
286     }
287
288     void* code = __ executableCopy(m_codeBlock->executablePool());
289
290     if (failureCases.size())
291         X86Assembler::link(code, failureJump, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail));
292
293     if (transitionWillNeedStorageRealloc(oldStructure, newStructure))
294         X86Assembler::link(code, callTarget, reinterpret_cast<void*>(resizePropertyStorage));
295     
296     stubInfo->stubRoutine = code;
297     
298     ctiRepatchCallByReturnAddress(returnAddress, code);
299 }
300
301 void JIT::patchGetByIdSelf(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
302 {
303     // We don't want to repatch more than once - in future go to cti_op_get_by_id_generic.
304     // Should probably go to Interpreter::cti_op_get_by_id_fail, but that doesn't do anything interesting right now.
305     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail));
306
307     // Repatch the offset into the propoerty map to load from, then repatch the Structure to look for.
308     X86Assembler::repatchDisplacement(reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset, cachedOffset * sizeof(JSValue*));
309     X86Assembler::repatchImmediate(reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdStructure, reinterpret_cast<uint32_t>(structure));
310 }
311
312 void JIT::patchPutByIdReplace(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
313 {
314     // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
315     // Should probably go to Interpreter::cti_op_put_by_id_fail, but that doesn't do anything interesting right now.
316     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_generic));
317
318     // Repatch the offset into the propoerty map to load from, then repatch the Structure to look for.
319     X86Assembler::repatchDisplacement(reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetPutByIdPropertyMapOffset, cachedOffset * sizeof(JSValue*));
320     X86Assembler::repatchImmediate(reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetPutByIdStructure, reinterpret_cast<uint32_t>(structure));
321 }
322
323 void JIT::privateCompilePatchGetArrayLength(void* returnAddress)
324 {
325     StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress);
326
327     // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
328     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_array_fail));
329
330     // Check eax is an array
331     __ cmpl_i32m(reinterpret_cast<unsigned>(m_interpreter->m_jsArrayVptr), X86::eax);
332     JmpSrc failureCases1 = __ jne();
333
334     // Checks out okay! - get the length from the storage
335     __ movl_mr(FIELD_OFFSET(JSArray, m_storage), X86::eax, X86::ecx);
336     __ movl_mr(FIELD_OFFSET(ArrayStorage, m_length), X86::ecx, X86::ecx);
337
338     __ cmpl_i32r(JSImmediate::maxImmediateInt, X86::ecx);
339     JmpSrc failureCases2 = __ ja();
340
341     __ addl_rr(X86::ecx, X86::ecx);
342     __ addl_i8r(1, X86::ecx);
343     __ movl_rr(X86::ecx, X86::eax);
344     JmpSrc success = __ jmp();
345
346     void* code = __ executableCopy(m_codeBlock->executablePool());
347
348     // Use the repatch information to link the failure cases back to the original slow case routine.
349     void* slowCaseBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
350     X86Assembler::link(code, failureCases1, slowCaseBegin);
351     X86Assembler::link(code, failureCases2, slowCaseBegin);
352
353     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
354     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
355     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
356
357     // Track the stub we have created so that it will be deleted later.
358     stubInfo->stubRoutine = code;
359
360     // Finally repatch the jump to sow case back in the hot path to jump here instead.
361     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
362     X86Assembler::repatchBranchOffset(jmpLocation, code);
363 }
364
365 void JIT::privateCompileGetByIdSelf(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
366 {
367     // Check eax is an object of the right Structure.
368     __ testl_i32r(JSImmediate::TagMask, X86::eax);
369     JmpSrc failureCases1 = __ jne();
370     JmpSrc failureCases2 = checkStructure(X86::eax, structure);
371
372     // Checks out okay! - getDirectOffset
373     __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
374     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::eax, X86::eax);
375     __ ret();
376
377     void* code = __ executableCopy(m_codeBlock->executablePool());
378
379     X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail));
380     X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail));
381
382     stubInfo->stubRoutine = code;
383
384     ctiRepatchCallByReturnAddress(returnAddress, code);
385 }
386
387 void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, void* returnAddress, CallFrame* callFrame)
388 {
389 #if USE(CTI_REPATCH_PIC)
390     // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
391     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list));
392
393     // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
394     // referencing the prototype object - let's speculatively load it's table nice and early!)
395     JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
396     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
397     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
398
399     // Check eax is an object of the right Structure.
400     JmpSrc failureCases1 = checkStructure(X86::eax, structure);
401
402     // Check the prototype object's Structure had not changed.
403     Structure** prototypeStructureAddress = &(protoObject->m_structure);
404     __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
405     JmpSrc failureCases2 = __ jne();
406
407     // Checks out okay! - getDirectOffset
408     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
409
410     JmpSrc success = __ jmp();
411
412     void* code = __ executableCopy(m_codeBlock->executablePool());
413
414     // Use the repatch information to link the failure cases back to the original slow case routine.
415     void* slowCaseBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
416     X86Assembler::link(code, failureCases1, slowCaseBegin);
417     X86Assembler::link(code, failureCases2, slowCaseBegin);
418
419     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
420     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
421     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
422
423     // Track the stub we have created so that it will be deleted later.
424     stubInfo->stubRoutine = code;
425
426     // Finally repatch the jump to slow case back in the hot path to jump here instead.
427     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
428     X86Assembler::repatchBranchOffset(jmpLocation, code);
429 #else
430     // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
431     // referencing the prototype object - let's speculatively load it's table nice and early!)
432     JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
433     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
434     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
435
436     // Check eax is an object of the right Structure.
437     __ testl_i32r(JSImmediate::TagMask, X86::eax);
438     JmpSrc failureCases1 = __ jne();
439     JmpSrc failureCases2 = checkStructure(X86::eax, structure);
440
441     // Check the prototype object's Structure had not changed.
442     Structure** prototypeStructureAddress = &(protoObject->m_structure);
443     __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
444     JmpSrc failureCases3 = __ jne();
445
446     // Checks out okay! - getDirectOffset
447     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
448
449     __ ret();
450
451     void* code = __ executableCopy(m_codeBlock->executablePool());
452
453     X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
454     X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
455     X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
456
457     stubInfo->stubRoutine = code;
458
459     ctiRepatchCallByReturnAddress(returnAddress, code);
460 #endif
461 }
462
463 #if USE(CTI_REPATCH_PIC)
464 void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, size_t cachedOffset)
465 {
466     JmpSrc failureCase = checkStructure(X86::eax, structure);
467     __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
468     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::eax, X86::eax);
469     JmpSrc success = __ jmp();
470
471     void* code = __ executableCopy(m_codeBlock->executablePool());
472     ASSERT(code);
473
474     // Use the repatch information to link the failure cases back to the original slow case routine.
475     void* lastProtoBegin = polymorphicStructures->list[currentIndex - 1].stubRoutine;
476     if (!lastProtoBegin)
477         lastProtoBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
478
479     X86Assembler::link(code, failureCase, lastProtoBegin);
480
481     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
482     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
483     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
484
485     structure->ref();
486     polymorphicStructures->list[currentIndex].set(cachedOffset, code, structure);
487
488     // Finally repatch the jump to slow case back in the hot path to jump here instead.
489     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
490     X86Assembler::repatchBranchOffset(jmpLocation, code);
491 }
492
493 void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame)
494 {
495     // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
496     // referencing the prototype object - let's speculatively load it's table nice and early!)
497     JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
498     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
499     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
500
501     // Check eax is an object of the right Structure.
502     JmpSrc failureCases1 = checkStructure(X86::eax, structure);
503
504     // Check the prototype object's Structure had not changed.
505     Structure** prototypeStructureAddress = &(protoObject->m_structure);
506     __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
507     JmpSrc failureCases2 = __ jne();
508
509     // Checks out okay! - getDirectOffset
510     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
511
512     JmpSrc success = __ jmp();
513
514     void* code = __ executableCopy(m_codeBlock->executablePool());
515
516     // Use the repatch information to link the failure cases back to the original slow case routine.
517     void* lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine;
518     X86Assembler::link(code, failureCases1, lastProtoBegin);
519     X86Assembler::link(code, failureCases2, lastProtoBegin);
520
521     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
522     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
523     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
524
525     structure->ref();
526     prototypeStructure->ref();
527     prototypeStructures->list[currentIndex].set(cachedOffset, code, structure, prototypeStructure);
528
529     // Finally repatch the jump to slow case back in the hot path to jump here instead.
530     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
531     X86Assembler::repatchBranchOffset(jmpLocation, code);
532 }
533
534 void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, CallFrame* callFrame)
535 {
536     ASSERT(count);
537     
538     Vector<JmpSrc> bucketsOfFail;
539
540     // Check eax is an object of the right Structure.
541     bucketsOfFail.append(checkStructure(X86::eax, structure));
542
543     Structure* currStructure = structure;
544     RefPtr<Structure>* chainEntries = chain->head();
545     JSObject* protoObject = 0;
546     for (unsigned i = 0; i < count; ++i) {
547         protoObject = asObject(currStructure->prototypeForLookup(callFrame));
548         currStructure = chainEntries[i].get();
549
550         // Check the prototype object's Structure had not changed.
551         Structure** prototypeStructureAddress = &(protoObject->m_structure);
552         __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), prototypeStructureAddress);
553         bucketsOfFail.append(__ jne());
554     }
555     ASSERT(protoObject);
556
557     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
558     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
559     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
560     JmpSrc success = __ jmp();
561
562     void* code = __ executableCopy(m_codeBlock->executablePool());
563
564     // Use the repatch information to link the failure cases back to the original slow case routine.
565     void* lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine;
566
567     for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
568         X86Assembler::link(code, bucketsOfFail[i], lastProtoBegin);
569
570     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
571     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
572     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
573
574     // Track the stub we have created so that it will be deleted later.
575     structure->ref();
576     chain->ref();
577     prototypeStructures->list[currentIndex].set(cachedOffset, code, structure, chain);
578
579     // Finally repatch the jump to slow case back in the hot path to jump here instead.
580     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
581     X86Assembler::repatchBranchOffset(jmpLocation, code);
582 }
583 #endif
584
585 void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame)
586 {
587 #if USE(CTI_REPATCH_PIC)
588     // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
589     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list));
590
591     ASSERT(count);
592     
593     Vector<JmpSrc> bucketsOfFail;
594
595     // Check eax is an object of the right Structure.
596     bucketsOfFail.append(checkStructure(X86::eax, structure));
597
598     Structure* currStructure = structure;
599     RefPtr<Structure>* chainEntries = chain->head();
600     JSObject* protoObject = 0;
601     for (unsigned i = 0; i < count; ++i) {
602         protoObject = asObject(currStructure->prototypeForLookup(callFrame));
603         currStructure = chainEntries[i].get();
604
605         // Check the prototype object's Structure had not changed.
606         Structure** prototypeStructureAddress = &(protoObject->m_structure);
607         __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), prototypeStructureAddress);
608         bucketsOfFail.append(__ jne());
609     }
610     ASSERT(protoObject);
611
612     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
613     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
614     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
615     JmpSrc success = __ jmp();
616
617     void* code = __ executableCopy(m_codeBlock->executablePool());
618
619     // Use the repatch information to link the failure cases back to the original slow case routine.
620     void* slowCaseBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
621
622     for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
623         X86Assembler::link(code, bucketsOfFail[i], slowCaseBegin);
624
625     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
626     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
627     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
628
629     // Track the stub we have created so that it will be deleted later.
630     stubInfo->stubRoutine = code;
631
632     // Finally repatch the jump to slow case back in the hot path to jump here instead.
633     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
634     X86Assembler::repatchBranchOffset(jmpLocation, code);
635 #else
636     ASSERT(count);
637     
638     Vector<JmpSrc> bucketsOfFail;
639
640     // Check eax is an object of the right Structure.
641     __ testl_i32r(JSImmediate::TagMask, X86::eax);
642     bucketsOfFail.append(__ jne());
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         __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), prototypeStructureAddress);
655         bucketsOfFail.append(__ jne());
656     }
657     ASSERT(protoObject);
658
659     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
660     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
661     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
662     __ ret();
663
664     void* code = __ executableCopy(m_codeBlock->executablePool());
665
666     for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
667         X86Assembler::link(code, bucketsOfFail[i], reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
668
669     stubInfo->stubRoutine = code;
670
671     ctiRepatchCallByReturnAddress(returnAddress, code);
672 #endif
673 }
674
675 void JIT::privateCompilePutByIdReplace(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
676 {
677     // Check eax is an object of the right Structure.
678     __ testl_i32r(JSImmediate::TagMask, X86::eax);
679     JmpSrc failureCases1 = __ jne();
680     JmpSrc failureCases2 = checkStructure(X86::eax, structure);
681
682     // checks out okay! - putDirectOffset
683     __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
684     __ movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
685     __ ret();
686
687     void* code = __ executableCopy(m_codeBlock->executablePool());
688     
689     X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail));
690     X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail));
691
692     stubInfo->stubRoutine = code;
693     
694     ctiRepatchCallByReturnAddress(returnAddress, code);
695 }
696
697 } // namespace JSC
698
699 #endif // ENABLE(JIT)