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