2008-12-11 Gavin Barraclough <barraclough@apple.com>
[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         failureJump = __ jmp();
285     }
286
287     void* code = __ executableCopy(m_codeBlock->executablePool());
288
289     if (failureCases.size())
290         X86Assembler::link(code, failureJump, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail));
291
292     if (transitionWillNeedStorageRealloc(oldStructure, newStructure))
293         X86Assembler::link(code, callTarget, reinterpret_cast<void*>(resizePropertyStorage));
294     
295     stubInfo->stubRoutine = code;
296     
297     ctiRepatchCallByReturnAddress(returnAddress, code);
298 }
299
300 void JIT::patchGetByIdSelf(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
301 {
302     // We don't want to repatch more than once - in future go to cti_op_get_by_id_generic.
303     // Should probably go to Interpreter::cti_op_get_by_id_fail, but that doesn't do anything interesting right now.
304     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail));
305
306     // Repatch the offset into the propoerty map to load from, then repatch the Structure to look for.
307     X86Assembler::repatchDisplacement(reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset, cachedOffset * sizeof(JSValue*));
308     X86Assembler::repatchImmediate(reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdStructure, reinterpret_cast<uint32_t>(structure));
309 }
310
311 void JIT::patchPutByIdReplace(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
312 {
313     // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
314     // Should probably go to Interpreter::cti_op_put_by_id_fail, but that doesn't do anything interesting right now.
315     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_generic));
316
317     // Repatch the offset into the propoerty map to load from, then repatch the Structure to look for.
318     X86Assembler::repatchDisplacement(reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetPutByIdPropertyMapOffset, cachedOffset * sizeof(JSValue*));
319     X86Assembler::repatchImmediate(reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetPutByIdStructure, reinterpret_cast<uint32_t>(structure));
320 }
321
322 void JIT::privateCompilePatchGetArrayLength(void* returnAddress)
323 {
324     StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress);
325
326     // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
327     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_array_fail));
328
329     // Check eax is an array
330     __ cmpl_i32m(reinterpret_cast<unsigned>(m_interpreter->m_jsArrayVptr), X86::eax);
331     JmpSrc failureCases1 = __ jne();
332
333     // Checks out okay! - get the length from the storage
334     __ movl_mr(FIELD_OFFSET(JSArray, m_storage), X86::eax, X86::ecx);
335     __ movl_mr(FIELD_OFFSET(ArrayStorage, m_length), X86::ecx, X86::ecx);
336
337     __ cmpl_i32r(JSImmediate::maxImmediateInt, X86::ecx);
338     JmpSrc failureCases2 = __ ja();
339
340     __ addl_rr(X86::ecx, X86::ecx);
341     __ addl_i8r(1, X86::ecx);
342     __ movl_rr(X86::ecx, X86::eax);
343     JmpSrc success = __ jmp();
344
345     void* code = __ executableCopy(m_codeBlock->executablePool());
346
347     // Use the repatch information to link the failure cases back to the original slow case routine.
348     void* slowCaseBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
349     X86Assembler::link(code, failureCases1, slowCaseBegin);
350     X86Assembler::link(code, failureCases2, slowCaseBegin);
351
352     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
353     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
354     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
355
356     // Track the stub we have created so that it will be deleted later.
357     stubInfo->stubRoutine = code;
358
359     // Finally repatch the jump to sow case back in the hot path to jump here instead.
360     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
361     X86Assembler::repatchBranchOffset(jmpLocation, code);
362 }
363
364 void JIT::privateCompileGetByIdSelf(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
365 {
366     // Check eax is an object of the right Structure.
367     __ testl_i32r(JSImmediate::TagMask, X86::eax);
368     JmpSrc failureCases1 = __ jne();
369     JmpSrc failureCases2 = checkStructure(X86::eax, structure);
370
371     // Checks out okay! - getDirectOffset
372     __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
373     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::eax, X86::eax);
374     __ ret();
375
376     void* code = __ executableCopy(m_codeBlock->executablePool());
377
378     X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail));
379     X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_self_fail));
380
381     stubInfo->stubRoutine = code;
382
383     ctiRepatchCallByReturnAddress(returnAddress, code);
384 }
385
386 void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, void* returnAddress, CallFrame* callFrame)
387 {
388 #if USE(CTI_REPATCH_PIC)
389     // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
390     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list));
391
392     // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
393     // referencing the prototype object - let's speculatively load it's table nice and early!)
394     JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
395     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
396     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
397
398     // Check eax is an object of the right Structure.
399     JmpSrc failureCases1 = checkStructure(X86::eax, structure);
400
401     // Check the prototype object's Structure had not changed.
402     Structure** prototypeStructureAddress = &(protoObject->m_structure);
403     __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
404     JmpSrc failureCases2 = __ jne();
405
406     // Checks out okay! - getDirectOffset
407     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
408
409     JmpSrc success = __ jmp();
410
411     void* code = __ executableCopy(m_codeBlock->executablePool());
412
413     // Use the repatch information to link the failure cases back to the original slow case routine.
414     void* slowCaseBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
415     X86Assembler::link(code, failureCases1, slowCaseBegin);
416     X86Assembler::link(code, failureCases2, slowCaseBegin);
417
418     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
419     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
420     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
421
422     // Track the stub we have created so that it will be deleted later.
423     stubInfo->stubRoutine = code;
424
425     // Finally repatch the jump to slow case back in the hot path to jump here instead.
426     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
427     X86Assembler::repatchBranchOffset(jmpLocation, code);
428 #else
429     // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
430     // referencing the prototype object - let's speculatively load it's table nice and early!)
431     JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
432     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
433     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
434
435     // Check eax is an object of the right Structure.
436     __ testl_i32r(JSImmediate::TagMask, X86::eax);
437     JmpSrc failureCases1 = __ jne();
438     JmpSrc failureCases2 = checkStructure(X86::eax, structure);
439
440     // Check the prototype object's Structure had not changed.
441     Structure** prototypeStructureAddress = &(protoObject->m_structure);
442     __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
443     JmpSrc failureCases3 = __ jne();
444
445     // Checks out okay! - getDirectOffset
446     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
447
448     __ ret();
449
450     void* code = __ executableCopy(m_codeBlock->executablePool());
451
452     X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
453     X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
454     X86Assembler::link(code, failureCases3, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
455
456     stubInfo->stubRoutine = code;
457
458     ctiRepatchCallByReturnAddress(returnAddress, code);
459 #endif
460 }
461
462 #if USE(CTI_REPATCH_PIC)
463 void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, size_t cachedOffset)
464 {
465     JmpSrc failureCase = checkStructure(X86::eax, structure);
466     __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
467     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::eax, X86::eax);
468     JmpSrc success = __ jmp();
469
470     void* code = __ executableCopy(m_codeBlock->executablePool());
471     ASSERT(code);
472
473     // Use the repatch information to link the failure cases back to the original slow case routine.
474     void* lastProtoBegin = polymorphicStructures->list[currentIndex - 1].stubRoutine;
475     if (!lastProtoBegin)
476         lastProtoBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
477
478     X86Assembler::link(code, failureCase, lastProtoBegin);
479
480     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
481     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
482     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
483
484     structure->ref();
485     polymorphicStructures->list[currentIndex].set(cachedOffset, code, structure);
486
487     // Finally repatch the jump to slow case back in the hot path to jump here instead.
488     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
489     X86Assembler::repatchBranchOffset(jmpLocation, code);
490 }
491
492 void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame)
493 {
494     // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
495     // referencing the prototype object - let's speculatively load it's table nice and early!)
496     JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
497     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
498     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
499
500     // Check eax is an object of the right Structure.
501     JmpSrc failureCases1 = checkStructure(X86::eax, structure);
502
503     // Check the prototype object's Structure had not changed.
504     Structure** prototypeStructureAddress = &(protoObject->m_structure);
505     __ cmpl_i32m(reinterpret_cast<uint32_t>(prototypeStructure), prototypeStructureAddress);
506     JmpSrc failureCases2 = __ jne();
507
508     // Checks out okay! - getDirectOffset
509     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
510
511     JmpSrc success = __ jmp();
512
513     void* code = __ executableCopy(m_codeBlock->executablePool());
514
515     // Use the repatch information to link the failure cases back to the original slow case routine.
516     void* lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine;
517     X86Assembler::link(code, failureCases1, lastProtoBegin);
518     X86Assembler::link(code, failureCases2, lastProtoBegin);
519
520     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
521     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
522     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
523
524     structure->ref();
525     prototypeStructure->ref();
526     prototypeStructures->list[currentIndex].set(cachedOffset, code, structure, prototypeStructure);
527
528     // Finally repatch the jump to slow case back in the hot path to jump here instead.
529     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
530     X86Assembler::repatchBranchOffset(jmpLocation, code);
531 }
532
533 void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, CallFrame* callFrame)
534 {
535     ASSERT(count);
536     
537     Vector<JmpSrc> bucketsOfFail;
538
539     // Check eax is an object of the right Structure.
540     bucketsOfFail.append(checkStructure(X86::eax, structure));
541
542     Structure* currStructure = structure;
543     RefPtr<Structure>* chainEntries = chain->head();
544     JSObject* protoObject = 0;
545     for (unsigned i = 0; i < count; ++i) {
546         protoObject = asObject(currStructure->prototypeForLookup(callFrame));
547         currStructure = chainEntries[i].get();
548
549         // Check the prototype object's Structure had not changed.
550         Structure** prototypeStructureAddress = &(protoObject->m_structure);
551         __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), prototypeStructureAddress);
552         bucketsOfFail.append(__ jne());
553     }
554     ASSERT(protoObject);
555
556     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
557     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
558     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
559     JmpSrc success = __ jmp();
560
561     void* code = __ executableCopy(m_codeBlock->executablePool());
562
563     // Use the repatch information to link the failure cases back to the original slow case routine.
564     void* lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine;
565
566     for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
567         X86Assembler::link(code, bucketsOfFail[i], lastProtoBegin);
568
569     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
570     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
571     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
572
573     // Track the stub we have created so that it will be deleted later.
574     structure->ref();
575     chain->ref();
576     prototypeStructures->list[currentIndex].set(cachedOffset, code, structure, chain);
577
578     // Finally repatch the jump to slow case back in the hot path to jump here instead.
579     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
580     X86Assembler::repatchBranchOffset(jmpLocation, code);
581 }
582 #endif
583
584 void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, void* returnAddress, CallFrame* callFrame)
585 {
586 #if USE(CTI_REPATCH_PIC)
587     // We don't want to repatch more than once - in future go to cti_op_put_by_id_generic.
588     ctiRepatchCallByReturnAddress(returnAddress, reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_list));
589
590     ASSERT(count);
591     
592     Vector<JmpSrc> bucketsOfFail;
593
594     // Check eax is an object of the right Structure.
595     bucketsOfFail.append(checkStructure(X86::eax, structure));
596
597     Structure* currStructure = structure;
598     RefPtr<Structure>* chainEntries = chain->head();
599     JSObject* protoObject = 0;
600     for (unsigned i = 0; i < count; ++i) {
601         protoObject = asObject(currStructure->prototypeForLookup(callFrame));
602         currStructure = chainEntries[i].get();
603
604         // Check the prototype object's Structure had not changed.
605         Structure** prototypeStructureAddress = &(protoObject->m_structure);
606         __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), prototypeStructureAddress);
607         bucketsOfFail.append(__ jne());
608     }
609     ASSERT(protoObject);
610
611     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
612     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
613     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
614     JmpSrc success = __ jmp();
615
616     void* code = __ executableCopy(m_codeBlock->executablePool());
617
618     // Use the repatch information to link the failure cases back to the original slow case routine.
619     void* slowCaseBegin = reinterpret_cast<char*>(stubInfo->callReturnLocation) - repatchOffsetGetByIdSlowCaseCall;
620
621     for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
622         X86Assembler::link(code, bucketsOfFail[i], slowCaseBegin);
623
624     // On success return back to the hot patch code, at a point it will perform the store to dest for us.
625     intptr_t successDest = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdPropertyMapOffset;
626     X86Assembler::link(code, success, reinterpret_cast<void*>(successDest));
627
628     // Track the stub we have created so that it will be deleted later.
629     stubInfo->stubRoutine = code;
630
631     // Finally repatch the jump to slow case back in the hot path to jump here instead.
632     intptr_t jmpLocation = reinterpret_cast<intptr_t>(stubInfo->hotPathBegin) + repatchOffsetGetByIdBranchToSlowCase;
633     X86Assembler::repatchBranchOffset(jmpLocation, code);
634 #else
635     ASSERT(count);
636     
637     Vector<JmpSrc> bucketsOfFail;
638
639     // Check eax is an object of the right Structure.
640     __ testl_i32r(JSImmediate::TagMask, X86::eax);
641     bucketsOfFail.append(__ jne());
642     bucketsOfFail.append(checkStructure(X86::eax, structure));
643
644     Structure* currStructure = structure;
645     RefPtr<Structure>* chainEntries = chain->head();
646     JSObject* protoObject = 0;
647     for (unsigned i = 0; i < count; ++i) {
648         protoObject = asObject(currStructure->prototypeForLookup(callFrame));
649         currStructure = chainEntries[i].get();
650
651         // Check the prototype object's Structure had not changed.
652         Structure** prototypeStructureAddress = &(protoObject->m_structure);
653         __ cmpl_i32m(reinterpret_cast<uint32_t>(currStructure), prototypeStructureAddress);
654         bucketsOfFail.append(__ jne());
655     }
656     ASSERT(protoObject);
657
658     PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
659     __ movl_mr(static_cast<void*>(protoPropertyStorage), X86::edx);
660     __ movl_mr(cachedOffset * sizeof(JSValue*), X86::edx, X86::eax);
661     __ ret();
662
663     void* code = __ executableCopy(m_codeBlock->executablePool());
664
665     for (unsigned i = 0; i < bucketsOfFail.size(); ++i)
666         X86Assembler::link(code, bucketsOfFail[i], reinterpret_cast<void*>(Interpreter::cti_op_get_by_id_proto_fail));
667
668     stubInfo->stubRoutine = code;
669
670     ctiRepatchCallByReturnAddress(returnAddress, code);
671 #endif
672 }
673
674 void JIT::privateCompilePutByIdReplace(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, void* returnAddress)
675 {
676     // Check eax is an object of the right Structure.
677     __ testl_i32r(JSImmediate::TagMask, X86::eax);
678     JmpSrc failureCases1 = __ jne();
679     JmpSrc failureCases2 = checkStructure(X86::eax, structure);
680
681     // checks out okay! - putDirectOffset
682     __ movl_mr(FIELD_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
683     __ movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
684     __ ret();
685
686     void* code = __ executableCopy(m_codeBlock->executablePool());
687     
688     X86Assembler::link(code, failureCases1, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail));
689     X86Assembler::link(code, failureCases2, reinterpret_cast<void*>(Interpreter::cti_op_put_by_id_fail));
690
691     stubInfo->stubRoutine = code;
692     
693     ctiRepatchCallByReturnAddress(returnAddress, code);
694 }
695
696 } // namespace JSC
697
698 #endif // ENABLE(JIT)