]>
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" | |
14957cd0 A |
27 | |
28 | #if ENABLE(JIT) | |
9dae56ea A |
29 | #include "JIT.h" |
30 | ||
ba379fdc | 31 | // This probably does not belong here; adding here for now as a quick Windows build fix. |
f9bf01c6 | 32 | #if ENABLE(ASSEMBLER) && CPU(X86) && !OS(MAC_OS_X) |
ba379fdc A |
33 | #include "MacroAssembler.h" |
34 | JSC::MacroAssemblerX86Common::SSE2CheckState JSC::MacroAssemblerX86Common::s_sse2CheckState = NotCheckedSSE2; | |
35 | #endif | |
36 | ||
9dae56ea | 37 | #include "CodeBlock.h" |
6fe7ccc8 A |
38 | #include <wtf/CryptographicallyRandomNumber.h> |
39 | #include "DFGNode.h" // for DFG_SUCCESS_STATS | |
ba379fdc | 40 | #include "Interpreter.h" |
9dae56ea | 41 | #include "JITInlineMethods.h" |
ba379fdc | 42 | #include "JITStubCall.h" |
9dae56ea A |
43 | #include "JSArray.h" |
44 | #include "JSFunction.h" | |
ba379fdc A |
45 | #include "LinkBuffer.h" |
46 | #include "RepatchBuffer.h" | |
9dae56ea A |
47 | #include "ResultType.h" |
48 | #include "SamplingTool.h" | |
9dae56ea A |
49 | |
50 | using namespace std; | |
51 | ||
52 | namespace JSC { | |
53 | ||
ba379fdc A |
54 | void ctiPatchNearCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction) |
55 | { | |
56 | RepatchBuffer repatchBuffer(codeblock); | |
57 | repatchBuffer.relinkNearCallerToTrampoline(returnAddress, newCalleeFunction); | |
9dae56ea A |
58 | } |
59 | ||
ba379fdc | 60 | void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction) |
9dae56ea | 61 | { |
ba379fdc A |
62 | RepatchBuffer repatchBuffer(codeblock); |
63 | repatchBuffer.relinkCallerToTrampoline(returnAddress, newCalleeFunction); | |
9dae56ea A |
64 | } |
65 | ||
ba379fdc | 66 | void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, FunctionPtr newCalleeFunction) |
9dae56ea | 67 | { |
ba379fdc A |
68 | RepatchBuffer repatchBuffer(codeblock); |
69 | repatchBuffer.relinkCallerToFunction(returnAddress, newCalleeFunction); | |
9dae56ea A |
70 | } |
71 | ||
14957cd0 | 72 | JIT::JIT(JSGlobalData* globalData, CodeBlock* codeBlock) |
9dae56ea A |
73 | : m_interpreter(globalData->interpreter) |
74 | , m_globalData(globalData) | |
75 | , m_codeBlock(codeBlock) | |
6fe7ccc8 | 76 | , m_labels(codeBlock ? codeBlock->numberOfInstructions() : 0) |
14957cd0 | 77 | , m_bytecodeOffset((unsigned)-1) |
ba379fdc A |
78 | #if USE(JSVALUE32_64) |
79 | , m_jumpTargetIndex(0) | |
14957cd0 | 80 | , m_mappedBytecodeOffset((unsigned)-1) |
6fe7ccc8 | 81 | , m_mappedVirtualRegisterIndex(RegisterFile::ReturnPC) |
ba379fdc A |
82 | , m_mappedTag((RegisterID)-1) |
83 | , m_mappedPayload((RegisterID)-1) | |
84 | #else | |
9dae56ea A |
85 | , m_lastResultBytecodeRegister(std::numeric_limits<int>::max()) |
86 | , m_jumpTargetsPosition(0) | |
ba379fdc | 87 | #endif |
14957cd0 A |
88 | #if USE(OS_RANDOMNESS) |
89 | , m_randomGenerator(cryptographicallyRandomNumber()) | |
90 | #else | |
91 | , m_randomGenerator(static_cast<unsigned>(randomNumber() * 0xFFFFFFF)) | |
92 | #endif | |
9dae56ea A |
93 | { |
94 | } | |
95 | ||
6fe7ccc8 A |
96 | #if ENABLE(DFG_JIT) |
97 | void JIT::emitOptimizationCheck(OptimizationCheckKind kind) | |
98 | { | |
99 | if (!shouldEmitProfiling()) | |
100 | return; | |
101 | ||
102 | Jump skipOptimize = branchAdd32(Signed, TrustedImm32(kind == LoopOptimizationCheck ? Options::executionCounterIncrementForLoop : Options::executionCounterIncrementForReturn), AbsoluteAddress(m_codeBlock->addressOfJITExecuteCounter())); | |
103 | JITStubCall stubCall(this, kind == LoopOptimizationCheck ? cti_optimize_from_loop : cti_optimize_from_ret); | |
104 | if (kind == LoopOptimizationCheck) | |
105 | stubCall.addArgument(TrustedImm32(m_bytecodeOffset)); | |
106 | stubCall.call(); | |
107 | skipOptimize.link(this); | |
108 | } | |
109 | #endif | |
110 | ||
111 | #if CPU(X86) | |
112 | void JIT::emitTimeoutCheck() | |
113 | { | |
114 | Jump skipTimeout = branchSub32(NonZero, TrustedImm32(1), AbsoluteAddress(&m_globalData->m_timeoutCount)); | |
115 | JITStubCall stubCall(this, cti_timeout_check); | |
116 | stubCall.addArgument(regT1, regT0); // save last result registers. | |
117 | stubCall.call(regT0); | |
118 | store32(regT0, &m_globalData->m_timeoutCount); | |
119 | stubCall.getArgument(0, regT1, regT0); // reload last result registers. | |
120 | skipTimeout.link(this); | |
121 | } | |
122 | #elif USE(JSVALUE32_64) | |
ba379fdc | 123 | void JIT::emitTimeoutCheck() |
9dae56ea | 124 | { |
14957cd0 | 125 | Jump skipTimeout = branchSub32(NonZero, TrustedImm32(1), timeoutCheckRegister); |
ba379fdc A |
126 | JITStubCall stubCall(this, cti_timeout_check); |
127 | stubCall.addArgument(regT1, regT0); // save last result registers. | |
128 | stubCall.call(timeoutCheckRegister); | |
129 | stubCall.getArgument(0, regT1, regT0); // reload last result registers. | |
130 | skipTimeout.link(this); | |
9dae56ea | 131 | } |
ba379fdc A |
132 | #else |
133 | void JIT::emitTimeoutCheck() | |
9dae56ea | 134 | { |
14957cd0 | 135 | Jump skipTimeout = branchSub32(NonZero, TrustedImm32(1), timeoutCheckRegister); |
ba379fdc | 136 | JITStubCall(this, cti_timeout_check).call(timeoutCheckRegister); |
9dae56ea A |
137 | skipTimeout.link(this); |
138 | ||
139 | killLastResultRegister(); | |
140 | } | |
ba379fdc | 141 | #endif |
9dae56ea A |
142 | |
143 | #define NEXT_OPCODE(name) \ | |
14957cd0 | 144 | m_bytecodeOffset += OPCODE_LENGTH(name); \ |
9dae56ea A |
145 | break; |
146 | ||
ba379fdc A |
147 | #if USE(JSVALUE32_64) |
148 | #define DEFINE_BINARY_OP(name) \ | |
149 | case name: { \ | |
150 | JITStubCall stubCall(this, cti_##name); \ | |
151 | stubCall.addArgument(currentInstruction[2].u.operand); \ | |
152 | stubCall.addArgument(currentInstruction[3].u.operand); \ | |
153 | stubCall.call(currentInstruction[1].u.operand); \ | |
154 | NEXT_OPCODE(name); \ | |
155 | } | |
156 | ||
157 | #define DEFINE_UNARY_OP(name) \ | |
158 | case name: { \ | |
159 | JITStubCall stubCall(this, cti_##name); \ | |
160 | stubCall.addArgument(currentInstruction[2].u.operand); \ | |
161 | stubCall.call(currentInstruction[1].u.operand); \ | |
162 | NEXT_OPCODE(name); \ | |
163 | } | |
164 | ||
165 | #else // USE(JSVALUE32_64) | |
166 | ||
167 | #define DEFINE_BINARY_OP(name) \ | |
168 | case name: { \ | |
169 | JITStubCall stubCall(this, cti_##name); \ | |
170 | stubCall.addArgument(currentInstruction[2].u.operand, regT2); \ | |
171 | stubCall.addArgument(currentInstruction[3].u.operand, regT2); \ | |
172 | stubCall.call(currentInstruction[1].u.operand); \ | |
173 | NEXT_OPCODE(name); \ | |
174 | } | |
175 | ||
176 | #define DEFINE_UNARY_OP(name) \ | |
177 | case name: { \ | |
178 | JITStubCall stubCall(this, cti_##name); \ | |
179 | stubCall.addArgument(currentInstruction[2].u.operand, regT2); \ | |
180 | stubCall.call(currentInstruction[1].u.operand); \ | |
181 | NEXT_OPCODE(name); \ | |
182 | } | |
183 | #endif // USE(JSVALUE32_64) | |
184 | ||
185 | #define DEFINE_OP(name) \ | |
9dae56ea | 186 | case name: { \ |
ba379fdc | 187 | emit_##name(currentInstruction); \ |
9dae56ea A |
188 | NEXT_OPCODE(name); \ |
189 | } | |
190 | ||
ba379fdc | 191 | #define DEFINE_SLOWCASE_OP(name) \ |
9dae56ea | 192 | case name: { \ |
ba379fdc | 193 | emitSlow_##name(currentInstruction, iter); \ |
9dae56ea A |
194 | NEXT_OPCODE(name); \ |
195 | } | |
196 | ||
197 | void JIT::privateCompileMainPass() | |
198 | { | |
199 | Instruction* instructionsBegin = m_codeBlock->instructions().begin(); | |
200 | unsigned instructionCount = m_codeBlock->instructions().size(); | |
ba379fdc | 201 | |
ba379fdc A |
202 | m_globalResolveInfoIndex = 0; |
203 | m_callLinkInfoIndex = 0; | |
9dae56ea | 204 | |
14957cd0 A |
205 | for (m_bytecodeOffset = 0; m_bytecodeOffset < instructionCount; ) { |
206 | Instruction* currentInstruction = instructionsBegin + m_bytecodeOffset; | |
207 | ASSERT_WITH_MESSAGE(m_interpreter->isOpcode(currentInstruction->u.opcode), "privateCompileMainPass gone bad @ %d", m_bytecodeOffset); | |
9dae56ea A |
208 | |
209 | #if ENABLE(OPCODE_SAMPLING) | |
14957cd0 | 210 | if (m_bytecodeOffset > 0) // Avoid the overhead of sampling op_enter twice. |
9dae56ea A |
211 | sampleInstruction(currentInstruction); |
212 | #endif | |
213 | ||
14957cd0 A |
214 | #if USE(JSVALUE64) |
215 | if (atJumpTarget()) | |
ba379fdc | 216 | killLastResultRegister(); |
9dae56ea | 217 | #endif |
9dae56ea | 218 | |
14957cd0 | 219 | m_labels[m_bytecodeOffset] = label(); |
9dae56ea | 220 | |
6fe7ccc8 A |
221 | #if ENABLE(JIT_VERBOSE) |
222 | dataLog("Old JIT emitting code for bc#%u at offset 0x%lx.\n", m_bytecodeOffset, (long)debugOffset()); | |
223 | #endif | |
224 | ||
ba379fdc A |
225 | switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) { |
226 | DEFINE_BINARY_OP(op_del_by_val) | |
ba379fdc A |
227 | DEFINE_BINARY_OP(op_in) |
228 | DEFINE_BINARY_OP(op_less) | |
229 | DEFINE_BINARY_OP(op_lesseq) | |
6fe7ccc8 A |
230 | DEFINE_BINARY_OP(op_greater) |
231 | DEFINE_BINARY_OP(op_greatereq) | |
ba379fdc | 232 | DEFINE_UNARY_OP(op_is_function) |
ba379fdc | 233 | DEFINE_UNARY_OP(op_is_object) |
ba379fdc A |
234 | DEFINE_UNARY_OP(op_typeof) |
235 | ||
236 | DEFINE_OP(op_add) | |
237 | DEFINE_OP(op_bitand) | |
ba379fdc A |
238 | DEFINE_OP(op_bitor) |
239 | DEFINE_OP(op_bitxor) | |
240 | DEFINE_OP(op_call) | |
241 | DEFINE_OP(op_call_eval) | |
242 | DEFINE_OP(op_call_varargs) | |
243 | DEFINE_OP(op_catch) | |
244 | DEFINE_OP(op_construct) | |
14957cd0 A |
245 | DEFINE_OP(op_get_callee) |
246 | DEFINE_OP(op_create_this) | |
ba379fdc | 247 | DEFINE_OP(op_convert_this) |
14957cd0 | 248 | DEFINE_OP(op_init_lazy_reg) |
ba379fdc A |
249 | DEFINE_OP(op_create_arguments) |
250 | DEFINE_OP(op_debug) | |
251 | DEFINE_OP(op_del_by_id) | |
ba379fdc | 252 | DEFINE_OP(op_div) |
ba379fdc A |
253 | DEFINE_OP(op_end) |
254 | DEFINE_OP(op_enter) | |
14957cd0 | 255 | DEFINE_OP(op_create_activation) |
ba379fdc A |
256 | DEFINE_OP(op_eq) |
257 | DEFINE_OP(op_eq_null) | |
258 | DEFINE_OP(op_get_by_id) | |
14957cd0 | 259 | DEFINE_OP(op_get_arguments_length) |
ba379fdc | 260 | DEFINE_OP(op_get_by_val) |
14957cd0 | 261 | DEFINE_OP(op_get_argument_by_val) |
f9bf01c6 | 262 | DEFINE_OP(op_get_by_pname) |
ba379fdc | 263 | DEFINE_OP(op_get_global_var) |
f9bf01c6 | 264 | DEFINE_OP(op_get_pnames) |
ba379fdc | 265 | DEFINE_OP(op_get_scoped_var) |
14957cd0 | 266 | DEFINE_OP(op_check_has_instance) |
ba379fdc | 267 | DEFINE_OP(op_instanceof) |
6fe7ccc8 A |
268 | DEFINE_OP(op_is_undefined) |
269 | DEFINE_OP(op_is_boolean) | |
270 | DEFINE_OP(op_is_number) | |
271 | DEFINE_OP(op_is_string) | |
ba379fdc A |
272 | DEFINE_OP(op_jeq_null) |
273 | DEFINE_OP(op_jfalse) | |
274 | DEFINE_OP(op_jmp) | |
275 | DEFINE_OP(op_jmp_scopes) | |
276 | DEFINE_OP(op_jneq_null) | |
277 | DEFINE_OP(op_jneq_ptr) | |
f9bf01c6 | 278 | DEFINE_OP(op_jless) |
4e4e5a6f | 279 | DEFINE_OP(op_jlesseq) |
6fe7ccc8 A |
280 | DEFINE_OP(op_jgreater) |
281 | DEFINE_OP(op_jgreatereq) | |
282 | DEFINE_OP(op_jnless) | |
ba379fdc | 283 | DEFINE_OP(op_jnlesseq) |
6fe7ccc8 A |
284 | DEFINE_OP(op_jngreater) |
285 | DEFINE_OP(op_jngreatereq) | |
ba379fdc | 286 | DEFINE_OP(op_jtrue) |
ba379fdc | 287 | DEFINE_OP(op_loop) |
6fe7ccc8 | 288 | DEFINE_OP(op_loop_hint) |
ba379fdc A |
289 | DEFINE_OP(op_loop_if_less) |
290 | DEFINE_OP(op_loop_if_lesseq) | |
6fe7ccc8 A |
291 | DEFINE_OP(op_loop_if_greater) |
292 | DEFINE_OP(op_loop_if_greatereq) | |
ba379fdc | 293 | DEFINE_OP(op_loop_if_true) |
f9bf01c6 | 294 | DEFINE_OP(op_loop_if_false) |
ba379fdc A |
295 | DEFINE_OP(op_lshift) |
296 | DEFINE_OP(op_method_check) | |
297 | DEFINE_OP(op_mod) | |
298 | DEFINE_OP(op_mov) | |
299 | DEFINE_OP(op_mul) | |
ba379fdc | 300 | DEFINE_OP(op_negate) |
ba379fdc A |
301 | DEFINE_OP(op_neq) |
302 | DEFINE_OP(op_neq_null) | |
303 | DEFINE_OP(op_new_array) | |
14957cd0 | 304 | DEFINE_OP(op_new_array_buffer) |
ba379fdc A |
305 | DEFINE_OP(op_new_func) |
306 | DEFINE_OP(op_new_func_exp) | |
307 | DEFINE_OP(op_new_object) | |
308 | DEFINE_OP(op_new_regexp) | |
309 | DEFINE_OP(op_next_pname) | |
310 | DEFINE_OP(op_not) | |
311 | DEFINE_OP(op_nstricteq) | |
312 | DEFINE_OP(op_pop_scope) | |
313 | DEFINE_OP(op_post_dec) | |
314 | DEFINE_OP(op_post_inc) | |
315 | DEFINE_OP(op_pre_dec) | |
316 | DEFINE_OP(op_pre_inc) | |
317 | DEFINE_OP(op_profile_did_call) | |
318 | DEFINE_OP(op_profile_will_call) | |
319 | DEFINE_OP(op_push_new_scope) | |
320 | DEFINE_OP(op_push_scope) | |
6fe7ccc8 A |
321 | case op_put_by_id_transition_direct: |
322 | case op_put_by_id_transition_normal: | |
ba379fdc A |
323 | DEFINE_OP(op_put_by_id) |
324 | DEFINE_OP(op_put_by_index) | |
325 | DEFINE_OP(op_put_by_val) | |
6fe7ccc8 | 326 | DEFINE_OP(op_put_getter_setter) |
ba379fdc A |
327 | DEFINE_OP(op_put_global_var) |
328 | DEFINE_OP(op_put_scoped_var) | |
ba379fdc A |
329 | DEFINE_OP(op_resolve) |
330 | DEFINE_OP(op_resolve_base) | |
14957cd0 | 331 | DEFINE_OP(op_ensure_property_exists) |
ba379fdc | 332 | DEFINE_OP(op_resolve_global) |
4e4e5a6f | 333 | DEFINE_OP(op_resolve_global_dynamic) |
ba379fdc A |
334 | DEFINE_OP(op_resolve_skip) |
335 | DEFINE_OP(op_resolve_with_base) | |
6fe7ccc8 | 336 | DEFINE_OP(op_resolve_with_this) |
ba379fdc | 337 | DEFINE_OP(op_ret) |
14957cd0 A |
338 | DEFINE_OP(op_call_put_result) |
339 | DEFINE_OP(op_ret_object_or_this) | |
ba379fdc | 340 | DEFINE_OP(op_rshift) |
4e4e5a6f | 341 | DEFINE_OP(op_urshift) |
ba379fdc A |
342 | DEFINE_OP(op_strcat) |
343 | DEFINE_OP(op_stricteq) | |
344 | DEFINE_OP(op_sub) | |
345 | DEFINE_OP(op_switch_char) | |
346 | DEFINE_OP(op_switch_imm) | |
347 | DEFINE_OP(op_switch_string) | |
348 | DEFINE_OP(op_tear_off_activation) | |
349 | DEFINE_OP(op_tear_off_arguments) | |
350 | DEFINE_OP(op_throw) | |
14957cd0 | 351 | DEFINE_OP(op_throw_reference_error) |
ba379fdc A |
352 | DEFINE_OP(op_to_jsnumber) |
353 | DEFINE_OP(op_to_primitive) | |
9dae56ea | 354 | |
9dae56ea A |
355 | case op_get_array_length: |
356 | case op_get_by_id_chain: | |
357 | case op_get_by_id_generic: | |
358 | case op_get_by_id_proto: | |
9dae56ea | 359 | case op_get_by_id_self: |
4e4e5a6f A |
360 | case op_get_by_id_getter_chain: |
361 | case op_get_by_id_getter_proto: | |
4e4e5a6f | 362 | case op_get_by_id_getter_self: |
4e4e5a6f A |
363 | case op_get_by_id_custom_chain: |
364 | case op_get_by_id_custom_proto: | |
4e4e5a6f | 365 | case op_get_by_id_custom_self: |
9dae56ea A |
366 | case op_get_string_length: |
367 | case op_put_by_id_generic: | |
368 | case op_put_by_id_replace: | |
369 | case op_put_by_id_transition: | |
370 | ASSERT_NOT_REACHED(); | |
371 | } | |
372 | } | |
373 | ||
6fe7ccc8 | 374 | ASSERT(m_callLinkInfoIndex == m_callStructureStubCompilationInfo.size()); |
9dae56ea A |
375 | |
376 | #ifndef NDEBUG | |
ba379fdc | 377 | // Reset this, in order to guard its use with ASSERTs. |
14957cd0 | 378 | m_bytecodeOffset = (unsigned)-1; |
9dae56ea A |
379 | #endif |
380 | } | |
381 | ||
9dae56ea A |
382 | void JIT::privateCompileLinkPass() |
383 | { | |
384 | unsigned jmpTableCount = m_jmpTable.size(); | |
385 | for (unsigned i = 0; i < jmpTableCount; ++i) | |
14957cd0 | 386 | m_jmpTable[i].from.linkTo(m_labels[m_jmpTable[i].toBytecodeOffset], this); |
9dae56ea A |
387 | m_jmpTable.clear(); |
388 | } | |
389 | ||
390 | void JIT::privateCompileSlowCases() | |
391 | { | |
392 | Instruction* instructionsBegin = m_codeBlock->instructions().begin(); | |
ba379fdc A |
393 | |
394 | m_propertyAccessInstructionIndex = 0; | |
ba379fdc | 395 | m_globalResolveInfoIndex = 0; |
ba379fdc | 396 | m_callLinkInfoIndex = 0; |
6fe7ccc8 A |
397 | |
398 | #if !ASSERT_DISABLED && ENABLE(VALUE_PROFILER) | |
399 | // Use this to assert that slow-path code associates new profiling sites with existing | |
400 | // ValueProfiles rather than creating new ones. This ensures that for a given instruction | |
401 | // (say, get_by_id) we get combined statistics for both the fast-path executions of that | |
402 | // instructions and the slow-path executions. Furthermore, if the slow-path code created | |
403 | // new ValueProfiles then the ValueProfiles would no longer be sorted by bytecode offset, | |
404 | // which would break the invariant necessary to use CodeBlock::valueProfileForBytecodeOffset(). | |
405 | unsigned numberOfValueProfiles = m_codeBlock->numberOfValueProfiles(); | |
406 | #endif | |
9dae56ea A |
407 | |
408 | for (Vector<SlowCaseEntry>::iterator iter = m_slowCases.begin(); iter != m_slowCases.end();) { | |
14957cd0 | 409 | #if USE(JSVALUE64) |
9dae56ea | 410 | killLastResultRegister(); |
ba379fdc | 411 | #endif |
9dae56ea | 412 | |
14957cd0 | 413 | m_bytecodeOffset = iter->to; |
9dae56ea | 414 | #ifndef NDEBUG |
14957cd0 | 415 | unsigned firstTo = m_bytecodeOffset; |
9dae56ea | 416 | #endif |
14957cd0 | 417 | Instruction* currentInstruction = instructionsBegin + m_bytecodeOffset; |
6fe7ccc8 A |
418 | |
419 | #if ENABLE(VALUE_PROFILER) | |
420 | RareCaseProfile* rareCaseProfile = 0; | |
421 | if (m_canBeOptimized) | |
422 | rareCaseProfile = m_codeBlock->addRareCaseProfile(m_bytecodeOffset); | |
423 | #endif | |
424 | ||
425 | #if ENABLE(JIT_VERBOSE) | |
426 | dataLog("Old JIT emitting slow code for bc#%u at offset 0x%lx.\n", m_bytecodeOffset, (long)debugOffset()); | |
427 | #endif | |
9dae56ea | 428 | |
ba379fdc A |
429 | switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) { |
430 | DEFINE_SLOWCASE_OP(op_add) | |
431 | DEFINE_SLOWCASE_OP(op_bitand) | |
ba379fdc A |
432 | DEFINE_SLOWCASE_OP(op_bitor) |
433 | DEFINE_SLOWCASE_OP(op_bitxor) | |
434 | DEFINE_SLOWCASE_OP(op_call) | |
435 | DEFINE_SLOWCASE_OP(op_call_eval) | |
436 | DEFINE_SLOWCASE_OP(op_call_varargs) | |
437 | DEFINE_SLOWCASE_OP(op_construct) | |
ba379fdc | 438 | DEFINE_SLOWCASE_OP(op_convert_this) |
6fe7ccc8 | 439 | DEFINE_SLOWCASE_OP(op_create_this) |
ba379fdc | 440 | DEFINE_SLOWCASE_OP(op_div) |
ba379fdc A |
441 | DEFINE_SLOWCASE_OP(op_eq) |
442 | DEFINE_SLOWCASE_OP(op_get_by_id) | |
14957cd0 | 443 | DEFINE_SLOWCASE_OP(op_get_arguments_length) |
ba379fdc | 444 | DEFINE_SLOWCASE_OP(op_get_by_val) |
14957cd0 | 445 | DEFINE_SLOWCASE_OP(op_get_argument_by_val) |
f9bf01c6 | 446 | DEFINE_SLOWCASE_OP(op_get_by_pname) |
14957cd0 | 447 | DEFINE_SLOWCASE_OP(op_check_has_instance) |
ba379fdc A |
448 | DEFINE_SLOWCASE_OP(op_instanceof) |
449 | DEFINE_SLOWCASE_OP(op_jfalse) | |
f9bf01c6 | 450 | DEFINE_SLOWCASE_OP(op_jless) |
4e4e5a6f | 451 | DEFINE_SLOWCASE_OP(op_jlesseq) |
6fe7ccc8 A |
452 | DEFINE_SLOWCASE_OP(op_jgreater) |
453 | DEFINE_SLOWCASE_OP(op_jgreatereq) | |
454 | DEFINE_SLOWCASE_OP(op_jnless) | |
ba379fdc | 455 | DEFINE_SLOWCASE_OP(op_jnlesseq) |
6fe7ccc8 A |
456 | DEFINE_SLOWCASE_OP(op_jngreater) |
457 | DEFINE_SLOWCASE_OP(op_jngreatereq) | |
ba379fdc A |
458 | DEFINE_SLOWCASE_OP(op_jtrue) |
459 | DEFINE_SLOWCASE_OP(op_loop_if_less) | |
460 | DEFINE_SLOWCASE_OP(op_loop_if_lesseq) | |
6fe7ccc8 A |
461 | DEFINE_SLOWCASE_OP(op_loop_if_greater) |
462 | DEFINE_SLOWCASE_OP(op_loop_if_greatereq) | |
ba379fdc | 463 | DEFINE_SLOWCASE_OP(op_loop_if_true) |
f9bf01c6 | 464 | DEFINE_SLOWCASE_OP(op_loop_if_false) |
ba379fdc A |
465 | DEFINE_SLOWCASE_OP(op_lshift) |
466 | DEFINE_SLOWCASE_OP(op_method_check) | |
467 | DEFINE_SLOWCASE_OP(op_mod) | |
468 | DEFINE_SLOWCASE_OP(op_mul) | |
ba379fdc | 469 | DEFINE_SLOWCASE_OP(op_negate) |
ba379fdc | 470 | DEFINE_SLOWCASE_OP(op_neq) |
6fe7ccc8 A |
471 | DEFINE_SLOWCASE_OP(op_new_array) |
472 | DEFINE_SLOWCASE_OP(op_new_object) | |
473 | DEFINE_SLOWCASE_OP(op_new_func) | |
474 | DEFINE_SLOWCASE_OP(op_new_func_exp) | |
ba379fdc A |
475 | DEFINE_SLOWCASE_OP(op_not) |
476 | DEFINE_SLOWCASE_OP(op_nstricteq) | |
477 | DEFINE_SLOWCASE_OP(op_post_dec) | |
478 | DEFINE_SLOWCASE_OP(op_post_inc) | |
479 | DEFINE_SLOWCASE_OP(op_pre_dec) | |
480 | DEFINE_SLOWCASE_OP(op_pre_inc) | |
6fe7ccc8 A |
481 | case op_put_by_id_transition_direct: |
482 | case op_put_by_id_transition_normal: | |
ba379fdc A |
483 | DEFINE_SLOWCASE_OP(op_put_by_id) |
484 | DEFINE_SLOWCASE_OP(op_put_by_val) | |
ba379fdc | 485 | DEFINE_SLOWCASE_OP(op_resolve_global) |
4e4e5a6f | 486 | DEFINE_SLOWCASE_OP(op_resolve_global_dynamic) |
ba379fdc | 487 | DEFINE_SLOWCASE_OP(op_rshift) |
4e4e5a6f | 488 | DEFINE_SLOWCASE_OP(op_urshift) |
ba379fdc A |
489 | DEFINE_SLOWCASE_OP(op_stricteq) |
490 | DEFINE_SLOWCASE_OP(op_sub) | |
491 | DEFINE_SLOWCASE_OP(op_to_jsnumber) | |
492 | DEFINE_SLOWCASE_OP(op_to_primitive) | |
9dae56ea A |
493 | default: |
494 | ASSERT_NOT_REACHED(); | |
495 | } | |
496 | ||
497 | ASSERT_WITH_MESSAGE(iter == m_slowCases.end() || firstTo != iter->to,"Not enough jumps linked in slow case codegen."); | |
498 | ASSERT_WITH_MESSAGE(firstTo == (iter - 1)->to, "Too many jumps linked in slow case codegen."); | |
6fe7ccc8 A |
499 | |
500 | #if ENABLE(VALUE_PROFILER) | |
501 | if (m_canBeOptimized) | |
502 | add32(TrustedImm32(1), AbsoluteAddress(&rareCaseProfile->m_counter)); | |
503 | #endif | |
9dae56ea A |
504 | |
505 | emitJumpSlowToHot(jump(), 0); | |
506 | } | |
507 | ||
6fe7ccc8 A |
508 | ASSERT(m_propertyAccessInstructionIndex == m_propertyAccessCompilationInfo.size()); |
509 | ASSERT(m_callLinkInfoIndex == m_callStructureStubCompilationInfo.size()); | |
510 | #if ENABLE(VALUE_PROFILER) | |
511 | ASSERT(numberOfValueProfiles == m_codeBlock->numberOfValueProfiles()); | |
9dae56ea | 512 | #endif |
9dae56ea A |
513 | |
514 | #ifndef NDEBUG | |
ba379fdc | 515 | // Reset this, in order to guard its use with ASSERTs. |
14957cd0 | 516 | m_bytecodeOffset = (unsigned)-1; |
9dae56ea A |
517 | #endif |
518 | } | |
519 | ||
6fe7ccc8 A |
520 | ALWAYS_INLINE void PropertyStubCompilationInfo::copyToStubInfo(StructureStubInfo& info, LinkBuffer &linkBuffer) |
521 | { | |
522 | ASSERT(bytecodeIndex != std::numeric_limits<unsigned>::max()); | |
523 | info.bytecodeIndex = bytecodeIndex; | |
524 | info.callReturnLocation = linkBuffer.locationOf(callReturnLocation); | |
525 | info.hotPathBegin = linkBuffer.locationOf(hotPathBegin); | |
526 | ||
527 | switch (m_type) { | |
528 | case MethodCheck: { | |
529 | CodeLocationDataLabelPtr structureToCompareLocation = linkBuffer.locationOf(methodCheckStructureToCompare); | |
530 | info.patch.baseline.methodCheckProtoObj = MacroAssembler::differenceBetweenCodePtr(structureToCompareLocation, linkBuffer.locationOf(methodCheckProtoObj)); | |
531 | info.patch.baseline.methodCheckProtoStructureToCompare = MacroAssembler::differenceBetweenCodePtr(structureToCompareLocation, linkBuffer.locationOf(methodCheckProtoStructureToCompare)); | |
532 | info.patch.baseline.methodCheckPutFunction = MacroAssembler::differenceBetweenCodePtr(structureToCompareLocation, linkBuffer.locationOf(methodCheckPutFunction)); | |
533 | // No break - fall through to GetById. | |
534 | } | |
535 | case GetById: { | |
536 | CodeLocationLabel hotPathBeginLocation = linkBuffer.locationOf(hotPathBegin); | |
537 | info.patch.baseline.u.get.structureToCompare = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(getStructureToCompare)); | |
538 | info.patch.baseline.u.get.structureCheck = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(getStructureCheck)); | |
539 | #if USE(JSVALUE64) | |
540 | info.patch.baseline.u.get.displacementLabel = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(getDisplacementLabel)); | |
541 | #else | |
542 | info.patch.baseline.u.get.displacementLabel1 = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(getDisplacementLabel1)); | |
543 | info.patch.baseline.u.get.displacementLabel2 = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(getDisplacementLabel2)); | |
544 | #endif | |
545 | info.patch.baseline.u.get.putResult = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(getPutResult)); | |
546 | info.patch.baseline.u.get.coldPathBegin = MacroAssembler::differenceBetweenCodePtr(linkBuffer.locationOf(getColdPathBegin), linkBuffer.locationOf(callReturnLocation)); | |
547 | break; | |
548 | } | |
549 | case PutById: | |
550 | CodeLocationLabel hotPathBeginLocation = linkBuffer.locationOf(hotPathBegin); | |
551 | info.patch.baseline.u.put.structureToCompare = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(putStructureToCompare)); | |
552 | #if USE(JSVALUE64) | |
553 | info.patch.baseline.u.put.displacementLabel = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(putDisplacementLabel)); | |
554 | #else | |
555 | info.patch.baseline.u.put.displacementLabel1 = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(putDisplacementLabel1)); | |
556 | info.patch.baseline.u.put.displacementLabel2 = MacroAssembler::differenceBetweenCodePtr(hotPathBeginLocation, linkBuffer.locationOf(putDisplacementLabel2)); | |
557 | #endif | |
558 | break; | |
559 | } | |
560 | } | |
561 | ||
562 | JITCode JIT::privateCompile(CodePtr* functionEntryArityCheck, JITCompilationEffort effort) | |
9dae56ea | 563 | { |
6fe7ccc8 A |
564 | #if ENABLE(JIT_VERBOSE_OSR) |
565 | printf("Compiling JIT code!\n"); | |
566 | #endif | |
567 | ||
568 | #if ENABLE(VALUE_PROFILER) | |
569 | m_canBeOptimized = m_codeBlock->canCompileWithDFG(); | |
570 | #endif | |
571 | ||
14957cd0 A |
572 | // Just add a little bit of randomness to the codegen |
573 | if (m_randomGenerator.getUint32() & 1) | |
574 | nop(); | |
9dae56ea | 575 | |
ba379fdc A |
576 | preserveReturnAddressAfterCall(regT2); |
577 | emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC); | |
6fe7ccc8 | 578 | emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock); |
9dae56ea | 579 | |
14957cd0 A |
580 | Label beginLabel(this); |
581 | ||
582 | sampleCodeBlock(m_codeBlock); | |
583 | #if ENABLE(OPCODE_SAMPLING) | |
584 | sampleInstruction(m_codeBlock->instructions().begin()); | |
585 | #endif | |
586 | ||
587 | Jump registerFileCheck; | |
9dae56ea | 588 | if (m_codeBlock->codeType() == FunctionCode) { |
6fe7ccc8 A |
589 | #if ENABLE(DFG_JIT) |
590 | #if DFG_ENABLE(SUCCESS_STATS) | |
14957cd0 A |
591 | static SamplingCounter counter("orignalJIT"); |
592 | emitCount(counter); | |
593 | #endif | |
6fe7ccc8 | 594 | #endif |
14957cd0 | 595 | |
6fe7ccc8 A |
596 | #if ENABLE(VALUE_PROFILER) |
597 | ASSERT(m_bytecodeOffset == (unsigned)-1); | |
598 | if (shouldEmitProfiling()) { | |
599 | for (int argument = 0; argument < m_codeBlock->numParameters(); ++argument) { | |
600 | // If this is a constructor, then we want to put in a dummy profiling site (to | |
601 | // keep things consistent) but we don't actually want to record the dummy value. | |
602 | if (m_codeBlock->m_isConstructor && !argument) | |
603 | continue; | |
604 | int offset = CallFrame::argumentOffsetIncludingThis(argument) * static_cast<int>(sizeof(Register)); | |
605 | #if USE(JSVALUE64) | |
606 | loadPtr(Address(callFrameRegister, offset), regT0); | |
607 | #elif USE(JSVALUE32_64) | |
608 | load32(Address(callFrameRegister, offset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); | |
609 | load32(Address(callFrameRegister, offset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); | |
610 | #endif | |
611 | emitValueProfilingSite(m_codeBlock->valueProfileForArgument(argument)); | |
612 | } | |
613 | } | |
614 | #endif | |
9dae56ea | 615 | |
6fe7ccc8 | 616 | addPtr(TrustedImm32(m_codeBlock->m_numCalleeRegisters * sizeof(Register)), callFrameRegister, regT1); |
14957cd0 | 617 | registerFileCheck = branchPtr(Below, AbsoluteAddress(m_globalData->interpreter->registerFile().addressOfEnd()), regT1); |
9dae56ea A |
618 | } |
619 | ||
14957cd0 | 620 | Label functionBody = label(); |
6fe7ccc8 A |
621 | |
622 | #if ENABLE(VALUE_PROFILER) | |
623 | if (m_canBeOptimized) | |
624 | add32(TrustedImm32(1), AbsoluteAddress(&m_codeBlock->m_executionEntryCount)); | |
625 | #endif | |
14957cd0 | 626 | |
9dae56ea A |
627 | privateCompileMainPass(); |
628 | privateCompileLinkPass(); | |
629 | privateCompileSlowCases(); | |
630 | ||
14957cd0 | 631 | Label arityCheck; |
9dae56ea | 632 | if (m_codeBlock->codeType() == FunctionCode) { |
14957cd0 A |
633 | registerFileCheck.link(this); |
634 | m_bytecodeOffset = 0; | |
ba379fdc | 635 | JITStubCall(this, cti_register_file_check).call(); |
9dae56ea | 636 | #ifndef NDEBUG |
14957cd0 | 637 | m_bytecodeOffset = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs. |
9dae56ea | 638 | #endif |
14957cd0 A |
639 | jump(functionBody); |
640 | ||
641 | arityCheck = label(); | |
642 | preserveReturnAddressAfterCall(regT2); | |
643 | emitPutToCallFrameHeader(regT2, RegisterFile::ReturnPC); | |
6fe7ccc8 | 644 | emitPutImmediateToCallFrameHeader(m_codeBlock, RegisterFile::CodeBlock); |
14957cd0 | 645 | |
6fe7ccc8 A |
646 | load32(payloadFor(RegisterFile::ArgumentCount), regT1); |
647 | branch32(AboveOrEqual, regT1, TrustedImm32(m_codeBlock->m_numParameters)).linkTo(beginLabel, this); | |
648 | ||
649 | m_bytecodeOffset = 0; | |
14957cd0 | 650 | JITStubCall(this, m_codeBlock->m_isConstructor ? cti_op_construct_arityCheck : cti_op_call_arityCheck).call(callFrameRegister); |
6fe7ccc8 A |
651 | #if !ASSERT_DISABLED |
652 | m_bytecodeOffset = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs. | |
653 | #endif | |
14957cd0 A |
654 | |
655 | jump(beginLabel); | |
9dae56ea A |
656 | } |
657 | ||
658 | ASSERT(m_jmpTable.isEmpty()); | |
659 | ||
6fe7ccc8 A |
660 | LinkBuffer patchBuffer(*m_globalData, this, m_codeBlock, effort); |
661 | if (patchBuffer.didFailToAllocate()) | |
662 | return JITCode(); | |
9dae56ea A |
663 | |
664 | // Translate vPC offsets into addresses in JIT generated code, for switch tables. | |
665 | for (unsigned i = 0; i < m_switches.size(); ++i) { | |
666 | SwitchRecord record = m_switches[i]; | |
14957cd0 | 667 | unsigned bytecodeOffset = record.bytecodeOffset; |
9dae56ea A |
668 | |
669 | if (record.type != SwitchRecord::String) { | |
670 | ASSERT(record.type == SwitchRecord::Immediate || record.type == SwitchRecord::Character); | |
671 | ASSERT(record.jumpTable.simpleJumpTable->branchOffsets.size() == record.jumpTable.simpleJumpTable->ctiOffsets.size()); | |
672 | ||
14957cd0 | 673 | record.jumpTable.simpleJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeOffset + record.defaultOffset]); |
9dae56ea A |
674 | |
675 | for (unsigned j = 0; j < record.jumpTable.simpleJumpTable->branchOffsets.size(); ++j) { | |
676 | unsigned offset = record.jumpTable.simpleJumpTable->branchOffsets[j]; | |
14957cd0 | 677 | record.jumpTable.simpleJumpTable->ctiOffsets[j] = offset ? patchBuffer.locationOf(m_labels[bytecodeOffset + offset]) : record.jumpTable.simpleJumpTable->ctiDefault; |
9dae56ea A |
678 | } |
679 | } else { | |
680 | ASSERT(record.type == SwitchRecord::String); | |
681 | ||
14957cd0 | 682 | record.jumpTable.stringJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeOffset + record.defaultOffset]); |
9dae56ea A |
683 | |
684 | StringJumpTable::StringOffsetTable::iterator end = record.jumpTable.stringJumpTable->offsetTable.end(); | |
685 | for (StringJumpTable::StringOffsetTable::iterator it = record.jumpTable.stringJumpTable->offsetTable.begin(); it != end; ++it) { | |
686 | unsigned offset = it->second.branchOffset; | |
14957cd0 | 687 | it->second.ctiOffset = offset ? patchBuffer.locationOf(m_labels[bytecodeOffset + offset]) : record.jumpTable.stringJumpTable->ctiDefault; |
9dae56ea A |
688 | } |
689 | } | |
690 | } | |
691 | ||
692 | for (size_t i = 0; i < m_codeBlock->numberOfExceptionHandlers(); ++i) { | |
693 | HandlerInfo& handler = m_codeBlock->exceptionHandler(i); | |
ba379fdc | 694 | handler.nativeCode = patchBuffer.locationOf(m_labels[handler.target]); |
9dae56ea A |
695 | } |
696 | ||
697 | for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { | |
698 | if (iter->to) | |
ba379fdc | 699 | patchBuffer.link(iter->from, FunctionPtr(iter->to)); |
9dae56ea A |
700 | } |
701 | ||
14957cd0 | 702 | if (m_codeBlock->needsCallReturnIndices()) { |
ba379fdc | 703 | m_codeBlock->callReturnIndexVector().reserveCapacity(m_calls.size()); |
9dae56ea | 704 | for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) |
14957cd0 | 705 | m_codeBlock->callReturnIndexVector().append(CallReturnOffsetToBytecodeOffset(patchBuffer.returnAddressOffset(iter->from), iter->bytecodeOffset)); |
9dae56ea A |
706 | } |
707 | ||
6fe7ccc8 A |
708 | m_codeBlock->setNumberOfStructureStubInfos(m_propertyAccessCompilationInfo.size()); |
709 | for (unsigned i = 0; i < m_propertyAccessCompilationInfo.size(); ++i) | |
710 | m_propertyAccessCompilationInfo[i].copyToStubInfo(m_codeBlock->structureStubInfo(i), patchBuffer); | |
711 | m_codeBlock->setNumberOfCallLinkInfos(m_callStructureStubCompilationInfo.size()); | |
9dae56ea A |
712 | for (unsigned i = 0; i < m_codeBlock->numberOfCallLinkInfos(); ++i) { |
713 | CallLinkInfo& info = m_codeBlock->callLinkInfo(i); | |
6fe7ccc8 A |
714 | info.callType = m_callStructureStubCompilationInfo[i].callType; |
715 | info.bytecodeIndex = m_callStructureStubCompilationInfo[i].bytecodeIndex; | |
716 | info.callReturnLocation = CodeLocationLabel(patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation)); | |
ba379fdc A |
717 | info.hotPathBegin = patchBuffer.locationOf(m_callStructureStubCompilationInfo[i].hotPathBegin); |
718 | info.hotPathOther = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].hotPathOther); | |
719 | } | |
ba379fdc A |
720 | unsigned methodCallCount = m_methodCallCompilationInfo.size(); |
721 | m_codeBlock->addMethodCallLinkInfos(methodCallCount); | |
722 | for (unsigned i = 0; i < methodCallCount; ++i) { | |
723 | MethodCallLinkInfo& info = m_codeBlock->methodCallLinkInfo(i); | |
6fe7ccc8 | 724 | info.bytecodeIndex = m_methodCallCompilationInfo[i].bytecodeIndex; |
14957cd0 | 725 | info.cachedStructure.setLocation(patchBuffer.locationOf(m_methodCallCompilationInfo[i].structureToCompare)); |
ba379fdc | 726 | info.callReturnLocation = m_codeBlock->structureStubInfo(m_methodCallCompilationInfo[i].propertyAccessIndex).callReturnLocation; |
9dae56ea A |
727 | } |
728 | ||
6fe7ccc8 A |
729 | #if ENABLE(DFG_JIT) || ENABLE(LLINT) |
730 | if (canBeOptimized() | |
731 | #if ENABLE(LLINT) | |
732 | || true | |
733 | #endif | |
734 | ) { | |
735 | CompactJITCodeMap::Encoder jitCodeMapEncoder; | |
736 | for (unsigned bytecodeOffset = 0; bytecodeOffset < m_labels.size(); ++bytecodeOffset) { | |
737 | if (m_labels[bytecodeOffset].isSet()) | |
738 | jitCodeMapEncoder.append(bytecodeOffset, patchBuffer.offsetOf(m_labels[bytecodeOffset])); | |
739 | } | |
740 | m_codeBlock->setJITCodeMap(jitCodeMapEncoder.finish()); | |
741 | } | |
742 | #endif | |
743 | ||
14957cd0 A |
744 | if (m_codeBlock->codeType() == FunctionCode && functionEntryArityCheck) |
745 | *functionEntryArityCheck = patchBuffer.locationOf(arityCheck); | |
6fe7ccc8 A |
746 | |
747 | CodeRef result = patchBuffer.finalizeCode(); | |
748 | ||
749 | m_globalData->machineCodeBytesPerBytecodeWordForBaselineJIT.add( | |
750 | static_cast<double>(result.size()) / | |
751 | static_cast<double>(m_codeBlock->instructions().size())); | |
752 | ||
753 | #if ENABLE(JIT_VERBOSE) | |
754 | dataLog("JIT generated code for %p at [%p, %p).\n", m_codeBlock, result.executableMemory()->start(), result.executableMemory()->end()); | |
755 | #endif | |
756 | ||
757 | return JITCode(result, JITCode::BaselineJIT); | |
9dae56ea A |
758 | } |
759 | ||
6fe7ccc8 | 760 | void JIT::linkFor(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JIT::CodePtr code, CallLinkInfo* callLinkInfo, JSGlobalData* globalData, CodeSpecializationKind kind) |
ba379fdc | 761 | { |
14957cd0 | 762 | RepatchBuffer repatchBuffer(callerCodeBlock); |
9dae56ea | 763 | |
6fe7ccc8 A |
764 | ASSERT(!callLinkInfo->isLinked()); |
765 | callLinkInfo->callee.set(*globalData, callLinkInfo->hotPathBegin, callerCodeBlock->ownerExecutable(), callee); | |
766 | callLinkInfo->lastSeenCallee.set(*globalData, callerCodeBlock->ownerExecutable(), callee); | |
767 | repatchBuffer.relink(callLinkInfo->hotPathOther, code); | |
14957cd0 | 768 | |
6fe7ccc8 A |
769 | if (calleeCodeBlock) |
770 | calleeCodeBlock->linkIncomingCall(callLinkInfo); | |
9dae56ea | 771 | |
6fe7ccc8 A |
772 | // Patch the slow patch so we do not continue to try to link. |
773 | if (kind == CodeForCall) { | |
774 | repatchBuffer.relink(CodeLocationNearCall(callLinkInfo->callReturnLocation), globalData->jitStubs->ctiVirtualCall()); | |
775 | return; | |
ba379fdc A |
776 | } |
777 | ||
6fe7ccc8 A |
778 | ASSERT(kind == CodeForConstruct); |
779 | repatchBuffer.relink(CodeLocationNearCall(callLinkInfo->callReturnLocation), globalData->jitStubs->ctiVirtualConstruct()); | |
9dae56ea A |
780 | } |
781 | ||
782 | } // namespace JSC | |
783 | ||
784 | #endif // ENABLE(JIT) |