1 /*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28
29 #if ENABLE(JIT)
30 #if USE(JSVALUE32_64)
31 #include "JIT.h"
32
33 #include "JITInlineMethods.h"
34 #include "JITStubCall.h"
35 #include "JSArray.h"
36 #include "JSCell.h"
37 #include "JSFunction.h"
38 #include "JSPropertyNameIterator.h"
39 #include "LinkBuffer.h"
40
41 namespace JSC {
42
privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool> * executablePool,JSGlobalData * globalData,TrampolineStructure * trampolines)43 void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executablePool, JSGlobalData* globalData, TrampolineStructure *trampolines)
44 {
45 #if ENABLE(JIT_USE_SOFT_MODULO)
46 Label softModBegin = align();
47 softModulo();
48 #endif
49 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
50 // (1) This function provides fast property access for string length
51 Label stringLengthBegin = align();
52
53 // regT0 holds payload, regT1 holds tag
54
55 Jump string_failureCases1 = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
56 Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr));
57
58 // Checks out okay! - get the length from the Ustring.
59 load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_length)), regT2);
60
61 Jump string_failureCases3 = branch32(Above, regT2, TrustedImm32(INT_MAX));
62 move(regT2, regT0);
63 move(TrustedImm32(JSValue::Int32Tag), regT1);
64
65 ret();
66 #endif
67
68 JumpList callLinkFailures;
69 // (2) Trampolines for the slow cases of op_call / op_call_eval / op_construct.
70 #if ENABLE(JIT_OPTIMIZE_CALL)
71 // VirtualCallLink Trampoline
72 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
73 Label virtualCallLinkBegin = align();
74 compileOpCallInitializeCallFrame();
75 preserveReturnAddressAfterCall(regT3);
76 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
77 restoreArgumentReference();
78 Call callLazyLinkCall = call();
79 callLinkFailures.append(branchTestPtr(Zero, regT0));
80 restoreReturnAddressBeforeReturn(regT3);
81 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
82 jump(regT0);
83
84 // VirtualConstructLink Trampoline
85 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
86 Label virtualConstructLinkBegin = align();
87 compileOpCallInitializeCallFrame();
88 preserveReturnAddressAfterCall(regT3);
89 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
90 restoreArgumentReference();
91 Call callLazyLinkConstruct = call();
92 restoreReturnAddressBeforeReturn(regT3);
93 callLinkFailures.append(branchTestPtr(Zero, regT0));
94 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
95 jump(regT0);
96
97 #endif // ENABLE(JIT_OPTIMIZE_CALL)
98
99 // VirtualCall Trampoline
100 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
101 Label virtualCallBegin = align();
102 compileOpCallInitializeCallFrame();
103
104 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
105
106 Jump hasCodeBlock3 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForCall)), TrustedImm32(0));
107 preserveReturnAddressAfterCall(regT3);
108 restoreArgumentReference();
109 Call callCompileCall = call();
110 callLinkFailures.append(branchTestPtr(Zero, regT0));
111 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
112 restoreReturnAddressBeforeReturn(regT3);
113 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
114 hasCodeBlock3.link(this);
115
116 loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForCallWithArityCheck)), regT0);
117 jump(regT0);
118
119 // VirtualConstruct Trampoline
120 // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable.
121 Label virtualConstructBegin = align();
122 compileOpCallInitializeCallFrame();
123
124 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
125
126 Jump hasCodeBlock4 = branch32(GreaterThanOrEqual, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParametersForConstruct)), TrustedImm32(0));
127 preserveReturnAddressAfterCall(regT3);
128 restoreArgumentReference();
129 Call callCompileCconstruct = call();
130 callLinkFailures.append(branchTestPtr(Zero, regT0));
131 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT1);
132 restoreReturnAddressBeforeReturn(regT3);
133 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
134 hasCodeBlock4.link(this);
135
136 loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCodeForConstructWithArityCheck)), regT0);
137 jump(regT0);
138
139 // If the parser fails we want to be able to be able to keep going,
140 // So we handle this as a parse failure.
141 callLinkFailures.link(this);
142 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1);
143 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
144 restoreReturnAddressBeforeReturn(regT1);
145 move(TrustedImmPtr(&globalData->exceptionLocation), regT2);
146 storePtr(regT1, regT2);
147 poke(callFrameRegister, 1 + OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
148 poke(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()));
149 ret();
150
151 // NativeCall Trampoline
152 Label nativeCallThunk = privateCompileCTINativeCall(globalData);
153 Label nativeConstructThunk = privateCompileCTINativeCall(globalData, true);
154
155 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
156 Call string_failureCases1Call = makeTailRecursiveCall(string_failureCases1);
157 Call string_failureCases2Call = makeTailRecursiveCall(string_failureCases2);
158 Call string_failureCases3Call = makeTailRecursiveCall(string_failureCases3);
159 #endif
160
161 // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
162 LinkBuffer patchBuffer(this, m_globalData->executableAllocator.poolForSize(m_assembler.size()), 0);
163
164 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
165 patchBuffer.link(string_failureCases1Call, FunctionPtr(cti_op_get_by_id_string_fail));
166 patchBuffer.link(string_failureCases2Call, FunctionPtr(cti_op_get_by_id_string_fail));
167 patchBuffer.link(string_failureCases3Call, FunctionPtr(cti_op_get_by_id_string_fail));
168 #endif
169 #if ENABLE(JIT_OPTIMIZE_CALL)
170 patchBuffer.link(callLazyLinkCall, FunctionPtr(cti_vm_lazyLinkCall));
171 patchBuffer.link(callLazyLinkConstruct, FunctionPtr(cti_vm_lazyLinkConstruct));
172 #endif
173 patchBuffer.link(callCompileCall, FunctionPtr(cti_op_call_jitCompile));
174 patchBuffer.link(callCompileCconstruct, FunctionPtr(cti_op_construct_jitCompile));
175
176 CodeRef finalCode = patchBuffer.finalizeCode();
177 *executablePool = finalCode.m_executablePool;
178
179 trampolines->ctiVirtualCall = patchBuffer.trampolineAt(virtualCallBegin);
180 trampolines->ctiVirtualConstruct = patchBuffer.trampolineAt(virtualConstructBegin);
181 trampolines->ctiNativeCall = patchBuffer.trampolineAt(nativeCallThunk);
182 trampolines->ctiNativeConstruct = patchBuffer.trampolineAt(nativeConstructThunk);
183 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
184 trampolines->ctiStringLengthTrampoline = patchBuffer.trampolineAt(stringLengthBegin);
185 #endif
186 #if ENABLE(JIT_OPTIMIZE_CALL)
187 trampolines->ctiVirtualCallLink = patchBuffer.trampolineAt(virtualCallLinkBegin);
188 trampolines->ctiVirtualConstructLink = patchBuffer.trampolineAt(virtualConstructLinkBegin);
189 #endif
190 #if ENABLE(JIT_USE_SOFT_MODULO)
191 trampolines->ctiSoftModulo = patchBuffer.trampolineAt(softModBegin);
192 #endif
193 }
194
privateCompileCTINativeCall(JSGlobalData * globalData,bool isConstruct)195 JIT::Label JIT::privateCompileCTINativeCall(JSGlobalData* globalData, bool isConstruct)
196 {
197 int executableOffsetToFunction = isConstruct ? OBJECT_OFFSETOF(NativeExecutable, m_constructor) : OBJECT_OFFSETOF(NativeExecutable, m_function);
198
199 Label nativeCallThunk = align();
200
201 emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock);
202
203 #if CPU(X86)
204 // Load caller frame's scope chain into this callframe so that whatever we call can
205 // get to its global data.
206 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
207 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
208 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
209
210 peek(regT1);
211 emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC);
212
213 // Calling convention: f(ecx, edx, ...);
214 // Host function signature: f(ExecState*);
215 move(callFrameRegister, X86Registers::ecx);
216
217 subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
218
219 // call the function
220 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT1);
221 loadPtr(Address(regT1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT1);
222 move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
223 call(Address(regT1, executableOffsetToFunction));
224
225 addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister);
226
227 #elif CPU(ARM)
228 // Load caller frame's scope chain into this callframe so that whatever we call can
229 // get to its global data.
230 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
231 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
232 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
233
234 preserveReturnAddressAfterCall(regT3); // Callee preserved
235 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
236
237 // Calling convention: f(r0 == regT0, r1 == regT1, ...);
238 // Host function signature: f(ExecState*);
239 move(callFrameRegister, ARMRegisters::r0);
240
241 // call the function
242 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1);
243 move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
244 loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
245 call(Address(regT2, executableOffsetToFunction));
246
247 restoreReturnAddressBeforeReturn(regT3);
248 #elif CPU(SH4)
249 // Load caller frame's scope chain into this callframe so that whatever we call can
250 // get to its global data.
251 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
252 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
253 emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
254
255 preserveReturnAddressAfterCall(regT3); // Callee preserved
256 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
257
258 // Calling convention: f(r0 == regT4, r1 == regT5, ...);
259 // Host function signature: f(ExecState*);
260 move(callFrameRegister, regT4);
261
262 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT5);
263 move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
264 loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
265
266 call(Address(regT2, executableOffsetToFunction), regT0);
267 restoreReturnAddressBeforeReturn(regT3);
268 #elif CPU(MIPS)
269 // Load caller frame's scope chain into this callframe so that whatever we call can
270 // get to its global data.
271 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
272 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
273 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
274
275 preserveReturnAddressAfterCall(regT3); // Callee preserved
276 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
277
278 // Calling convention: f(a0, a1, a2, a3);
279 // Host function signature: f(ExecState*);
280
281 // Allocate stack space for 16 bytes (8-byte aligned)
282 // 16 bytes (unused) for 4 arguments
283 subPtr(TrustedImm32(16), stackPointerRegister);
284
285 // Setup arg0
286 move(callFrameRegister, MIPSRegisters::a0);
287
288 // Call
289 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2);
290 loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
291 move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
292 call(Address(regT2, executableOffsetToFunction));
293
294 // Restore stack space
295 addPtr(TrustedImm32(16), stackPointerRegister);
296
297 restoreReturnAddressBeforeReturn(regT3);
298
299 #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
300 #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
301 #else
302 UNUSED_PARAM(executableOffsetToFunction);
303 breakpoint();
304 #endif // CPU(X86)
305
306 // Check for an exception
307 Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
308
309 // Return.
310 ret();
311
312 // Handle an exception
313 sawException.link(this);
314
315 // Grab the return address.
316 preserveReturnAddressAfterCall(regT1);
317
318 move(TrustedImmPtr(&globalData->exceptionLocation), regT2);
319 storePtr(regT1, regT2);
320 poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
321
322 // Set the return address.
323 move(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1);
324 restoreReturnAddressBeforeReturn(regT1);
325
326 ret();
327
328 return nativeCallThunk;
329 }
330
privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool,JSGlobalData * globalData,NativeFunction func)331 JIT::CodePtr JIT::privateCompileCTINativeCall(PassRefPtr<ExecutablePool> executablePool, JSGlobalData* globalData, NativeFunction func)
332 {
333 Call nativeCall;
334 Label nativeCallThunk = align();
335
336 emitPutImmediateToCallFrameHeader(0, RegisterFile::CodeBlock);
337
338 #if CPU(X86)
339 // Load caller frame's scope chain into this callframe so that whatever we call can
340 // get to its global data.
341 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
342 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
343 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
344
345 peek(regT1);
346 emitPutToCallFrameHeader(regT1, RegisterFile::ReturnPC);
347
348 // Calling convention: f(ecx, edx, ...);
349 // Host function signature: f(ExecState*);
350 move(callFrameRegister, X86Registers::ecx);
351
352 subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
353
354 move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
355
356 // call the function
357 nativeCall = call();
358
359 addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister);
360
361 #elif CPU(ARM)
362 // Load caller frame's scope chain into this callframe so that whatever we call can
363 // get to its global data.
364 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
365 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
366 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
367
368 preserveReturnAddressAfterCall(regT3); // Callee preserved
369 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
370
371 // Calling convention: f(r0 == regT0, r1 == regT1, ...);
372 // Host function signature: f(ExecState*);
373 move(callFrameRegister, ARMRegisters::r0);
374
375 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, ARMRegisters::r1);
376 move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
377 loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
378
379 // call the function
380 nativeCall = call();
381
382 restoreReturnAddressBeforeReturn(regT3);
383
384 #elif CPU(MIPS)
385 // Load caller frame's scope chain into this callframe so that whatever we call can
386 // get to its global data.
387 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT0);
388 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT0);
389 emitPutCellToCallFrameHeader(regT1, RegisterFile::ScopeChain);
390
391 preserveReturnAddressAfterCall(regT3); // Callee preserved
392 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
393
394 // Calling convention: f(a0, a1, a2, a3);
395 // Host function signature: f(ExecState*);
396
397 // Allocate stack space for 16 bytes (8-byte aligned)
398 // 16 bytes (unused) for 4 arguments
399 subPtr(TrustedImm32(16), stackPointerRegister);
400
401 // Setup arg0
402 move(callFrameRegister, MIPSRegisters::a0);
403
404 // Call
405 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, MIPSRegisters::a2);
406 loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
407 move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
408
409 // call the function
410 nativeCall = call();
411
412 // Restore stack space
413 addPtr(TrustedImm32(16), stackPointerRegister);
414
415 restoreReturnAddressBeforeReturn(regT3);
416 #elif CPU(SH4)
417 // Load caller frame's scope chain into this callframe so that whatever we call can
418 // get to its global data.
419 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, regT2);
420 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT2);
421 emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain);
422
423 preserveReturnAddressAfterCall(regT3); // Callee preserved
424 emitPutToCallFrameHeader(regT3, RegisterFile::ReturnPC);
425
426 // Calling convention: f(r0 == regT4, r1 == regT5, ...);
427 // Host function signature: f(ExecState*);
428 move(callFrameRegister, regT4);
429
430 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT5);
431 move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
432 loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
433
434 // call the function
435 nativeCall = call();
436
437 restoreReturnAddressBeforeReturn(regT3);
438 #elif ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
439 #error "JIT_OPTIMIZE_NATIVE_CALL not yet supported on this platform."
440 #else
441 breakpoint();
442 #endif // CPU(X86)
443
444 // Check for an exception
445 Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&globalData->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
446
447 // Return.
448 ret();
449
450 // Handle an exception
451 sawException.link(this);
452
453 // Grab the return address.
454 preserveReturnAddressAfterCall(regT1);
455
456 move(TrustedImmPtr(&globalData->exceptionLocation), regT2);
457 storePtr(regT1, regT2);
458 poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
459
460 // Set the return address.
461 move(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1);
462 restoreReturnAddressBeforeReturn(regT1);
463
464 ret();
465
466 // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
467 LinkBuffer patchBuffer(this, executablePool, 0);
468
469 patchBuffer.link(nativeCall, FunctionPtr(func));
470 patchBuffer.finalizeCode();
471
472 return patchBuffer.trampolineAt(nativeCallThunk);
473 }
474
emit_op_mov(Instruction * currentInstruction)475 void JIT::emit_op_mov(Instruction* currentInstruction)
476 {
477 unsigned dst = currentInstruction[1].u.operand;
478 unsigned src = currentInstruction[2].u.operand;
479
480 if (m_codeBlock->isConstantRegisterIndex(src))
481 emitStore(dst, getConstantOperand(src));
482 else {
483 emitLoad(src, regT1, regT0);
484 emitStore(dst, regT1, regT0);
485 map(m_bytecodeOffset + OPCODE_LENGTH(op_mov), dst, regT1, regT0);
486 }
487 }
488
emit_op_end(Instruction * currentInstruction)489 void JIT::emit_op_end(Instruction* currentInstruction)
490 {
491 ASSERT(returnValueRegister != callFrameRegister);
492 emitLoad(currentInstruction[1].u.operand, regT1, regT0);
493 restoreReturnAddressBeforeReturn(Address(callFrameRegister, RegisterFile::ReturnPC * static_cast<int>(sizeof(Register))));
494 ret();
495 }
496
emit_op_jmp(Instruction * currentInstruction)497 void JIT::emit_op_jmp(Instruction* currentInstruction)
498 {
499 unsigned target = currentInstruction[1].u.operand;
500 addJump(jump(), target);
501 }
502
emit_op_loop_if_lesseq(Instruction * currentInstruction)503 void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction)
504 {
505 unsigned op1 = currentInstruction[1].u.operand;
506 unsigned op2 = currentInstruction[2].u.operand;
507 unsigned target = currentInstruction[3].u.operand;
508
509 emitTimeoutCheck();
510
511 if (isOperandConstantImmediateInt(op1)) {
512 emitLoad(op2, regT1, regT0);
513 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
514 addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op1).asInt32())), target);
515 return;
516 }
517
518 if (isOperandConstantImmediateInt(op2)) {
519 emitLoad(op1, regT1, regT0);
520 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
521 addJump(branch32(LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
522 return;
523 }
524
525 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
526 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
527 addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag)));
528 addJump(branch32(LessThanOrEqual, regT0, regT2), target);
529 }
530
emitSlow_op_loop_if_lesseq(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)531 void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
532 {
533 unsigned op1 = currentInstruction[1].u.operand;
534 unsigned op2 = currentInstruction[2].u.operand;
535 unsigned target = currentInstruction[3].u.operand;
536
537 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
538 linkSlowCase(iter); // int32 check
539 linkSlowCase(iter); // int32 check
540
541 JITStubCall stubCall(this, cti_op_loop_if_lesseq);
542 stubCall.addArgument(op1);
543 stubCall.addArgument(op2);
544 stubCall.call();
545 emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
546 }
547
emit_op_new_object(Instruction * currentInstruction)548 void JIT::emit_op_new_object(Instruction* currentInstruction)
549 {
550 JITStubCall(this, cti_op_new_object).call(currentInstruction[1].u.operand);
551 }
552
emit_op_check_has_instance(Instruction * currentInstruction)553 void JIT::emit_op_check_has_instance(Instruction* currentInstruction)
554 {
555 unsigned baseVal = currentInstruction[1].u.operand;
556
557 emitLoadPayload(baseVal, regT0);
558
559 // Check that baseVal is a cell.
560 emitJumpSlowCaseIfNotJSCell(baseVal);
561
562 // Check that baseVal 'ImplementsHasInstance'.
563 loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
564 addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsHasInstance)));
565 }
566
emit_op_instanceof(Instruction * currentInstruction)567 void JIT::emit_op_instanceof(Instruction* currentInstruction)
568 {
569 unsigned dst = currentInstruction[1].u.operand;
570 unsigned value = currentInstruction[2].u.operand;
571 unsigned baseVal = currentInstruction[3].u.operand;
572 unsigned proto = currentInstruction[4].u.operand;
573
574 // Load the operands into registers.
575 // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result.
576 emitLoadPayload(value, regT2);
577 emitLoadPayload(baseVal, regT0);
578 emitLoadPayload(proto, regT1);
579
580 // Check that proto are cells. baseVal must be a cell - this is checked by op_check_has_instance.
581 emitJumpSlowCaseIfNotJSCell(value);
582 emitJumpSlowCaseIfNotJSCell(proto);
583
584 // Check that prototype is an object
585 loadPtr(Address(regT1, JSCell::structureOffset()), regT3);
586 addSlowCase(branch8(NotEqual, Address(regT3, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)));
587
588 // Fixme: this check is only needed because the JSC API allows HasInstance to be overridden; we should deprecate this.
589 // Check that baseVal 'ImplementsDefaultHasInstance'.
590 loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
591 addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance)));
592
593 // Optimistically load the result true, and start looping.
594 // Initially, regT1 still contains proto and regT2 still contains value.
595 // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain.
596 move(TrustedImm32(1), regT0);
597 Label loop(this);
598
599 // Load the prototype of the cell in regT2. If this is equal to regT1 - WIN!
600 // Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again.
601 loadPtr(Address(regT2, JSCell::structureOffset()), regT2);
602 load32(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
603 Jump isInstance = branchPtr(Equal, regT2, regT1);
604 branchTest32(NonZero, regT2).linkTo(loop, this);
605
606 // We get here either by dropping out of the loop, or if value was not an Object. Result is false.
607 move(TrustedImm32(0), regT0);
608
609 // isInstance jumps right down to here, to skip setting the result to false (it has already set true).
610 isInstance.link(this);
611 emitStoreBool(dst, regT0);
612 }
613
emitSlow_op_check_has_instance(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)614 void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
615 {
616 unsigned baseVal = currentInstruction[1].u.operand;
617
618 linkSlowCaseIfNotJSCell(iter, baseVal);
619 linkSlowCase(iter);
620
621 JITStubCall stubCall(this, cti_op_check_has_instance);
622 stubCall.addArgument(baseVal);
623 stubCall.call();
624 }
625
emitSlow_op_instanceof(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)626 void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
627 {
628 unsigned dst = currentInstruction[1].u.operand;
629 unsigned value = currentInstruction[2].u.operand;
630 unsigned baseVal = currentInstruction[3].u.operand;
631 unsigned proto = currentInstruction[4].u.operand;
632
633 linkSlowCaseIfNotJSCell(iter, value);
634 linkSlowCaseIfNotJSCell(iter, proto);
635 linkSlowCase(iter);
636 linkSlowCase(iter);
637
638 JITStubCall stubCall(this, cti_op_instanceof);
639 stubCall.addArgument(value);
640 stubCall.addArgument(baseVal);
641 stubCall.addArgument(proto);
642 stubCall.call(dst);
643 }
644
emit_op_get_global_var(Instruction * currentInstruction)645 void JIT::emit_op_get_global_var(Instruction* currentInstruction)
646 {
647 int dst = currentInstruction[1].u.operand;
648 JSGlobalObject* globalObject = m_codeBlock->globalObject();
649 ASSERT(globalObject->isGlobalObject());
650 int index = currentInstruction[2].u.operand;
651
652 loadPtr(&globalObject->m_registers, regT2);
653
654 emitLoad(index, regT1, regT0, regT2);
655 emitStore(dst, regT1, regT0);
656 map(m_bytecodeOffset + OPCODE_LENGTH(op_get_global_var), dst, regT1, regT0);
657 }
658
emit_op_put_global_var(Instruction * currentInstruction)659 void JIT::emit_op_put_global_var(Instruction* currentInstruction)
660 {
661 JSGlobalObject* globalObject = m_codeBlock->globalObject();
662 ASSERT(globalObject->isGlobalObject());
663 int index = currentInstruction[1].u.operand;
664 int value = currentInstruction[2].u.operand;
665
666 emitLoad(value, regT1, regT0);
667
668 loadPtr(&globalObject->m_registers, regT2);
669 emitStore(index, regT1, regT0, regT2);
670 map(m_bytecodeOffset + OPCODE_LENGTH(op_put_global_var), value, regT1, regT0);
671 }
672
emit_op_get_scoped_var(Instruction * currentInstruction)673 void JIT::emit_op_get_scoped_var(Instruction* currentInstruction)
674 {
675 int dst = currentInstruction[1].u.operand;
676 int index = currentInstruction[2].u.operand;
677 int skip = currentInstruction[3].u.operand;
678
679 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2);
680 bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
681 ASSERT(skip || !checkTopLevel);
682 if (checkTopLevel && skip--) {
683 Jump activationNotCreated;
684 if (checkTopLevel)
685 activationNotCreated = branch32(Equal, tagFor(m_codeBlock->activationRegister()), TrustedImm32(JSValue::EmptyValueTag));
686 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2);
687 activationNotCreated.link(this);
688 }
689 while (skip--)
690 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2);
691
692 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2);
693 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, m_registers)), regT2);
694
695 emitLoad(index, regT1, regT0, regT2);
696 emitStore(dst, regT1, regT0);
697 map(m_bytecodeOffset + OPCODE_LENGTH(op_get_scoped_var), dst, regT1, regT0);
698 }
699
emit_op_put_scoped_var(Instruction * currentInstruction)700 void JIT::emit_op_put_scoped_var(Instruction* currentInstruction)
701 {
702 int index = currentInstruction[1].u.operand;
703 int skip = currentInstruction[2].u.operand;
704 int value = currentInstruction[3].u.operand;
705
706 emitLoad(value, regT1, regT0);
707
708 emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2);
709 bool checkTopLevel = m_codeBlock->codeType() == FunctionCode && m_codeBlock->needsFullScopeChain();
710 ASSERT(skip || !checkTopLevel);
711 if (checkTopLevel && skip--) {
712 Jump activationNotCreated;
713 if (checkTopLevel)
714 activationNotCreated = branch32(Equal, tagFor(m_codeBlock->activationRegister()), TrustedImm32(JSValue::EmptyValueTag));
715 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2);
716 activationNotCreated.link(this);
717 }
718 while (skip--)
719 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, next)), regT2);
720
721 loadPtr(Address(regT2, OBJECT_OFFSETOF(ScopeChainNode, object)), regT2);
722 loadPtr(Address(regT2, OBJECT_OFFSETOF(JSVariableObject, m_registers)), regT2);
723
724 emitStore(index, regT1, regT0, regT2);
725 map(m_bytecodeOffset + OPCODE_LENGTH(op_put_scoped_var), value, regT1, regT0);
726 }
727
emit_op_tear_off_activation(Instruction * currentInstruction)728 void JIT::emit_op_tear_off_activation(Instruction* currentInstruction)
729 {
730 unsigned activation = currentInstruction[1].u.operand;
731 unsigned arguments = currentInstruction[2].u.operand;
732 Jump activationCreated = branch32(NotEqual, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag));
733 Jump argumentsNotCreated = branch32(Equal, tagFor(arguments), TrustedImm32(JSValue::EmptyValueTag));
734 activationCreated.link(this);
735 JITStubCall stubCall(this, cti_op_tear_off_activation);
736 stubCall.addArgument(currentInstruction[1].u.operand);
737 stubCall.addArgument(unmodifiedArgumentsRegister(currentInstruction[2].u.operand));
738 stubCall.call();
739 argumentsNotCreated.link(this);
740 }
741
emit_op_tear_off_arguments(Instruction * currentInstruction)742 void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
743 {
744 int dst = currentInstruction[1].u.operand;
745
746 Jump argsNotCreated = branch32(Equal, tagFor(unmodifiedArgumentsRegister(dst)), TrustedImm32(JSValue::EmptyValueTag));
747 JITStubCall stubCall(this, cti_op_tear_off_arguments);
748 stubCall.addArgument(unmodifiedArgumentsRegister(dst));
749 stubCall.call();
750 argsNotCreated.link(this);
751 }
752
emit_op_new_array(Instruction * currentInstruction)753 void JIT::emit_op_new_array(Instruction* currentInstruction)
754 {
755 JITStubCall stubCall(this, cti_op_new_array);
756 stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
757 stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
758 stubCall.call(currentInstruction[1].u.operand);
759 }
760
emit_op_resolve(Instruction * currentInstruction)761 void JIT::emit_op_resolve(Instruction* currentInstruction)
762 {
763 JITStubCall stubCall(this, cti_op_resolve);
764 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
765 stubCall.call(currentInstruction[1].u.operand);
766 }
767
emit_op_to_primitive(Instruction * currentInstruction)768 void JIT::emit_op_to_primitive(Instruction* currentInstruction)
769 {
770 int dst = currentInstruction[1].u.operand;
771 int src = currentInstruction[2].u.operand;
772
773 emitLoad(src, regT1, regT0);
774
775 Jump isImm = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
776 addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr)));
777 isImm.link(this);
778
779 if (dst != src)
780 emitStore(dst, regT1, regT0);
781 map(m_bytecodeOffset + OPCODE_LENGTH(op_to_primitive), dst, regT1, regT0);
782 }
783
emitSlow_op_to_primitive(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)784 void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
785 {
786 int dst = currentInstruction[1].u.operand;
787
788 linkSlowCase(iter);
789
790 JITStubCall stubCall(this, cti_op_to_primitive);
791 stubCall.addArgument(regT1, regT0);
792 stubCall.call(dst);
793 }
794
emit_op_strcat(Instruction * currentInstruction)795 void JIT::emit_op_strcat(Instruction* currentInstruction)
796 {
797 JITStubCall stubCall(this, cti_op_strcat);
798 stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
799 stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
800 stubCall.call(currentInstruction[1].u.operand);
801 }
802
emit_op_resolve_base(Instruction * currentInstruction)803 void JIT::emit_op_resolve_base(Instruction* currentInstruction)
804 {
805 JITStubCall stubCall(this, currentInstruction[3].u.operand ? cti_op_resolve_base_strict_put : cti_op_resolve_base);
806 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
807 stubCall.call(currentInstruction[1].u.operand);
808 }
809
emit_op_ensure_property_exists(Instruction * currentInstruction)810 void JIT::emit_op_ensure_property_exists(Instruction* currentInstruction)
811 {
812 JITStubCall stubCall(this, cti_op_ensure_property_exists);
813 stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
814 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
815 stubCall.call(currentInstruction[1].u.operand);
816 }
817
emit_op_resolve_skip(Instruction * currentInstruction)818 void JIT::emit_op_resolve_skip(Instruction* currentInstruction)
819 {
820 JITStubCall stubCall(this, cti_op_resolve_skip);
821 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
822 stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
823 stubCall.call(currentInstruction[1].u.operand);
824 }
825
emit_op_resolve_global(Instruction * currentInstruction,bool dynamic)826 void JIT::emit_op_resolve_global(Instruction* currentInstruction, bool dynamic)
827 {
828 // FIXME: Optimize to use patching instead of so many memory accesses.
829
830 unsigned dst = currentInstruction[1].u.operand;
831 void* globalObject = m_codeBlock->globalObject();
832
833 unsigned currentIndex = m_globalResolveInfoIndex++;
834 void* structureAddress = &(m_codeBlock->globalResolveInfo(currentIndex).structure);
835 void* offsetAddr = &(m_codeBlock->globalResolveInfo(currentIndex).offset);
836
837 // Verify structure.
838 move(TrustedImmPtr(globalObject), regT0);
839 loadPtr(structureAddress, regT1);
840 addSlowCase(branchPtr(NotEqual, regT1, Address(regT0, JSCell::structureOffset())));
841
842 // Load property.
843 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSGlobalObject, m_propertyStorage)), regT2);
844 load32(offsetAddr, regT3);
845 load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0); // payload
846 load32(BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1); // tag
847 emitStore(dst, regT1, regT0);
848 map(m_bytecodeOffset + dynamic ? OPCODE_LENGTH(op_resolve_global_dynamic) : OPCODE_LENGTH(op_resolve_global), dst, regT1, regT0);
849 }
850
emitSlow_op_resolve_global(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)851 void JIT::emitSlow_op_resolve_global(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
852 {
853 unsigned dst = currentInstruction[1].u.operand;
854 Identifier* ident = &m_codeBlock->identifier(currentInstruction[2].u.operand);
855
856 unsigned currentIndex = m_globalResolveInfoIndex++;
857
858 linkSlowCase(iter);
859 JITStubCall stubCall(this, cti_op_resolve_global);
860 stubCall.addArgument(TrustedImmPtr(ident));
861 stubCall.addArgument(Imm32(currentIndex));
862 stubCall.call(dst);
863 }
864
emit_op_not(Instruction * currentInstruction)865 void JIT::emit_op_not(Instruction* currentInstruction)
866 {
867 unsigned dst = currentInstruction[1].u.operand;
868 unsigned src = currentInstruction[2].u.operand;
869
870 emitLoadTag(src, regT0);
871
872 emitLoad(src, regT1, regT0);
873 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::BooleanTag)));
874 xor32(TrustedImm32(1), regT0);
875
876 emitStoreBool(dst, regT0, (dst == src));
877 }
878
emitSlow_op_not(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)879 void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
880 {
881 unsigned dst = currentInstruction[1].u.operand;
882 unsigned src = currentInstruction[2].u.operand;
883
884 linkSlowCase(iter);
885
886 JITStubCall stubCall(this, cti_op_not);
887 stubCall.addArgument(src);
888 stubCall.call(dst);
889 }
890
emit_op_jfalse(Instruction * currentInstruction)891 void JIT::emit_op_jfalse(Instruction* currentInstruction)
892 {
893 unsigned cond = currentInstruction[1].u.operand;
894 unsigned target = currentInstruction[2].u.operand;
895
896 emitLoad(cond, regT1, regT0);
897
898 ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1));
899 addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag)));
900 addJump(branchTest32(Zero, regT0), target);
901 }
902
emitSlow_op_jfalse(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)903 void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
904 {
905 unsigned cond = currentInstruction[1].u.operand;
906 unsigned target = currentInstruction[2].u.operand;
907
908 linkSlowCase(iter);
909
910 if (supportsFloatingPoint()) {
911 // regT1 contains the tag from the hot path.
912 Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag));
913
914 emitLoadDouble(cond, fpRegT0);
915 emitJumpSlowToHot(branchDoubleZeroOrNaN(fpRegT0, fpRegT1), target);
916 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jfalse));
917
918 notNumber.link(this);
919 }
920
921 JITStubCall stubCall(this, cti_op_jtrue);
922 stubCall.addArgument(cond);
923 stubCall.call();
924 emitJumpSlowToHot(branchTest32(Zero, regT0), target); // Inverted.
925 }
926
emit_op_jtrue(Instruction * currentInstruction)927 void JIT::emit_op_jtrue(Instruction* currentInstruction)
928 {
929 unsigned cond = currentInstruction[1].u.operand;
930 unsigned target = currentInstruction[2].u.operand;
931
932 emitLoad(cond, regT1, regT0);
933
934 ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1));
935 addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag)));
936 addJump(branchTest32(NonZero, regT0), target);
937 }
938
emitSlow_op_jtrue(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)939 void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
940 {
941 unsigned cond = currentInstruction[1].u.operand;
942 unsigned target = currentInstruction[2].u.operand;
943
944 linkSlowCase(iter);
945
946 if (supportsFloatingPoint()) {
947 // regT1 contains the tag from the hot path.
948 Jump notNumber = branch32(Above, regT1, Imm32(JSValue::LowestTag));
949
950 emitLoadDouble(cond, fpRegT0);
951 emitJumpSlowToHot(branchDoubleNonZero(fpRegT0, fpRegT1), target);
952 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jtrue));
953
954 notNumber.link(this);
955 }
956
957 JITStubCall stubCall(this, cti_op_jtrue);
958 stubCall.addArgument(cond);
959 stubCall.call();
960 emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
961 }
962
emit_op_jeq_null(Instruction * currentInstruction)963 void JIT::emit_op_jeq_null(Instruction* currentInstruction)
964 {
965 unsigned src = currentInstruction[1].u.operand;
966 unsigned target = currentInstruction[2].u.operand;
967
968 emitLoad(src, regT1, regT0);
969
970 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
971
972 // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure.
973 loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
974 addJump(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target);
975
976 Jump wasNotImmediate = jump();
977
978 // Now handle the immediate cases - undefined & null
979 isImmediate.link(this);
980
981 ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1));
982 or32(TrustedImm32(1), regT1);
983 addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), target);
984
985 wasNotImmediate.link(this);
986 }
987
emit_op_jneq_null(Instruction * currentInstruction)988 void JIT::emit_op_jneq_null(Instruction* currentInstruction)
989 {
990 unsigned src = currentInstruction[1].u.operand;
991 unsigned target = currentInstruction[2].u.operand;
992
993 emitLoad(src, regT1, regT0);
994
995 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
996
997 // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure.
998 loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
999 addJump(branchTest8(Zero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target);
1000
1001 Jump wasNotImmediate = jump();
1002
1003 // Now handle the immediate cases - undefined & null
1004 isImmediate.link(this);
1005
1006 ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1));
1007 or32(TrustedImm32(1), regT1);
1008 addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::NullTag)), target);
1009
1010 wasNotImmediate.link(this);
1011 }
1012
emit_op_jneq_ptr(Instruction * currentInstruction)1013 void JIT::emit_op_jneq_ptr(Instruction* currentInstruction)
1014 {
1015 unsigned src = currentInstruction[1].u.operand;
1016 JSCell* ptr = currentInstruction[2].u.jsCell.get();
1017 unsigned target = currentInstruction[3].u.operand;
1018
1019 emitLoad(src, regT1, regT0);
1020 addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)), target);
1021 addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(ptr)), target);
1022 }
1023
emit_op_jsr(Instruction * currentInstruction)1024 void JIT::emit_op_jsr(Instruction* currentInstruction)
1025 {
1026 int retAddrDst = currentInstruction[1].u.operand;
1027 int target = currentInstruction[2].u.operand;
1028 DataLabelPtr storeLocation = storePtrWithPatch(TrustedImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst));
1029 addJump(jump(), target);
1030 m_jsrSites.append(JSRInfo(storeLocation, label()));
1031 }
1032
emit_op_sret(Instruction * currentInstruction)1033 void JIT::emit_op_sret(Instruction* currentInstruction)
1034 {
1035 jump(Address(callFrameRegister, sizeof(Register) * currentInstruction[1].u.operand));
1036 }
1037
emit_op_eq(Instruction * currentInstruction)1038 void JIT::emit_op_eq(Instruction* currentInstruction)
1039 {
1040 unsigned dst = currentInstruction[1].u.operand;
1041 unsigned src1 = currentInstruction[2].u.operand;
1042 unsigned src2 = currentInstruction[3].u.operand;
1043
1044 emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
1045 addSlowCase(branch32(NotEqual, regT1, regT3));
1046 addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
1047 addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
1048
1049 set32Compare32(Equal, regT0, regT2, regT0);
1050
1051 emitStoreBool(dst, regT0);
1052 }
1053
emitSlow_op_eq(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)1054 void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1055 {
1056 unsigned dst = currentInstruction[1].u.operand;
1057 unsigned op1 = currentInstruction[2].u.operand;
1058 unsigned op2 = currentInstruction[3].u.operand;
1059
1060 JumpList storeResult;
1061 JumpList genericCase;
1062
1063 genericCase.append(getSlowCase(iter)); // tags not equal
1064
1065 linkSlowCase(iter); // tags equal and JSCell
1066 genericCase.append(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr)));
1067 genericCase.append(branchPtr(NotEqual, Address(regT2), TrustedImmPtr(m_globalData->jsStringVPtr)));
1068
1069 // String case.
1070 JITStubCall stubCallEqStrings(this, cti_op_eq_strings);
1071 stubCallEqStrings.addArgument(regT0);
1072 stubCallEqStrings.addArgument(regT2);
1073 stubCallEqStrings.call();
1074 storeResult.append(jump());
1075
1076 // Generic case.
1077 genericCase.append(getSlowCase(iter)); // doubles
1078 genericCase.link(this);
1079 JITStubCall stubCallEq(this, cti_op_eq);
1080 stubCallEq.addArgument(op1);
1081 stubCallEq.addArgument(op2);
1082 stubCallEq.call(regT0);
1083
1084 storeResult.link(this);
1085 emitStoreBool(dst, regT0);
1086 }
1087
emit_op_neq(Instruction * currentInstruction)1088 void JIT::emit_op_neq(Instruction* currentInstruction)
1089 {
1090 unsigned dst = currentInstruction[1].u.operand;
1091 unsigned src1 = currentInstruction[2].u.operand;
1092 unsigned src2 = currentInstruction[3].u.operand;
1093
1094 emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
1095 addSlowCase(branch32(NotEqual, regT1, regT3));
1096 addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
1097 addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
1098
1099 set32Compare32(NotEqual, regT0, regT2, regT0);
1100
1101 emitStoreBool(dst, regT0);
1102 }
1103
emitSlow_op_neq(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)1104 void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1105 {
1106 unsigned dst = currentInstruction[1].u.operand;
1107
1108 JumpList storeResult;
1109 JumpList genericCase;
1110
1111 genericCase.append(getSlowCase(iter)); // tags not equal
1112
1113 linkSlowCase(iter); // tags equal and JSCell
1114 genericCase.append(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsStringVPtr)));
1115 genericCase.append(branchPtr(NotEqual, Address(regT2), TrustedImmPtr(m_globalData->jsStringVPtr)));
1116
1117 // String case.
1118 JITStubCall stubCallEqStrings(this, cti_op_eq_strings);
1119 stubCallEqStrings.addArgument(regT0);
1120 stubCallEqStrings.addArgument(regT2);
1121 stubCallEqStrings.call(regT0);
1122 storeResult.append(jump());
1123
1124 // Generic case.
1125 genericCase.append(getSlowCase(iter)); // doubles
1126 genericCase.link(this);
1127 JITStubCall stubCallEq(this, cti_op_eq);
1128 stubCallEq.addArgument(regT1, regT0);
1129 stubCallEq.addArgument(regT3, regT2);
1130 stubCallEq.call(regT0);
1131
1132 storeResult.link(this);
1133 xor32(TrustedImm32(0x1), regT0);
1134 emitStoreBool(dst, regT0);
1135 }
1136
compileOpStrictEq(Instruction * currentInstruction,CompileOpStrictEqType type)1137 void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqType type)
1138 {
1139 unsigned dst = currentInstruction[1].u.operand;
1140 unsigned src1 = currentInstruction[2].u.operand;
1141 unsigned src2 = currentInstruction[3].u.operand;
1142
1143 emitLoadTag(src1, regT0);
1144 emitLoadTag(src2, regT1);
1145
1146 // Jump to a slow case if either operand is double, or if both operands are
1147 // cells and/or Int32s.
1148 move(regT0, regT2);
1149 and32(regT1, regT2);
1150 addSlowCase(branch32(Below, regT2, TrustedImm32(JSValue::LowestTag)));
1151 addSlowCase(branch32(AboveOrEqual, regT2, TrustedImm32(JSValue::CellTag)));
1152
1153 if (type == OpStrictEq)
1154 set32Compare32(Equal, regT0, regT1, regT0);
1155 else
1156 set32Compare32(NotEqual, regT0, regT1, regT0);
1157
1158 emitStoreBool(dst, regT0);
1159 }
1160
emit_op_stricteq(Instruction * currentInstruction)1161 void JIT::emit_op_stricteq(Instruction* currentInstruction)
1162 {
1163 compileOpStrictEq(currentInstruction, OpStrictEq);
1164 }
1165
emitSlow_op_stricteq(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)1166 void JIT::emitSlow_op_stricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1167 {
1168 unsigned dst = currentInstruction[1].u.operand;
1169 unsigned src1 = currentInstruction[2].u.operand;
1170 unsigned src2 = currentInstruction[3].u.operand;
1171
1172 linkSlowCase(iter);
1173 linkSlowCase(iter);
1174
1175 JITStubCall stubCall(this, cti_op_stricteq);
1176 stubCall.addArgument(src1);
1177 stubCall.addArgument(src2);
1178 stubCall.call(dst);
1179 }
1180
emit_op_nstricteq(Instruction * currentInstruction)1181 void JIT::emit_op_nstricteq(Instruction* currentInstruction)
1182 {
1183 compileOpStrictEq(currentInstruction, OpNStrictEq);
1184 }
1185
emitSlow_op_nstricteq(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)1186 void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1187 {
1188 unsigned dst = currentInstruction[1].u.operand;
1189 unsigned src1 = currentInstruction[2].u.operand;
1190 unsigned src2 = currentInstruction[3].u.operand;
1191
1192 linkSlowCase(iter);
1193 linkSlowCase(iter);
1194
1195 JITStubCall stubCall(this, cti_op_nstricteq);
1196 stubCall.addArgument(src1);
1197 stubCall.addArgument(src2);
1198 stubCall.call(dst);
1199 }
1200
emit_op_eq_null(Instruction * currentInstruction)1201 void JIT::emit_op_eq_null(Instruction* currentInstruction)
1202 {
1203 unsigned dst = currentInstruction[1].u.operand;
1204 unsigned src = currentInstruction[2].u.operand;
1205
1206 emitLoad(src, regT1, regT0);
1207 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
1208
1209 loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
1210 set32Test8(NonZero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), regT1);
1211
1212 Jump wasNotImmediate = jump();
1213
1214 isImmediate.link(this);
1215
1216 set32Compare32(Equal, regT1, TrustedImm32(JSValue::NullTag), regT2);
1217 set32Compare32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
1218 or32(regT2, regT1);
1219
1220 wasNotImmediate.link(this);
1221
1222 emitStoreBool(dst, regT1);
1223 }
1224
emit_op_neq_null(Instruction * currentInstruction)1225 void JIT::emit_op_neq_null(Instruction* currentInstruction)
1226 {
1227 unsigned dst = currentInstruction[1].u.operand;
1228 unsigned src = currentInstruction[2].u.operand;
1229
1230 emitLoad(src, regT1, regT0);
1231 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
1232
1233 loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
1234 set32Test8(Zero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined), regT1);
1235
1236 Jump wasNotImmediate = jump();
1237
1238 isImmediate.link(this);
1239
1240 set32Compare32(NotEqual, regT1, TrustedImm32(JSValue::NullTag), regT2);
1241 set32Compare32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
1242 and32(regT2, regT1);
1243
1244 wasNotImmediate.link(this);
1245
1246 emitStoreBool(dst, regT1);
1247 }
1248
emit_op_resolve_with_base(Instruction * currentInstruction)1249 void JIT::emit_op_resolve_with_base(Instruction* currentInstruction)
1250 {
1251 JITStubCall stubCall(this, cti_op_resolve_with_base);
1252 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
1253 stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
1254 stubCall.call(currentInstruction[2].u.operand);
1255 }
1256
emit_op_new_func_exp(Instruction * currentInstruction)1257 void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
1258 {
1259 JITStubCall stubCall(this, cti_op_new_func_exp);
1260 stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand)));
1261 stubCall.call(currentInstruction[1].u.operand);
1262 }
1263
emit_op_throw(Instruction * currentInstruction)1264 void JIT::emit_op_throw(Instruction* currentInstruction)
1265 {
1266 unsigned exception = currentInstruction[1].u.operand;
1267 JITStubCall stubCall(this, cti_op_throw);
1268 stubCall.addArgument(exception);
1269 stubCall.call();
1270
1271 #ifndef NDEBUG
1272 // cti_op_throw always changes it's return address,
1273 // this point in the code should never be reached.
1274 breakpoint();
1275 #endif
1276 }
1277
emit_op_get_pnames(Instruction * currentInstruction)1278 void JIT::emit_op_get_pnames(Instruction* currentInstruction)
1279 {
1280 int dst = currentInstruction[1].u.operand;
1281 int base = currentInstruction[2].u.operand;
1282 int i = currentInstruction[3].u.operand;
1283 int size = currentInstruction[4].u.operand;
1284 int breakTarget = currentInstruction[5].u.operand;
1285
1286 JumpList isNotObject;
1287
1288 emitLoad(base, regT1, regT0);
1289 if (!m_codeBlock->isKnownNotImmediate(base))
1290 isNotObject.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
1291 if (base != m_codeBlock->thisRegister() || m_codeBlock->isStrictMode()) {
1292 loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
1293 isNotObject.append(branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType)));
1294 }
1295
1296 // We could inline the case where you have a valid cache, but
1297 // this call doesn't seem to be hot.
1298 Label isObject(this);
1299 JITStubCall getPnamesStubCall(this, cti_op_get_pnames);
1300 getPnamesStubCall.addArgument(regT0);
1301 getPnamesStubCall.call(dst);
1302 load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
1303 store32(TrustedImm32(Int32Tag), intTagFor(i));
1304 store32(TrustedImm32(0), intPayloadFor(i));
1305 store32(TrustedImm32(Int32Tag), intTagFor(size));
1306 store32(regT3, payloadFor(size));
1307 Jump end = jump();
1308
1309 isNotObject.link(this);
1310 addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), breakTarget);
1311 addJump(branch32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag)), breakTarget);
1312 JITStubCall toObjectStubCall(this, cti_to_object);
1313 toObjectStubCall.addArgument(regT1, regT0);
1314 toObjectStubCall.call(base);
1315 jump().linkTo(isObject, this);
1316
1317 end.link(this);
1318 }
1319
emit_op_next_pname(Instruction * currentInstruction)1320 void JIT::emit_op_next_pname(Instruction* currentInstruction)
1321 {
1322 int dst = currentInstruction[1].u.operand;
1323 int base = currentInstruction[2].u.operand;
1324 int i = currentInstruction[3].u.operand;
1325 int size = currentInstruction[4].u.operand;
1326 int it = currentInstruction[5].u.operand;
1327 int target = currentInstruction[6].u.operand;
1328
1329 JumpList callHasProperty;
1330
1331 Label begin(this);
1332 load32(intPayloadFor(i), regT0);
1333 Jump end = branch32(Equal, regT0, intPayloadFor(size));
1334
1335 // Grab key @ i
1336 loadPtr(payloadFor(it), regT1);
1337 loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
1338 load32(BaseIndex(regT2, regT0, TimesEight), regT2);
1339 store32(TrustedImm32(JSValue::CellTag), tagFor(dst));
1340 store32(regT2, payloadFor(dst));
1341
1342 // Increment i
1343 add32(TrustedImm32(1), regT0);
1344 store32(regT0, intPayloadFor(i));
1345
1346 // Verify that i is valid:
1347 loadPtr(payloadFor(base), regT0);
1348
1349 // Test base's structure
1350 loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
1351 callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
1352
1353 // Test base's prototype chain
1354 loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3);
1355 loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3);
1356 addJump(branchTestPtr(Zero, Address(regT3)), target);
1357
1358 Label checkPrototype(this);
1359 callHasProperty.append(branch32(Equal, Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::NullTag)));
1360 loadPtr(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
1361 loadPtr(Address(regT2, JSCell::structureOffset()), regT2);
1362 callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
1363 addPtr(TrustedImm32(sizeof(Structure*)), regT3);
1364 branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
1365
1366 // Continue loop.
1367 addJump(jump(), target);
1368
1369 // Slow case: Ask the object if i is valid.
1370 callHasProperty.link(this);
1371 loadPtr(addressFor(dst), regT1);
1372 JITStubCall stubCall(this, cti_has_property);
1373 stubCall.addArgument(regT0);
1374 stubCall.addArgument(regT1);
1375 stubCall.call();
1376
1377 // Test for valid key.
1378 addJump(branchTest32(NonZero, regT0), target);
1379 jump().linkTo(begin, this);
1380
1381 // End of loop.
1382 end.link(this);
1383 }
1384
emit_op_push_scope(Instruction * currentInstruction)1385 void JIT::emit_op_push_scope(Instruction* currentInstruction)
1386 {
1387 JITStubCall stubCall(this, cti_op_push_scope);
1388 stubCall.addArgument(currentInstruction[1].u.operand);
1389 stubCall.call(currentInstruction[1].u.operand);
1390 }
1391
emit_op_pop_scope(Instruction *)1392 void JIT::emit_op_pop_scope(Instruction*)
1393 {
1394 JITStubCall(this, cti_op_pop_scope).call();
1395 }
1396
emit_op_to_jsnumber(Instruction * currentInstruction)1397 void JIT::emit_op_to_jsnumber(Instruction* currentInstruction)
1398 {
1399 int dst = currentInstruction[1].u.operand;
1400 int src = currentInstruction[2].u.operand;
1401
1402 emitLoad(src, regT1, regT0);
1403
1404 Jump isInt32 = branch32(Equal, regT1, TrustedImm32(JSValue::Int32Tag));
1405 addSlowCase(branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::EmptyValueTag)));
1406 isInt32.link(this);
1407
1408 if (src != dst)
1409 emitStore(dst, regT1, regT0);
1410 map(m_bytecodeOffset + OPCODE_LENGTH(op_to_jsnumber), dst, regT1, regT0);
1411 }
1412
emitSlow_op_to_jsnumber(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)1413 void JIT::emitSlow_op_to_jsnumber(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1414 {
1415 int dst = currentInstruction[1].u.operand;
1416
1417 linkSlowCase(iter);
1418
1419 JITStubCall stubCall(this, cti_op_to_jsnumber);
1420 stubCall.addArgument(regT1, regT0);
1421 stubCall.call(dst);
1422 }
1423
emit_op_push_new_scope(Instruction * currentInstruction)1424 void JIT::emit_op_push_new_scope(Instruction* currentInstruction)
1425 {
1426 JITStubCall stubCall(this, cti_op_push_new_scope);
1427 stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
1428 stubCall.addArgument(currentInstruction[3].u.operand);
1429 stubCall.call(currentInstruction[1].u.operand);
1430 }
1431
emit_op_catch(Instruction * currentInstruction)1432 void JIT::emit_op_catch(Instruction* currentInstruction)
1433 {
1434 // cti_op_throw returns the callFrame for the handler.
1435 move(regT0, callFrameRegister);
1436
1437 // Now store the exception returned by cti_op_throw.
1438 loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(struct JITStackFrame, globalData)), regT3);
1439 load32(Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
1440 load32(Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
1441 store32(TrustedImm32(JSValue().payload()), Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1442 store32(TrustedImm32(JSValue().tag()), Address(regT3, OBJECT_OFFSETOF(JSGlobalData, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1443
1444 unsigned exception = currentInstruction[1].u.operand;
1445 emitStore(exception, regT1, regT0);
1446 map(m_bytecodeOffset + OPCODE_LENGTH(op_catch), exception, regT1, regT0);
1447 }
1448
emit_op_jmp_scopes(Instruction * currentInstruction)1449 void JIT::emit_op_jmp_scopes(Instruction* currentInstruction)
1450 {
1451 JITStubCall stubCall(this, cti_op_jmp_scopes);
1452 stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
1453 stubCall.call();
1454 addJump(jump(), currentInstruction[2].u.operand);
1455 }
1456
emit_op_switch_imm(Instruction * currentInstruction)1457 void JIT::emit_op_switch_imm(Instruction* currentInstruction)
1458 {
1459 unsigned tableIndex = currentInstruction[1].u.operand;
1460 unsigned defaultOffset = currentInstruction[2].u.operand;
1461 unsigned scrutinee = currentInstruction[3].u.operand;
1462
1463 // create jump table for switch destinations, track this switch statement.
1464 SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTable(tableIndex);
1465 m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Immediate));
1466 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
1467
1468 JITStubCall stubCall(this, cti_op_switch_imm);
1469 stubCall.addArgument(scrutinee);
1470 stubCall.addArgument(Imm32(tableIndex));
1471 stubCall.call();
1472 jump(regT0);
1473 }
1474
emit_op_switch_char(Instruction * currentInstruction)1475 void JIT::emit_op_switch_char(Instruction* currentInstruction)
1476 {
1477 unsigned tableIndex = currentInstruction[1].u.operand;
1478 unsigned defaultOffset = currentInstruction[2].u.operand;
1479 unsigned scrutinee = currentInstruction[3].u.operand;
1480
1481 // create jump table for switch destinations, track this switch statement.
1482 SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTable(tableIndex);
1483 m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Character));
1484 jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
1485
1486 JITStubCall stubCall(this, cti_op_switch_char);
1487 stubCall.addArgument(scrutinee);
1488 stubCall.addArgument(Imm32(tableIndex));
1489 stubCall.call();
1490 jump(regT0);
1491 }
1492
emit_op_switch_string(Instruction * currentInstruction)1493 void JIT::emit_op_switch_string(Instruction* currentInstruction)
1494 {
1495 unsigned tableIndex = currentInstruction[1].u.operand;
1496 unsigned defaultOffset = currentInstruction[2].u.operand;
1497 unsigned scrutinee = currentInstruction[3].u.operand;
1498
1499 // create jump table for switch destinations, track this switch statement.
1500 StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex);
1501 m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset));
1502
1503 JITStubCall stubCall(this, cti_op_switch_string);
1504 stubCall.addArgument(scrutinee);
1505 stubCall.addArgument(Imm32(tableIndex));
1506 stubCall.call();
1507 jump(regT0);
1508 }
1509
emit_op_throw_reference_error(Instruction * currentInstruction)1510 void JIT::emit_op_throw_reference_error(Instruction* currentInstruction)
1511 {
1512 unsigned message = currentInstruction[1].u.operand;
1513
1514 JITStubCall stubCall(this, cti_op_throw_reference_error);
1515 stubCall.addArgument(m_codeBlock->getConstant(message));
1516 stubCall.call();
1517 }
1518
emit_op_debug(Instruction * currentInstruction)1519 void JIT::emit_op_debug(Instruction* currentInstruction)
1520 {
1521 #if ENABLE(DEBUG_WITH_BREAKPOINT)
1522 UNUSED_PARAM(currentInstruction);
1523 breakpoint();
1524 #else
1525 JITStubCall stubCall(this, cti_op_debug);
1526 stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
1527 stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
1528 stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
1529 stubCall.call();
1530 #endif
1531 }
1532
1533
emit_op_enter(Instruction *)1534 void JIT::emit_op_enter(Instruction*)
1535 {
1536 // Even though JIT code doesn't use them, we initialize our constant
1537 // registers to zap stale pointers, to avoid unnecessarily prolonging
1538 // object lifetime and increasing GC pressure.
1539 for (int i = 0; i < m_codeBlock->m_numVars; ++i)
1540 emitStore(i, jsUndefined());
1541 }
1542
emit_op_create_activation(Instruction * currentInstruction)1543 void JIT::emit_op_create_activation(Instruction* currentInstruction)
1544 {
1545 unsigned activation = currentInstruction[1].u.operand;
1546
1547 Jump activationCreated = branch32(NotEqual, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag));
1548 JITStubCall(this, cti_op_push_activation).call(activation);
1549 activationCreated.link(this);
1550 }
1551
emit_op_create_arguments(Instruction * currentInstruction)1552 void JIT::emit_op_create_arguments(Instruction* currentInstruction)
1553 {
1554 unsigned dst = currentInstruction[1].u.operand;
1555
1556 Jump argsCreated = branch32(NotEqual, tagFor(dst), TrustedImm32(JSValue::EmptyValueTag));
1557
1558 if (m_codeBlock->m_numParameters == 1)
1559 JITStubCall(this, cti_op_create_arguments_no_params).call();
1560 else
1561 JITStubCall(this, cti_op_create_arguments).call();
1562
1563 emitStore(dst, regT1, regT0);
1564 emitStore(unmodifiedArgumentsRegister(dst), regT1, regT0);
1565
1566 argsCreated.link(this);
1567 }
1568
emit_op_init_lazy_reg(Instruction * currentInstruction)1569 void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction)
1570 {
1571 unsigned dst = currentInstruction[1].u.operand;
1572
1573 emitStore(dst, JSValue());
1574 }
1575
emit_op_get_callee(Instruction * currentInstruction)1576 void JIT::emit_op_get_callee(Instruction* currentInstruction)
1577 {
1578 int dst = currentInstruction[1].u.operand;
1579 emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
1580 emitStoreCell(dst, regT0);
1581 }
1582
emit_op_create_this(Instruction * currentInstruction)1583 void JIT::emit_op_create_this(Instruction* currentInstruction)
1584 {
1585 unsigned protoRegister = currentInstruction[2].u.operand;
1586 emitLoad(protoRegister, regT1, regT0);
1587 JITStubCall stubCall(this, cti_op_create_this);
1588 stubCall.addArgument(regT1, regT0);
1589 stubCall.call(currentInstruction[1].u.operand);
1590 }
1591
emit_op_convert_this(Instruction * currentInstruction)1592 void JIT::emit_op_convert_this(Instruction* currentInstruction)
1593 {
1594 unsigned thisRegister = currentInstruction[1].u.operand;
1595
1596 emitLoad(thisRegister, regT1, regT0);
1597
1598 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
1599
1600 loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
1601 addSlowCase(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(NeedsThisConversion)));
1602
1603 map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0);
1604 }
1605
emit_op_convert_this_strict(Instruction * currentInstruction)1606 void JIT::emit_op_convert_this_strict(Instruction* currentInstruction)
1607 {
1608 unsigned thisRegister = currentInstruction[1].u.operand;
1609
1610 emitLoad(thisRegister, regT1, regT0);
1611
1612 Jump notNull = branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag));
1613 emitStore(thisRegister, jsNull());
1614 Jump setThis = jump();
1615 notNull.link(this);
1616 Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
1617 loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
1618 Jump notAnObject = branch8(NotEqual, Address(regT2, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
1619 addSlowCase(branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(NeedsThisConversion)));
1620 isImmediate.link(this);
1621 notAnObject.link(this);
1622 setThis.link(this);
1623 map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this_strict), thisRegister, regT1, regT0);
1624 }
1625
emitSlow_op_convert_this(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)1626 void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1627 {
1628 unsigned thisRegister = currentInstruction[1].u.operand;
1629
1630 linkSlowCase(iter);
1631 linkSlowCase(iter);
1632
1633 JITStubCall stubCall(this, cti_op_convert_this);
1634 stubCall.addArgument(regT1, regT0);
1635 stubCall.call(thisRegister);
1636 }
1637
emitSlow_op_convert_this_strict(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)1638 void JIT::emitSlow_op_convert_this_strict(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1639 {
1640 unsigned thisRegister = currentInstruction[1].u.operand;
1641
1642 linkSlowCase(iter);
1643
1644 JITStubCall stubCall(this, cti_op_convert_this_strict);
1645 stubCall.addArgument(regT1, regT0);
1646 stubCall.call(thisRegister);
1647 }
1648
emit_op_profile_will_call(Instruction * currentInstruction)1649 void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
1650 {
1651 peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*));
1652 Jump noProfiler = branchTestPtr(Zero, Address(regT2));
1653
1654 JITStubCall stubCall(this, cti_op_profile_will_call);
1655 stubCall.addArgument(currentInstruction[1].u.operand);
1656 stubCall.call();
1657 noProfiler.link(this);
1658 }
1659
emit_op_profile_did_call(Instruction * currentInstruction)1660 void JIT::emit_op_profile_did_call(Instruction* currentInstruction)
1661 {
1662 peek(regT2, OBJECT_OFFSETOF(JITStackFrame, enabledProfilerReference) / sizeof(void*));
1663 Jump noProfiler = branchTestPtr(Zero, Address(regT2));
1664
1665 JITStubCall stubCall(this, cti_op_profile_did_call);
1666 stubCall.addArgument(currentInstruction[1].u.operand);
1667 stubCall.call();
1668 noProfiler.link(this);
1669 }
1670
emit_op_get_arguments_length(Instruction * currentInstruction)1671 void JIT::emit_op_get_arguments_length(Instruction* currentInstruction)
1672 {
1673 int dst = currentInstruction[1].u.operand;
1674 int argumentsRegister = currentInstruction[2].u.operand;
1675 addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag)));
1676 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0);
1677 sub32(TrustedImm32(1), regT0);
1678 emitStoreInt32(dst, regT0);
1679 }
1680
emitSlow_op_get_arguments_length(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)1681 void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1682 {
1683 linkSlowCase(iter);
1684 int dst = currentInstruction[1].u.operand;
1685 int base = currentInstruction[2].u.operand;
1686 int ident = currentInstruction[3].u.operand;
1687
1688 JITStubCall stubCall(this, cti_op_get_by_id_generic);
1689 stubCall.addArgument(base);
1690 stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident))));
1691 stubCall.call(dst);
1692 }
1693
emit_op_get_argument_by_val(Instruction * currentInstruction)1694 void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction)
1695 {
1696 int dst = currentInstruction[1].u.operand;
1697 int argumentsRegister = currentInstruction[2].u.operand;
1698 int property = currentInstruction[3].u.operand;
1699 addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag)));
1700 emitLoad(property, regT1, regT2);
1701 addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
1702 add32(TrustedImm32(1), regT2);
1703 // regT2 now contains the integer index of the argument we want, including this
1704 emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT3);
1705 addSlowCase(branch32(AboveOrEqual, regT2, regT3));
1706
1707 Jump skipOutofLineParams;
1708 int numArgs = m_codeBlock->m_numParameters;
1709 if (numArgs) {
1710 Jump notInInPlaceArgs = branch32(AboveOrEqual, regT2, Imm32(numArgs));
1711 addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1);
1712 loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
1713 loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
1714 skipOutofLineParams = jump();
1715 notInInPlaceArgs.link(this);
1716 }
1717
1718 addPtr(Imm32(static_cast<unsigned>(-(RegisterFile::CallFrameHeaderSize + numArgs) * sizeof(Register))), callFrameRegister, regT1);
1719 mul32(TrustedImm32(sizeof(Register)), regT3, regT3);
1720 subPtr(regT3, regT1);
1721 loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
1722 loadPtr(BaseIndex(regT1, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
1723 if (numArgs)
1724 skipOutofLineParams.link(this);
1725 emitStore(dst, regT1, regT0);
1726 }
1727
emitSlow_op_get_argument_by_val(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)1728 void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1729 {
1730 unsigned dst = currentInstruction[1].u.operand;
1731 unsigned arguments = currentInstruction[2].u.operand;
1732 unsigned property = currentInstruction[3].u.operand;
1733
1734 linkSlowCase(iter);
1735 Jump skipArgumentsCreation = jump();
1736
1737 linkSlowCase(iter);
1738 linkSlowCase(iter);
1739 if (m_codeBlock->m_numParameters == 1)
1740 JITStubCall(this, cti_op_create_arguments_no_params).call();
1741 else
1742 JITStubCall(this, cti_op_create_arguments).call();
1743
1744 emitStore(arguments, regT1, regT0);
1745 emitStore(unmodifiedArgumentsRegister(arguments), regT1, regT0);
1746
1747 skipArgumentsCreation.link(this);
1748 JITStubCall stubCall(this, cti_op_get_by_val);
1749 stubCall.addArgument(arguments);
1750 stubCall.addArgument(property);
1751 stubCall.call(dst);
1752 }
1753
1754 #if ENABLE(JIT_USE_SOFT_MODULO)
softModulo()1755 void JIT::softModulo()
1756 {
1757 push(regT1);
1758 push(regT3);
1759 move(regT2, regT3);
1760 move(regT0, regT2);
1761 move(TrustedImm32(0), regT1);
1762
1763 // Check for negative result reminder
1764 Jump positiveRegT3 = branch32(GreaterThanOrEqual, regT3, TrustedImm32(0));
1765 neg32(regT3);
1766 xor32(TrustedImm32(1), regT1);
1767 positiveRegT3.link(this);
1768
1769 Jump positiveRegT2 = branch32(GreaterThanOrEqual, regT2, TrustedImm32(0));
1770 neg32(regT2);
1771 xor32(TrustedImm32(2), regT1);
1772 positiveRegT2.link(this);
1773
1774 // Save the condition for negative reminder
1775 push(regT1);
1776
1777 Jump exitBranch = branch32(LessThan, regT2, regT3);
1778
1779 // Power of two fast case
1780 move(regT3, regT0);
1781 sub32(TrustedImm32(1), regT0);
1782 Jump powerOfTwo = branchTest32(NotEqual, regT0, regT3);
1783 and32(regT0, regT2);
1784 powerOfTwo.link(this);
1785
1786 and32(regT3, regT0);
1787
1788 Jump exitBranch2 = branchTest32(Zero, regT0);
1789
1790 countLeadingZeros32(regT2, regT0);
1791 countLeadingZeros32(regT3, regT1);
1792 sub32(regT0, regT1);
1793
1794 Jump useFullTable = branch32(Equal, regT1, TrustedImm32(31));
1795
1796 neg32(regT1);
1797 add32(TrustedImm32(31), regT1);
1798
1799 int elementSizeByShift = -1;
1800 #if CPU(ARM)
1801 elementSizeByShift = 3;
1802 #else
1803 #error "JIT_OPTIMIZE_MOD not yet supported on this platform."
1804 #endif
1805 relativeTableJump(regT1, elementSizeByShift);
1806
1807 useFullTable.link(this);
1808 // Modulo table
1809 for (int i = 31; i > 0; --i) {
1810 #if CPU(ARM_TRADITIONAL)
1811 m_assembler.cmp_r(regT2, m_assembler.lsl(regT3, i));
1812 m_assembler.sub_r(regT2, regT2, m_assembler.lsl(regT3, i), ARMAssembler::CS);
1813 #elif CPU(ARM_THUMB2)
1814 ShiftTypeAndAmount shift(SRType_LSL, i);
1815 m_assembler.sub_S(regT1, regT2, regT3, shift);
1816 m_assembler.it(ARMv7Assembler::ConditionCS);
1817 m_assembler.mov(regT2, regT1);
1818 #else
1819 #error "JIT_OPTIMIZE_MOD not yet supported on this platform."
1820 #endif
1821 }
1822
1823 Jump lower = branch32(Below, regT2, regT3);
1824 sub32(regT3, regT2);
1825 lower.link(this);
1826
1827 exitBranch.link(this);
1828 exitBranch2.link(this);
1829
1830 // Check for negative reminder
1831 pop(regT1);
1832 Jump positiveResult = branch32(Equal, regT1, TrustedImm32(0));
1833 neg32(regT2);
1834 positiveResult.link(this);
1835
1836 move(regT2, regT0);
1837
1838 pop(regT3);
1839 pop(regT1);
1840 ret();
1841 }
1842 #endif // ENABLE(JIT_USE_SOFT_MODULO)
1843
1844 } // namespace JSC
1845
1846 #endif // USE(JSVALUE32_64)
1847 #endif // ENABLE(JIT)
1848