]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
1 | /* |
2 | * Copyright (C) 2008, 2009 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 | ||
ba379fdc | 29 | // This probably does not belong here; adding here for now as a quick Windows build fix. |
f9bf01c6 | 30 | #if ENABLE(ASSEMBLER) && CPU(X86) && !OS(MAC_OS_X) |
ba379fdc A |
31 | #include "MacroAssembler.h" |
32 | JSC::MacroAssemblerX86Common::SSE2CheckState JSC::MacroAssemblerX86Common::s_sse2CheckState = NotCheckedSSE2; | |
33 | #endif | |
34 | ||
9dae56ea A |
35 | #if ENABLE(JIT) |
36 | ||
37 | #include "CodeBlock.h" | |
ba379fdc | 38 | #include "Interpreter.h" |
9dae56ea | 39 | #include "JITInlineMethods.h" |
ba379fdc | 40 | #include "JITStubCall.h" |
9dae56ea A |
41 | #include "JSArray.h" |
42 | #include "JSFunction.h" | |
ba379fdc A |
43 | #include "LinkBuffer.h" |
44 | #include "RepatchBuffer.h" | |
9dae56ea A |
45 | #include "ResultType.h" |
46 | #include "SamplingTool.h" | |
47 | ||
48 | #ifndef NDEBUG | |
49 | #include <stdio.h> | |
50 | #endif | |
51 | ||
52 | using namespace std; | |
53 | ||
54 | namespace JSC { | |
55 | ||
ba379fdc A |
56 | void ctiPatchNearCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction) |
57 | { | |
58 | RepatchBuffer repatchBuffer(codeblock); | |
59 | repatchBuffer.relinkNearCallerToTrampoline(returnAddress, newCalleeFunction); | |
9dae56ea A |
60 | } |
61 | ||
ba379fdc | 62 | void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction) |
9dae56ea | 63 | { |
ba379fdc A |
64 | RepatchBuffer repatchBuffer(codeblock); |
65 | repatchBuffer.relinkCallerToTrampoline(returnAddress, newCalleeFunction); | |
9dae56ea A |
66 | } |
67 | ||
ba379fdc | 68 | void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, FunctionPtr newCalleeFunction) |
9dae56ea | 69 | { |
ba379fdc A |
70 | RepatchBuffer repatchBuffer(codeblock); |
71 | repatchBuffer.relinkCallerToFunction(returnAddress, newCalleeFunction); | |
9dae56ea A |
72 | } |
73 | ||
b80e6193 | 74 | JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock, void* linkerOffset) |
9dae56ea A |
75 | : m_interpreter(globalData->interpreter) |
76 | , m_globalData(globalData) | |
77 | , m_codeBlock(codeBlock) | |
78 | , m_labels(codeBlock ? codeBlock->instructions().size() : 0) | |
79 | , m_propertyAccessCompilationInfo(codeBlock ? codeBlock->numberOfStructureStubInfos() : 0) | |
80 | , m_callStructureStubCompilationInfo(codeBlock ? codeBlock->numberOfCallLinkInfos() : 0) | |
ba379fdc A |
81 | , m_bytecodeIndex((unsigned)-1) |
82 | #if USE(JSVALUE32_64) | |
83 | , m_jumpTargetIndex(0) | |
84 | , m_mappedBytecodeIndex((unsigned)-1) | |
85 | , m_mappedVirtualRegisterIndex((unsigned)-1) | |
86 | , m_mappedTag((RegisterID)-1) | |
87 | , m_mappedPayload((RegisterID)-1) | |
88 | #else | |
9dae56ea A |
89 | , m_lastResultBytecodeRegister(std::numeric_limits<int>::max()) |
90 | , m_jumpTargetsPosition(0) | |
ba379fdc | 91 | #endif |
b80e6193 | 92 | , m_linkerOffset(linkerOffset) |
9dae56ea A |
93 | { |
94 | } | |
95 | ||
ba379fdc A |
96 | #if USE(JSVALUE32_64) |
97 | void JIT::emitTimeoutCheck() | |
9dae56ea | 98 | { |
ba379fdc A |
99 | Jump skipTimeout = branchSub32(NonZero, Imm32(1), timeoutCheckRegister); |
100 | JITStubCall stubCall(this, cti_timeout_check); | |
101 | stubCall.addArgument(regT1, regT0); // save last result registers. | |
102 | stubCall.call(timeoutCheckRegister); | |
103 | stubCall.getArgument(0, regT1, regT0); // reload last result registers. | |
104 | skipTimeout.link(this); | |
9dae56ea | 105 | } |
ba379fdc A |
106 | #else |
107 | void JIT::emitTimeoutCheck() | |
9dae56ea | 108 | { |
ba379fdc A |
109 | Jump skipTimeout = branchSub32(NonZero, Imm32(1), timeoutCheckRegister); |
110 | JITStubCall(this, cti_timeout_check).call(timeoutCheckRegister); | |
9dae56ea A |
111 | skipTimeout.link(this); |
112 | ||
113 | killLastResultRegister(); | |
114 | } | |
ba379fdc | 115 | #endif |
9dae56ea A |
116 | |
117 | #define NEXT_OPCODE(name) \ | |
118 | m_bytecodeIndex += OPCODE_LENGTH(name); \ | |
119 | break; | |
120 | ||
ba379fdc A |
121 | #if USE(JSVALUE32_64) |
122 | #define DEFINE_BINARY_OP(name) \ | |
123 | case name: { \ | |
124 | JITStubCall stubCall(this, cti_##name); \ | |
125 | stubCall.addArgument(currentInstruction[2].u.operand); \ | |
126 | stubCall.addArgument(currentInstruction[3].u.operand); \ | |
127 | stubCall.call(currentInstruction[1].u.operand); \ | |
128 | NEXT_OPCODE(name); \ | |
129 | } | |
130 | ||
131 | #define DEFINE_UNARY_OP(name) \ | |
132 | case name: { \ | |
133 | JITStubCall stubCall(this, cti_##name); \ | |
134 | stubCall.addArgument(currentInstruction[2].u.operand); \ | |
135 | stubCall.call(currentInstruction[1].u.operand); \ | |
136 | NEXT_OPCODE(name); \ | |
137 | } | |
138 | ||
139 | #else // USE(JSVALUE32_64) | |
140 | ||
141 | #define DEFINE_BINARY_OP(name) \ | |
142 | case name: { \ | |
143 | JITStubCall stubCall(this, cti_##name); \ | |
144 | stubCall.addArgument(currentInstruction[2].u.operand, regT2); \ | |
145 | stubCall.addArgument(currentInstruction[3].u.operand, regT2); \ | |
146 | stubCall.call(currentInstruction[1].u.operand); \ | |
147 | NEXT_OPCODE(name); \ | |
148 | } | |
149 | ||
150 | #define DEFINE_UNARY_OP(name) \ | |
151 | case name: { \ | |
152 | JITStubCall stubCall(this, cti_##name); \ | |
153 | stubCall.addArgument(currentInstruction[2].u.operand, regT2); \ | |
154 | stubCall.call(currentInstruction[1].u.operand); \ | |
155 | NEXT_OPCODE(name); \ | |
156 | } | |
157 | #endif // USE(JSVALUE32_64) | |
158 | ||
159 | #define DEFINE_OP(name) \ | |
9dae56ea | 160 | case name: { \ |
ba379fdc | 161 | emit_##name(currentInstruction); \ |
9dae56ea A |
162 | NEXT_OPCODE(name); \ |
163 | } | |
164 | ||
ba379fdc | 165 | #define DEFINE_SLOWCASE_OP(name) \ |
9dae56ea | 166 | case name: { \ |
ba379fdc | 167 | emitSlow_##name(currentInstruction, iter); \ |
9dae56ea A |
168 | NEXT_OPCODE(name); \ |
169 | } | |
170 | ||
171 | void JIT::privateCompileMainPass() | |
172 | { | |
173 | Instruction* instructionsBegin = m_codeBlock->instructions().begin(); | |
174 | unsigned instructionCount = m_codeBlock->instructions().size(); | |
ba379fdc A |
175 | |
176 | m_propertyAccessInstructionIndex = 0; | |
177 | m_globalResolveInfoIndex = 0; | |
178 | m_callLinkInfoIndex = 0; | |
9dae56ea A |
179 | |
180 | for (m_bytecodeIndex = 0; m_bytecodeIndex < instructionCount; ) { | |
181 | Instruction* currentInstruction = instructionsBegin + m_bytecodeIndex; | |
182 | ASSERT_WITH_MESSAGE(m_interpreter->isOpcode(currentInstruction->u.opcode), "privateCompileMainPass gone bad @ %d", m_bytecodeIndex); | |
183 | ||
184 | #if ENABLE(OPCODE_SAMPLING) | |
185 | if (m_bytecodeIndex > 0) // Avoid the overhead of sampling op_enter twice. | |
186 | sampleInstruction(currentInstruction); | |
187 | #endif | |
188 | ||
ba379fdc A |
189 | #if !USE(JSVALUE32_64) |
190 | if (m_labels[m_bytecodeIndex].isUsed()) | |
191 | killLastResultRegister(); | |
9dae56ea | 192 | #endif |
9dae56ea | 193 | |
ba379fdc | 194 | m_labels[m_bytecodeIndex] = label(); |
9dae56ea | 195 | |
ba379fdc A |
196 | switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) { |
197 | DEFINE_BINARY_OP(op_del_by_val) | |
f9bf01c6 | 198 | #if USE(JSVALUE32) |
ba379fdc | 199 | DEFINE_BINARY_OP(op_div) |
9dae56ea | 200 | #endif |
ba379fdc A |
201 | DEFINE_BINARY_OP(op_in) |
202 | DEFINE_BINARY_OP(op_less) | |
203 | DEFINE_BINARY_OP(op_lesseq) | |
ba379fdc A |
204 | DEFINE_UNARY_OP(op_is_boolean) |
205 | DEFINE_UNARY_OP(op_is_function) | |
206 | DEFINE_UNARY_OP(op_is_number) | |
207 | DEFINE_UNARY_OP(op_is_object) | |
208 | DEFINE_UNARY_OP(op_is_string) | |
209 | DEFINE_UNARY_OP(op_is_undefined) | |
210 | #if !USE(JSVALUE32_64) | |
211 | DEFINE_UNARY_OP(op_negate) | |
9dae56ea | 212 | #endif |
ba379fdc A |
213 | DEFINE_UNARY_OP(op_typeof) |
214 | ||
215 | DEFINE_OP(op_add) | |
216 | DEFINE_OP(op_bitand) | |
217 | DEFINE_OP(op_bitnot) | |
218 | DEFINE_OP(op_bitor) | |
219 | DEFINE_OP(op_bitxor) | |
220 | DEFINE_OP(op_call) | |
221 | DEFINE_OP(op_call_eval) | |
222 | DEFINE_OP(op_call_varargs) | |
223 | DEFINE_OP(op_catch) | |
224 | DEFINE_OP(op_construct) | |
225 | DEFINE_OP(op_construct_verify) | |
226 | DEFINE_OP(op_convert_this) | |
227 | DEFINE_OP(op_init_arguments) | |
228 | DEFINE_OP(op_create_arguments) | |
229 | DEFINE_OP(op_debug) | |
230 | DEFINE_OP(op_del_by_id) | |
f9bf01c6 | 231 | #if !USE(JSVALUE32) |
ba379fdc | 232 | DEFINE_OP(op_div) |
9dae56ea | 233 | #endif |
ba379fdc A |
234 | DEFINE_OP(op_end) |
235 | DEFINE_OP(op_enter) | |
236 | DEFINE_OP(op_enter_with_activation) | |
237 | DEFINE_OP(op_eq) | |
238 | DEFINE_OP(op_eq_null) | |
239 | DEFINE_OP(op_get_by_id) | |
240 | DEFINE_OP(op_get_by_val) | |
f9bf01c6 | 241 | DEFINE_OP(op_get_by_pname) |
ba379fdc | 242 | DEFINE_OP(op_get_global_var) |
f9bf01c6 | 243 | DEFINE_OP(op_get_pnames) |
ba379fdc A |
244 | DEFINE_OP(op_get_scoped_var) |
245 | DEFINE_OP(op_instanceof) | |
246 | DEFINE_OP(op_jeq_null) | |
247 | DEFINE_OP(op_jfalse) | |
248 | DEFINE_OP(op_jmp) | |
249 | DEFINE_OP(op_jmp_scopes) | |
250 | DEFINE_OP(op_jneq_null) | |
251 | DEFINE_OP(op_jneq_ptr) | |
252 | DEFINE_OP(op_jnless) | |
f9bf01c6 | 253 | DEFINE_OP(op_jless) |
4e4e5a6f | 254 | DEFINE_OP(op_jlesseq) |
ba379fdc A |
255 | DEFINE_OP(op_jnlesseq) |
256 | DEFINE_OP(op_jsr) | |
257 | DEFINE_OP(op_jtrue) | |
258 | DEFINE_OP(op_load_varargs) | |
259 | DEFINE_OP(op_loop) | |
260 | DEFINE_OP(op_loop_if_less) | |
261 | DEFINE_OP(op_loop_if_lesseq) | |
262 | DEFINE_OP(op_loop_if_true) | |
f9bf01c6 | 263 | DEFINE_OP(op_loop_if_false) |
ba379fdc A |
264 | DEFINE_OP(op_lshift) |
265 | DEFINE_OP(op_method_check) | |
266 | DEFINE_OP(op_mod) | |
267 | DEFINE_OP(op_mov) | |
268 | DEFINE_OP(op_mul) | |
269 | #if USE(JSVALUE32_64) | |
270 | DEFINE_OP(op_negate) | |
9dae56ea | 271 | #endif |
ba379fdc A |
272 | DEFINE_OP(op_neq) |
273 | DEFINE_OP(op_neq_null) | |
274 | DEFINE_OP(op_new_array) | |
275 | DEFINE_OP(op_new_error) | |
276 | DEFINE_OP(op_new_func) | |
277 | DEFINE_OP(op_new_func_exp) | |
278 | DEFINE_OP(op_new_object) | |
279 | DEFINE_OP(op_new_regexp) | |
280 | DEFINE_OP(op_next_pname) | |
281 | DEFINE_OP(op_not) | |
282 | DEFINE_OP(op_nstricteq) | |
283 | DEFINE_OP(op_pop_scope) | |
284 | DEFINE_OP(op_post_dec) | |
285 | DEFINE_OP(op_post_inc) | |
286 | DEFINE_OP(op_pre_dec) | |
287 | DEFINE_OP(op_pre_inc) | |
288 | DEFINE_OP(op_profile_did_call) | |
289 | DEFINE_OP(op_profile_will_call) | |
290 | DEFINE_OP(op_push_new_scope) | |
291 | DEFINE_OP(op_push_scope) | |
292 | DEFINE_OP(op_put_by_id) | |
293 | DEFINE_OP(op_put_by_index) | |
294 | DEFINE_OP(op_put_by_val) | |
295 | DEFINE_OP(op_put_getter) | |
296 | DEFINE_OP(op_put_global_var) | |
297 | DEFINE_OP(op_put_scoped_var) | |
298 | DEFINE_OP(op_put_setter) | |
299 | DEFINE_OP(op_resolve) | |
300 | DEFINE_OP(op_resolve_base) | |
301 | DEFINE_OP(op_resolve_global) | |
4e4e5a6f | 302 | DEFINE_OP(op_resolve_global_dynamic) |
ba379fdc A |
303 | DEFINE_OP(op_resolve_skip) |
304 | DEFINE_OP(op_resolve_with_base) | |
305 | DEFINE_OP(op_ret) | |
306 | DEFINE_OP(op_rshift) | |
4e4e5a6f | 307 | DEFINE_OP(op_urshift) |
ba379fdc A |
308 | DEFINE_OP(op_sret) |
309 | DEFINE_OP(op_strcat) | |
310 | DEFINE_OP(op_stricteq) | |
311 | DEFINE_OP(op_sub) | |
312 | DEFINE_OP(op_switch_char) | |
313 | DEFINE_OP(op_switch_imm) | |
314 | DEFINE_OP(op_switch_string) | |
315 | DEFINE_OP(op_tear_off_activation) | |
316 | DEFINE_OP(op_tear_off_arguments) | |
317 | DEFINE_OP(op_throw) | |
318 | DEFINE_OP(op_to_jsnumber) | |
319 | DEFINE_OP(op_to_primitive) | |
9dae56ea | 320 | |
9dae56ea A |
321 | case op_get_array_length: |
322 | case op_get_by_id_chain: | |
323 | case op_get_by_id_generic: | |
324 | case op_get_by_id_proto: | |
325 | case op_get_by_id_proto_list: | |
326 | case op_get_by_id_self: | |
327 | case op_get_by_id_self_list: | |
4e4e5a6f A |
328 | case op_get_by_id_getter_chain: |
329 | case op_get_by_id_getter_proto: | |
330 | case op_get_by_id_getter_proto_list: | |
331 | case op_get_by_id_getter_self: | |
332 | case op_get_by_id_getter_self_list: | |
333 | case op_get_by_id_custom_chain: | |
334 | case op_get_by_id_custom_proto: | |
335 | case op_get_by_id_custom_proto_list: | |
336 | case op_get_by_id_custom_self: | |
337 | case op_get_by_id_custom_self_list: | |
9dae56ea A |
338 | case op_get_string_length: |
339 | case op_put_by_id_generic: | |
340 | case op_put_by_id_replace: | |
341 | case op_put_by_id_transition: | |
342 | ASSERT_NOT_REACHED(); | |
343 | } | |
344 | } | |
345 | ||
ba379fdc A |
346 | ASSERT(m_propertyAccessInstructionIndex == m_codeBlock->numberOfStructureStubInfos()); |
347 | ASSERT(m_callLinkInfoIndex == m_codeBlock->numberOfCallLinkInfos()); | |
9dae56ea A |
348 | |
349 | #ifndef NDEBUG | |
ba379fdc | 350 | // Reset this, in order to guard its use with ASSERTs. |
9dae56ea A |
351 | m_bytecodeIndex = (unsigned)-1; |
352 | #endif | |
353 | } | |
354 | ||
355 | ||
356 | void JIT::privateCompileLinkPass() | |
357 | { | |
358 | unsigned jmpTableCount = m_jmpTable.size(); | |
359 | for (unsigned i = 0; i < jmpTableCount; ++i) | |
360 | m_jmpTable[i].from.linkTo(m_labels[m_jmpTable[i].toBytecodeIndex], this); | |
361 | m_jmpTable.clear(); | |
362 | } | |
363 | ||
364 | void JIT::privateCompileSlowCases() | |
365 | { | |
366 | Instruction* instructionsBegin = m_codeBlock->instructions().begin(); | |
ba379fdc A |
367 | |
368 | m_propertyAccessInstructionIndex = 0; | |
ba379fdc | 369 | m_globalResolveInfoIndex = 0; |
ba379fdc | 370 | m_callLinkInfoIndex = 0; |
9dae56ea A |
371 | |
372 | for (Vector<SlowCaseEntry>::iterator iter = m_slowCases.begin(); iter != m_slowCases.end();) { | |
ba379fdc | 373 | #if !USE(JSVALUE32_64) |
9dae56ea | 374 | killLastResultRegister(); |
ba379fdc | 375 | #endif |
9dae56ea A |
376 | |
377 | m_bytecodeIndex = iter->to; | |
378 | #ifndef NDEBUG | |
379 | unsigned firstTo = m_bytecodeIndex; | |
380 | #endif | |
381 | Instruction* currentInstruction = instructionsBegin + m_bytecodeIndex; | |
382 | ||
ba379fdc A |
383 | switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) { |
384 | DEFINE_SLOWCASE_OP(op_add) | |
385 | DEFINE_SLOWCASE_OP(op_bitand) | |
386 | DEFINE_SLOWCASE_OP(op_bitnot) | |
387 | DEFINE_SLOWCASE_OP(op_bitor) | |
388 | DEFINE_SLOWCASE_OP(op_bitxor) | |
389 | DEFINE_SLOWCASE_OP(op_call) | |
390 | DEFINE_SLOWCASE_OP(op_call_eval) | |
391 | DEFINE_SLOWCASE_OP(op_call_varargs) | |
392 | DEFINE_SLOWCASE_OP(op_construct) | |
393 | DEFINE_SLOWCASE_OP(op_construct_verify) | |
394 | DEFINE_SLOWCASE_OP(op_convert_this) | |
f9bf01c6 | 395 | #if !USE(JSVALUE32) |
ba379fdc | 396 | DEFINE_SLOWCASE_OP(op_div) |
9dae56ea | 397 | #endif |
ba379fdc A |
398 | DEFINE_SLOWCASE_OP(op_eq) |
399 | DEFINE_SLOWCASE_OP(op_get_by_id) | |
400 | DEFINE_SLOWCASE_OP(op_get_by_val) | |
f9bf01c6 | 401 | DEFINE_SLOWCASE_OP(op_get_by_pname) |
ba379fdc A |
402 | DEFINE_SLOWCASE_OP(op_instanceof) |
403 | DEFINE_SLOWCASE_OP(op_jfalse) | |
404 | DEFINE_SLOWCASE_OP(op_jnless) | |
f9bf01c6 | 405 | DEFINE_SLOWCASE_OP(op_jless) |
4e4e5a6f | 406 | DEFINE_SLOWCASE_OP(op_jlesseq) |
ba379fdc A |
407 | DEFINE_SLOWCASE_OP(op_jnlesseq) |
408 | DEFINE_SLOWCASE_OP(op_jtrue) | |
409 | DEFINE_SLOWCASE_OP(op_loop_if_less) | |
410 | DEFINE_SLOWCASE_OP(op_loop_if_lesseq) | |
411 | DEFINE_SLOWCASE_OP(op_loop_if_true) | |
f9bf01c6 | 412 | DEFINE_SLOWCASE_OP(op_loop_if_false) |
ba379fdc A |
413 | DEFINE_SLOWCASE_OP(op_lshift) |
414 | DEFINE_SLOWCASE_OP(op_method_check) | |
415 | DEFINE_SLOWCASE_OP(op_mod) | |
416 | DEFINE_SLOWCASE_OP(op_mul) | |
417 | #if USE(JSVALUE32_64) | |
418 | DEFINE_SLOWCASE_OP(op_negate) | |
9dae56ea | 419 | #endif |
ba379fdc A |
420 | DEFINE_SLOWCASE_OP(op_neq) |
421 | DEFINE_SLOWCASE_OP(op_not) | |
422 | DEFINE_SLOWCASE_OP(op_nstricteq) | |
423 | DEFINE_SLOWCASE_OP(op_post_dec) | |
424 | DEFINE_SLOWCASE_OP(op_post_inc) | |
425 | DEFINE_SLOWCASE_OP(op_pre_dec) | |
426 | DEFINE_SLOWCASE_OP(op_pre_inc) | |
427 | DEFINE_SLOWCASE_OP(op_put_by_id) | |
428 | DEFINE_SLOWCASE_OP(op_put_by_val) | |
ba379fdc | 429 | DEFINE_SLOWCASE_OP(op_resolve_global) |
4e4e5a6f | 430 | DEFINE_SLOWCASE_OP(op_resolve_global_dynamic) |
ba379fdc | 431 | DEFINE_SLOWCASE_OP(op_rshift) |
4e4e5a6f | 432 | DEFINE_SLOWCASE_OP(op_urshift) |
ba379fdc A |
433 | DEFINE_SLOWCASE_OP(op_stricteq) |
434 | DEFINE_SLOWCASE_OP(op_sub) | |
435 | DEFINE_SLOWCASE_OP(op_to_jsnumber) | |
436 | DEFINE_SLOWCASE_OP(op_to_primitive) | |
9dae56ea A |
437 | default: |
438 | ASSERT_NOT_REACHED(); | |
439 | } | |
440 | ||
441 | ASSERT_WITH_MESSAGE(iter == m_slowCases.end() || firstTo != iter->to,"Not enough jumps linked in slow case codegen."); | |
442 | ASSERT_WITH_MESSAGE(firstTo == (iter - 1)->to, "Too many jumps linked in slow case codegen."); | |
443 | ||
444 | emitJumpSlowToHot(jump(), 0); | |
445 | } | |
446 | ||
447 | #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) | |
ba379fdc | 448 | ASSERT(m_propertyAccessInstructionIndex == m_codeBlock->numberOfStructureStubInfos()); |
9dae56ea | 449 | #endif |
ba379fdc | 450 | ASSERT(m_callLinkInfoIndex == m_codeBlock->numberOfCallLinkInfos()); |
9dae56ea A |
451 | |
452 | #ifndef NDEBUG | |
ba379fdc | 453 | // Reset this, in order to guard its use with ASSERTs. |
9dae56ea A |
454 | m_bytecodeIndex = (unsigned)-1; |
455 | #endif | |
456 | } | |
457 | ||
f9bf01c6 | 458 | JITCode JIT::privateCompile() |
9dae56ea A |
459 | { |
460 | sampleCodeBlock(m_codeBlock); | |
461 | #if ENABLE(OPCODE_SAMPLING) | |
462 | sampleInstruction(m_codeBlock->instructions().begin()); | |
463 | #endif | |
464 | ||
465 | // Could use a pop_m, but would need to offset the following instruction if so. | |
ba379fdc A |
466 | preserveReturnAddressAfterCall(regT2); |
467 | emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC); | |
9dae56ea A |
468 | |
469 | Jump slowRegisterFileCheck; | |
470 | Label afterRegisterFileCheck; | |
471 | if (m_codeBlock->codeType() == FunctionCode) { | |
472 | // In the case of a fast linked call, we do not set this up in the caller. | |
473 | emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock); | |
474 | ||
ba379fdc A |
475 | peek(regT0, OBJECT_OFFSETOF(JITStackFrame, registerFile) / sizeof (void*)); |
476 | addPtr(Imm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), callFrameRegister, regT1); | |
477 | ||
478 | slowRegisterFileCheck = branchPtr(Above, regT1, Address(regT0, OBJECT_OFFSETOF(RegisterFile, m_end))); | |
9dae56ea A |
479 | afterRegisterFileCheck = label(); |
480 | } | |
481 | ||
482 | privateCompileMainPass(); | |
483 | privateCompileLinkPass(); | |
484 | privateCompileSlowCases(); | |
485 | ||
486 | if (m_codeBlock->codeType() == FunctionCode) { | |
487 | slowRegisterFileCheck.link(this); | |
ba379fdc A |
488 | m_bytecodeIndex = 0; |
489 | JITStubCall(this, cti_register_file_check).call(); | |
9dae56ea | 490 | #ifndef NDEBUG |
ba379fdc | 491 | m_bytecodeIndex = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs. |
9dae56ea A |
492 | #endif |
493 | jump(afterRegisterFileCheck); | |
494 | } | |
495 | ||
496 | ASSERT(m_jmpTable.isEmpty()); | |
497 | ||
b80e6193 A |
498 | RefPtr<ExecutablePool> executablePool = m_globalData->executableAllocator.poolForSize(m_assembler.size()); |
499 | if (!executablePool) | |
500 | return JITCode(); | |
501 | LinkBuffer patchBuffer(this, executablePool.release(), m_linkerOffset); | |
9dae56ea A |
502 | |
503 | // Translate vPC offsets into addresses in JIT generated code, for switch tables. | |
504 | for (unsigned i = 0; i < m_switches.size(); ++i) { | |
505 | SwitchRecord record = m_switches[i]; | |
506 | unsigned bytecodeIndex = record.bytecodeIndex; | |
507 | ||
508 | if (record.type != SwitchRecord::String) { | |
509 | ASSERT(record.type == SwitchRecord::Immediate || record.type == SwitchRecord::Character); | |
510 | ASSERT(record.jumpTable.simpleJumpTable->branchOffsets.size() == record.jumpTable.simpleJumpTable->ctiOffsets.size()); | |
511 | ||
f9bf01c6 | 512 | record.jumpTable.simpleJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeIndex + record.defaultOffset]); |
9dae56ea A |
513 | |
514 | for (unsigned j = 0; j < record.jumpTable.simpleJumpTable->branchOffsets.size(); ++j) { | |
515 | unsigned offset = record.jumpTable.simpleJumpTable->branchOffsets[j]; | |
f9bf01c6 | 516 | record.jumpTable.simpleJumpTable->ctiOffsets[j] = offset ? patchBuffer.locationOf(m_labels[bytecodeIndex + offset]) : record.jumpTable.simpleJumpTable->ctiDefault; |
9dae56ea A |
517 | } |
518 | } else { | |
519 | ASSERT(record.type == SwitchRecord::String); | |
520 | ||
f9bf01c6 | 521 | record.jumpTable.stringJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeIndex + record.defaultOffset]); |
9dae56ea A |
522 | |
523 | StringJumpTable::StringOffsetTable::iterator end = record.jumpTable.stringJumpTable->offsetTable.end(); | |
524 | for (StringJumpTable::StringOffsetTable::iterator it = record.jumpTable.stringJumpTable->offsetTable.begin(); it != end; ++it) { | |
525 | unsigned offset = it->second.branchOffset; | |
f9bf01c6 | 526 | it->second.ctiOffset = offset ? patchBuffer.locationOf(m_labels[bytecodeIndex + offset]) : record.jumpTable.stringJumpTable->ctiDefault; |
9dae56ea A |
527 | } |
528 | } | |
529 | } | |
530 | ||
531 | for (size_t i = 0; i < m_codeBlock->numberOfExceptionHandlers(); ++i) { | |
532 | HandlerInfo& handler = m_codeBlock->exceptionHandler(i); | |
ba379fdc | 533 | handler.nativeCode = patchBuffer.locationOf(m_labels[handler.target]); |
9dae56ea A |
534 | } |
535 | ||
536 | for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { | |
537 | if (iter->to) | |
ba379fdc | 538 | patchBuffer.link(iter->from, FunctionPtr(iter->to)); |
9dae56ea A |
539 | } |
540 | ||
541 | if (m_codeBlock->hasExceptionInfo()) { | |
ba379fdc | 542 | m_codeBlock->callReturnIndexVector().reserveCapacity(m_calls.size()); |
9dae56ea | 543 | for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) |
ba379fdc | 544 | m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeIndex(patchBuffer.returnAddressOffset(iter->from), iter->bytecodeIndex)); |
9dae56ea A |
545 | } |
546 | ||
547 | // Link absolute addresses for jsr | |
548 | for (Vector<JSRInfo>::iterator iter = m_jsrSites.begin(); iter != m_jsrSites.end(); ++iter) | |
ba379fdc | 549 | patchBuffer.patch(iter->storeLocation, patchBuffer.locationOf(iter->target).executableAddress()); |
9dae56ea | 550 | |
ba379fdc | 551 | #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) |
9dae56ea A |
552 | for (unsigned i = 0; i < m_codeBlock->numberOfStructureStubInfos(); ++i) { |
553 | StructureStubInfo& info = m_codeBlock->structureStubInfo(i); | |
ba379fdc A |
554 | info.callReturnLocation = patchBuffer.locationOf(m_propertyAccessCompilationInfo[i].callReturnLocation); |
555 | info.hotPathBegin = patchBuffer.locationOf(m_propertyAccessCompilationInfo[i].hotPathBegin); | |
9dae56ea | 556 | } |
ba379fdc A |
557 | #endif |
558 | #if ENABLE(JIT_OPTIMIZE_CALL) | |
9dae56ea A |
559 | for (unsigned i = 0; i < m_codeBlock->numberOfCallLinkInfos(); ++i) { |
560 | CallLinkInfo& info = m_codeBlock->callLinkInfo(i); | |
ba379fdc A |
561 | info.ownerCodeBlock = m_codeBlock; |
562 | info.callReturnLocation = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation); | |
563 | info.hotPathBegin = patchBuffer.locationOf(m_callStructureStubCompilationInfo[i].hotPathBegin); | |
564 | info.hotPathOther = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].hotPathOther); | |
565 | } | |
9dae56ea | 566 | #endif |
ba379fdc A |
567 | unsigned methodCallCount = m_methodCallCompilationInfo.size(); |
568 | m_codeBlock->addMethodCallLinkInfos(methodCallCount); | |
569 | for (unsigned i = 0; i < methodCallCount; ++i) { | |
570 | MethodCallLinkInfo& info = m_codeBlock->methodCallLinkInfo(i); | |
571 | info.structureLabel = patchBuffer.locationOf(m_methodCallCompilationInfo[i].structureToCompare); | |
572 | info.callReturnLocation = m_codeBlock->structureStubInfo(m_methodCallCompilationInfo[i].propertyAccessIndex).callReturnLocation; | |
9dae56ea A |
573 | } |
574 | ||
f9bf01c6 | 575 | return patchBuffer.finalizeCode(); |
9dae56ea A |
576 | } |
577 | ||
ba379fdc A |
578 | #if !USE(JSVALUE32_64) |
579 | void JIT::emitGetVariableObjectRegister(RegisterID variableObject, int index, RegisterID dst) | |
9dae56ea | 580 | { |
ba379fdc A |
581 | loadPtr(Address(variableObject, OBJECT_OFFSETOF(JSVariableObject, d)), dst); |
582 | loadPtr(Address(dst, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), dst); | |
583 | loadPtr(Address(dst, index * sizeof(Register)), dst); | |
584 | } | |
9dae56ea | 585 | |
ba379fdc A |
586 | void JIT::emitPutVariableObjectRegister(RegisterID src, RegisterID variableObject, int index) |
587 | { | |
588 | loadPtr(Address(variableObject, OBJECT_OFFSETOF(JSVariableObject, d)), variableObject); | |
589 | loadPtr(Address(variableObject, OBJECT_OFFSETOF(JSVariableObject::JSVariableObjectData, registers)), variableObject); | |
590 | storePtr(src, Address(variableObject, index * sizeof(Register))); | |
591 | } | |
9dae56ea A |
592 | #endif |
593 | ||
ba379fdc A |
594 | #if ENABLE(JIT_OPTIMIZE_CALL) |
595 | void JIT::unlinkCall(CallLinkInfo* callLinkInfo) | |
596 | { | |
597 | // When the JSFunction is deleted the pointer embedded in the instruction stream will no longer be valid | |
598 | // (and, if a new JSFunction happened to be constructed at the same location, we could get a false positive | |
599 | // match). Reset the check so it no longer matches. | |
4e4e5a6f | 600 | RepatchBuffer repatchBuffer(callLinkInfo->ownerCodeBlock); |
ba379fdc A |
601 | #if USE(JSVALUE32_64) |
602 | repatchBuffer.repatch(callLinkInfo->hotPathBegin, 0); | |
603 | #else | |
604 | repatchBuffer.repatch(callLinkInfo->hotPathBegin, JSValue::encode(JSValue())); | |
9dae56ea | 605 | #endif |
9dae56ea A |
606 | } |
607 | ||
ba379fdc | 608 | void JIT::linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode& code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData) |
9dae56ea | 609 | { |
ba379fdc | 610 | RepatchBuffer repatchBuffer(callerCodeBlock); |
9dae56ea | 611 | |
ba379fdc A |
612 | // Currently we only link calls with the exact number of arguments. |
613 | // If this is a native call calleeCodeBlock is null so the number of parameters is unimportant | |
f9bf01c6 | 614 | if (!calleeCodeBlock || (callerArgCount == calleeCodeBlock->m_numParameters)) { |
ba379fdc A |
615 | ASSERT(!callLinkInfo->isLinked()); |
616 | ||
617 | if (calleeCodeBlock) | |
618 | calleeCodeBlock->addCaller(callLinkInfo); | |
619 | ||
620 | repatchBuffer.repatch(callLinkInfo->hotPathBegin, callee); | |
621 | repatchBuffer.relink(callLinkInfo->hotPathOther, code.addressForCall()); | |
622 | } | |
623 | ||
624 | // patch the call so we do not continue to try to link. | |
4e4e5a6f | 625 | repatchBuffer.relink(callLinkInfo->callReturnLocation, globalData->jitStubs->ctiVirtualCall()); |
9dae56ea | 626 | } |
ba379fdc | 627 | #endif // ENABLE(JIT_OPTIMIZE_CALL) |
9dae56ea A |
628 | |
629 | } // namespace JSC | |
630 | ||
631 | #endif // ENABLE(JIT) |