1/*
2 * Copyright (C) 2009, 2012 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 "JITInlines.h"
34#include "JITStubCall.h"
35#include "JSArray.h"
36#include "JSCell.h"
37#include "JSFunction.h"
38#include "JSPropertyNameIterator.h"
39#include "JSVariableObject.h"
40#include "LinkBuffer.h"
41
42namespace JSC {
43
44JIT::CodeRef JIT::privateCompileCTINativeCall(VM* vm, NativeFunction func)
45{
46    Call nativeCall;
47
48    emitPutImmediateToCallFrameHeader(0, JSStack::CodeBlock);
49    storePtr(callFrameRegister, &m_vm->topCallFrame);
50
51#if CPU(X86)
52    // Load caller frame's scope chain into this callframe so that whatever we call can
53    // get to its global data.
54    emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, regT0);
55    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT1, regT0);
56    emitPutCellToCallFrameHeader(regT1, JSStack::ScopeChain);
57
58    peek(regT1);
59    emitPutToCallFrameHeader(regT1, JSStack::ReturnPC);
60
61    // Calling convention:      f(ecx, edx, ...);
62    // Host function signature: f(ExecState*);
63    move(callFrameRegister, X86Registers::ecx);
64
65    subPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister); // Align stack after call.
66
67    move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
68
69    // call the function
70    nativeCall = call();
71
72    addPtr(TrustedImm32(16 - sizeof(void*)), stackPointerRegister);
73
74#elif CPU(ARM)
75    // Load caller frame's scope chain into this callframe so that whatever we call can
76    // get to its global data.
77    emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, regT2);
78    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT1, regT2);
79    emitPutCellToCallFrameHeader(regT1, JSStack::ScopeChain);
80
81    preserveReturnAddressAfterCall(regT3); // Callee preserved
82    emitPutToCallFrameHeader(regT3, JSStack::ReturnPC);
83
84    // Calling convention:      f(r0 == regT0, r1 == regT1, ...);
85    // Host function signature: f(ExecState*);
86    move(callFrameRegister, ARMRegisters::r0);
87
88    emitGetFromCallFrameHeaderPtr(JSStack::Callee, ARMRegisters::r1);
89    move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
90    loadPtr(Address(ARMRegisters::r1, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
91
92    // call the function
93    nativeCall = call();
94
95    restoreReturnAddressBeforeReturn(regT3);
96
97#elif CPU(MIPS)
98    // Load caller frame's scope chain into this callframe so that whatever we call can
99    // get to its global data.
100    emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, regT0);
101    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT1, regT0);
102    emitPutCellToCallFrameHeader(regT1, JSStack::ScopeChain);
103
104    preserveReturnAddressAfterCall(regT3); // Callee preserved
105    emitPutToCallFrameHeader(regT3, JSStack::ReturnPC);
106
107    // Calling convention:      f(a0, a1, a2, a3);
108    // Host function signature: f(ExecState*);
109
110    // Allocate stack space for 16 bytes (8-byte aligned)
111    // 16 bytes (unused) for 4 arguments
112    subPtr(TrustedImm32(16), stackPointerRegister);
113
114    // Setup arg0
115    move(callFrameRegister, MIPSRegisters::a0);
116
117    // Call
118    emitGetFromCallFrameHeaderPtr(JSStack::Callee, MIPSRegisters::a2);
119    loadPtr(Address(MIPSRegisters::a2, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
120    move(regT0, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
121
122    // call the function
123    nativeCall = call();
124
125    // Restore stack space
126    addPtr(TrustedImm32(16), stackPointerRegister);
127
128    restoreReturnAddressBeforeReturn(regT3);
129#elif CPU(SH4)
130    // Load caller frame's scope chain into this callframe so that whatever we call can
131    // get to its global data.
132    emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, regT2);
133    emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, regT1, regT2);
134    emitPutCellToCallFrameHeader(regT1, JSStack::ScopeChain);
135
136    preserveReturnAddressAfterCall(regT3); // Callee preserved
137    emitPutToCallFrameHeader(regT3, JSStack::ReturnPC);
138
139    // Calling convention: f(r0 == regT4, r1 == regT5, ...);
140    // Host function signature: f(ExecState*);
141    move(callFrameRegister, regT4);
142
143    emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT5);
144    move(regT2, callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
145    loadPtr(Address(regT5, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2);
146
147    // call the function
148    nativeCall = call();
149
150    restoreReturnAddressBeforeReturn(regT3);
151#else
152#error "JIT not supported on this platform."
153    breakpoint();
154#endif // CPU(X86)
155
156    // Check for an exception
157    Jump sawException = branch32(NotEqual, AbsoluteAddress(reinterpret_cast<char*>(&vm->exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag));
158
159    // Return.
160    ret();
161
162    // Handle an exception
163    sawException.link(this);
164
165    // Grab the return address.
166    preserveReturnAddressAfterCall(regT1);
167
168    move(TrustedImmPtr(&vm->exceptionLocation), regT2);
169    storePtr(regT1, regT2);
170    poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof(void*));
171
172    storePtr(callFrameRegister, &m_vm->topCallFrame);
173    // Set the return address.
174    move(TrustedImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT1);
175    restoreReturnAddressBeforeReturn(regT1);
176
177    ret();
178
179    // All trampolines constructed! copy the code, link up calls, and set the pointers on the Machine object.
180    LinkBuffer patchBuffer(*m_vm, this, GLOBAL_THUNK_ID);
181
182    patchBuffer.link(nativeCall, FunctionPtr(func));
183    return FINALIZE_CODE(patchBuffer, ("JIT CTI native call"));
184}
185
186void JIT::emit_op_mov(Instruction* currentInstruction)
187{
188    unsigned dst = currentInstruction[1].u.operand;
189    unsigned src = currentInstruction[2].u.operand;
190
191    if (m_codeBlock->isConstantRegisterIndex(src))
192        emitStore(dst, getConstantOperand(src));
193    else {
194        emitLoad(src, regT1, regT0);
195        emitStore(dst, regT1, regT0);
196        map(m_bytecodeOffset + OPCODE_LENGTH(op_mov), dst, regT1, regT0);
197    }
198}
199
200void JIT::emit_op_end(Instruction* currentInstruction)
201{
202    ASSERT(returnValueRegister != callFrameRegister);
203    emitLoad(currentInstruction[1].u.operand, regT1, regT0);
204    restoreReturnAddressBeforeReturn(Address(callFrameRegister, JSStack::ReturnPC * static_cast<int>(sizeof(Register))));
205    ret();
206}
207
208void JIT::emit_op_jmp(Instruction* currentInstruction)
209{
210    unsigned target = currentInstruction[1].u.operand;
211    addJump(jump(), target);
212}
213
214void JIT::emit_op_new_object(Instruction* currentInstruction)
215{
216    Structure* structure = currentInstruction[3].u.objectAllocationProfile->structure();
217    size_t allocationSize = JSObject::allocationSize(structure->inlineCapacity());
218    MarkedAllocator* allocator = &m_vm->heap.allocatorForObjectWithoutDestructor(allocationSize);
219
220    RegisterID resultReg = regT0;
221    RegisterID allocatorReg = regT1;
222    RegisterID scratchReg = regT2;
223
224    move(TrustedImmPtr(allocator), allocatorReg);
225    emitAllocateJSObject(allocatorReg, TrustedImmPtr(structure), resultReg, scratchReg);
226    emitStoreCell(currentInstruction[1].u.operand, resultReg);
227}
228
229void JIT::emitSlow_op_new_object(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
230{
231    linkSlowCase(iter);
232    JITStubCall stubCall(this, cti_op_new_object);
233    stubCall.addArgument(TrustedImmPtr(currentInstruction[3].u.objectAllocationProfile->structure()));
234    stubCall.call(currentInstruction[1].u.operand);
235}
236
237void JIT::emit_op_check_has_instance(Instruction* currentInstruction)
238{
239    unsigned baseVal = currentInstruction[3].u.operand;
240
241    emitLoadPayload(baseVal, regT0);
242
243    // Check that baseVal is a cell.
244    emitJumpSlowCaseIfNotJSCell(baseVal);
245
246    // Check that baseVal 'ImplementsHasInstance'.
247    loadPtr(Address(regT0, JSCell::structureOffset()), regT0);
248    addSlowCase(branchTest8(Zero, Address(regT0, Structure::typeInfoFlagsOffset()), TrustedImm32(ImplementsDefaultHasInstance)));
249}
250
251void JIT::emit_op_instanceof(Instruction* currentInstruction)
252{
253    unsigned dst = currentInstruction[1].u.operand;
254    unsigned value = currentInstruction[2].u.operand;
255    unsigned proto = currentInstruction[3].u.operand;
256
257    // Load the operands into registers.
258    // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result.
259    emitLoadPayload(value, regT2);
260    emitLoadPayload(proto, regT1);
261
262    // Check that proto are cells.  baseVal must be a cell - this is checked by op_check_has_instance.
263    emitJumpSlowCaseIfNotJSCell(value);
264    emitJumpSlowCaseIfNotJSCell(proto);
265
266    // Check that prototype is an object
267    loadPtr(Address(regT1, JSCell::structureOffset()), regT3);
268    addSlowCase(emitJumpIfNotObject(regT3));
269
270    // Optimistically load the result true, and start looping.
271    // Initially, regT1 still contains proto and regT2 still contains value.
272    // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain.
273    move(TrustedImm32(1), regT0);
274    Label loop(this);
275
276    // Load the prototype of the cell in regT2.  If this is equal to regT1 - WIN!
277    // Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again.
278    loadPtr(Address(regT2, JSCell::structureOffset()), regT2);
279    load32(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
280    Jump isInstance = branchPtr(Equal, regT2, regT1);
281    branchTest32(NonZero, regT2).linkTo(loop, this);
282
283    // We get here either by dropping out of the loop, or if value was not an Object.  Result is false.
284    move(TrustedImm32(0), regT0);
285
286    // isInstance jumps right down to here, to skip setting the result to false (it has already set true).
287    isInstance.link(this);
288    emitStoreBool(dst, regT0);
289}
290
291void JIT::emitSlow_op_check_has_instance(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
292{
293    unsigned dst = currentInstruction[1].u.operand;
294    unsigned value = currentInstruction[2].u.operand;
295    unsigned baseVal = currentInstruction[3].u.operand;
296
297    linkSlowCaseIfNotJSCell(iter, baseVal);
298    linkSlowCase(iter);
299
300    JITStubCall stubCall(this, cti_op_check_has_instance);
301    stubCall.addArgument(value);
302    stubCall.addArgument(baseVal);
303    stubCall.call(dst);
304
305    emitJumpSlowToHot(jump(), currentInstruction[4].u.operand);
306}
307
308void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
309{
310    unsigned dst = currentInstruction[1].u.operand;
311    unsigned value = currentInstruction[2].u.operand;
312    unsigned proto = currentInstruction[3].u.operand;
313
314    linkSlowCaseIfNotJSCell(iter, value);
315    linkSlowCaseIfNotJSCell(iter, proto);
316    linkSlowCase(iter);
317
318    JITStubCall stubCall(this, cti_op_instanceof);
319    stubCall.addArgument(value);
320    stubCall.addArgument(proto);
321    stubCall.call(dst);
322}
323
324void JIT::emit_op_is_undefined(Instruction* currentInstruction)
325{
326    unsigned dst = currentInstruction[1].u.operand;
327    unsigned value = currentInstruction[2].u.operand;
328
329    emitLoad(value, regT1, regT0);
330    Jump isCell = branch32(Equal, regT1, TrustedImm32(JSValue::CellTag));
331
332    compare32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag), regT0);
333    Jump done = jump();
334
335    isCell.link(this);
336    loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
337    Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT1, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
338    move(TrustedImm32(0), regT0);
339    Jump notMasqueradesAsUndefined = jump();
340
341    isMasqueradesAsUndefined.link(this);
342    move(TrustedImmPtr(m_codeBlock->globalObject()), regT0);
343    loadPtr(Address(regT1, Structure::globalObjectOffset()), regT1);
344    compare32(Equal, regT0, regT1, regT0);
345
346    notMasqueradesAsUndefined.link(this);
347    done.link(this);
348    emitStoreBool(dst, regT0);
349}
350
351void JIT::emit_op_is_boolean(Instruction* currentInstruction)
352{
353    unsigned dst = currentInstruction[1].u.operand;
354    unsigned value = currentInstruction[2].u.operand;
355
356    emitLoadTag(value, regT0);
357    compare32(Equal, regT0, TrustedImm32(JSValue::BooleanTag), regT0);
358    emitStoreBool(dst, regT0);
359}
360
361void JIT::emit_op_is_number(Instruction* currentInstruction)
362{
363    unsigned dst = currentInstruction[1].u.operand;
364    unsigned value = currentInstruction[2].u.operand;
365
366    emitLoadTag(value, regT0);
367    add32(TrustedImm32(1), regT0);
368    compare32(Below, regT0, TrustedImm32(JSValue::LowestTag + 1), regT0);
369    emitStoreBool(dst, regT0);
370}
371
372void JIT::emit_op_is_string(Instruction* currentInstruction)
373{
374    unsigned dst = currentInstruction[1].u.operand;
375    unsigned value = currentInstruction[2].u.operand;
376
377    emitLoad(value, regT1, regT0);
378    Jump isNotCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
379
380    loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
381    compare8(Equal, Address(regT1, Structure::typeInfoTypeOffset()), TrustedImm32(StringType), regT0);
382    Jump done = jump();
383
384    isNotCell.link(this);
385    move(TrustedImm32(0), regT0);
386
387    done.link(this);
388    emitStoreBool(dst, regT0);
389}
390
391void JIT::emit_op_tear_off_activation(Instruction* currentInstruction)
392{
393    unsigned activation = currentInstruction[1].u.operand;
394    Jump activationNotCreated = branch32(Equal, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag));
395    JITStubCall stubCall(this, cti_op_tear_off_activation);
396    stubCall.addArgument(activation);
397    stubCall.call();
398    activationNotCreated.link(this);
399}
400
401void JIT::emit_op_tear_off_arguments(Instruction* currentInstruction)
402{
403    int arguments = currentInstruction[1].u.operand;
404    int activation = currentInstruction[2].u.operand;
405
406    Jump argsNotCreated = branch32(Equal, tagFor(unmodifiedArgumentsRegister(arguments)), TrustedImm32(JSValue::EmptyValueTag));
407    JITStubCall stubCall(this, cti_op_tear_off_arguments);
408    stubCall.addArgument(unmodifiedArgumentsRegister(arguments));
409    stubCall.addArgument(activation);
410    stubCall.call();
411    argsNotCreated.link(this);
412}
413
414void JIT::emit_op_to_primitive(Instruction* currentInstruction)
415{
416    int dst = currentInstruction[1].u.operand;
417    int src = currentInstruction[2].u.operand;
418
419    emitLoad(src, regT1, regT0);
420
421    Jump isImm = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
422    addSlowCase(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
423    isImm.link(this);
424
425    if (dst != src)
426        emitStore(dst, regT1, regT0);
427    map(m_bytecodeOffset + OPCODE_LENGTH(op_to_primitive), dst, regT1, regT0);
428}
429
430void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
431{
432    int dst = currentInstruction[1].u.operand;
433
434    linkSlowCase(iter);
435
436    JITStubCall stubCall(this, cti_op_to_primitive);
437    stubCall.addArgument(regT1, regT0);
438    stubCall.call(dst);
439}
440
441void JIT::emit_op_strcat(Instruction* currentInstruction)
442{
443    JITStubCall stubCall(this, cti_op_strcat);
444    stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand));
445    stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
446    stubCall.call(currentInstruction[1].u.operand);
447}
448
449void JIT::emit_op_not(Instruction* currentInstruction)
450{
451    unsigned dst = currentInstruction[1].u.operand;
452    unsigned src = currentInstruction[2].u.operand;
453
454    emitLoadTag(src, regT0);
455
456    emitLoad(src, regT1, regT0);
457    addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::BooleanTag)));
458    xor32(TrustedImm32(1), regT0);
459
460    emitStoreBool(dst, regT0, (dst == src));
461}
462
463void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
464{
465    unsigned dst = currentInstruction[1].u.operand;
466    unsigned src = currentInstruction[2].u.operand;
467
468    linkSlowCase(iter);
469
470    JITStubCall stubCall(this, cti_op_not);
471    stubCall.addArgument(src);
472    stubCall.call(dst);
473}
474
475void JIT::emit_op_jfalse(Instruction* currentInstruction)
476{
477    unsigned cond = currentInstruction[1].u.operand;
478    unsigned target = currentInstruction[2].u.operand;
479
480    emitLoad(cond, regT1, regT0);
481
482    ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1));
483    addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag)));
484    addJump(branchTest32(Zero, regT0), target);
485}
486
487void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
488{
489    unsigned cond = currentInstruction[1].u.operand;
490    unsigned target = currentInstruction[2].u.operand;
491
492    linkSlowCase(iter);
493
494    if (supportsFloatingPoint()) {
495        // regT1 contains the tag from the hot path.
496        Jump notNumber = branch32(Above, regT1, TrustedImm32(JSValue::LowestTag));
497
498        emitLoadDouble(cond, fpRegT0);
499        emitJumpSlowToHot(branchDoubleZeroOrNaN(fpRegT0, fpRegT1), target);
500        emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jfalse));
501
502        notNumber.link(this);
503    }
504
505    JITStubCall stubCall(this, cti_op_jtrue);
506    stubCall.addArgument(cond);
507    stubCall.call();
508    emitJumpSlowToHot(branchTest32(Zero, regT0), target); // Inverted.
509}
510
511void JIT::emit_op_jtrue(Instruction* currentInstruction)
512{
513    unsigned cond = currentInstruction[1].u.operand;
514    unsigned target = currentInstruction[2].u.operand;
515
516    emitLoad(cond, regT1, regT0);
517
518    ASSERT((JSValue::BooleanTag + 1 == JSValue::Int32Tag) && !(JSValue::Int32Tag + 1));
519    addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::BooleanTag)));
520    addJump(branchTest32(NonZero, regT0), target);
521}
522
523void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
524{
525    unsigned cond = currentInstruction[1].u.operand;
526    unsigned target = currentInstruction[2].u.operand;
527
528    linkSlowCase(iter);
529
530    if (supportsFloatingPoint()) {
531        // regT1 contains the tag from the hot path.
532        Jump notNumber = branch32(Above, regT1, TrustedImm32(JSValue::LowestTag));
533
534        emitLoadDouble(cond, fpRegT0);
535        emitJumpSlowToHot(branchDoubleNonZero(fpRegT0, fpRegT1), target);
536        emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jtrue));
537
538        notNumber.link(this);
539    }
540
541    JITStubCall stubCall(this, cti_op_jtrue);
542    stubCall.addArgument(cond);
543    stubCall.call();
544    emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
545}
546
547void JIT::emit_op_jeq_null(Instruction* currentInstruction)
548{
549    unsigned src = currentInstruction[1].u.operand;
550    unsigned target = currentInstruction[2].u.operand;
551
552    emitLoad(src, regT1, regT0);
553
554    Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
555
556    // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure.
557    loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
558    Jump isNotMasqueradesAsUndefined = branchTest8(Zero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
559    move(TrustedImmPtr(m_codeBlock->globalObject()), regT0);
560    addJump(branchPtr(Equal, Address(regT2, Structure::globalObjectOffset()), regT0), target);
561    Jump masqueradesGlobalObjectIsForeign = jump();
562
563    // Now handle the immediate cases - undefined & null
564    isImmediate.link(this);
565    ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1));
566    or32(TrustedImm32(1), regT1);
567    addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), target);
568
569    isNotMasqueradesAsUndefined.link(this);
570    masqueradesGlobalObjectIsForeign.link(this);
571}
572
573void JIT::emit_op_jneq_null(Instruction* currentInstruction)
574{
575    unsigned src = currentInstruction[1].u.operand;
576    unsigned target = currentInstruction[2].u.operand;
577
578    emitLoad(src, regT1, regT0);
579
580    Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
581
582    // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure.
583    loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
584    addJump(branchTest8(Zero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined)), target);
585    move(TrustedImmPtr(m_codeBlock->globalObject()), regT0);
586    addJump(branchPtr(NotEqual, Address(regT2, Structure::globalObjectOffset()), regT0), target);
587    Jump wasNotImmediate = jump();
588
589    // Now handle the immediate cases - undefined & null
590    isImmediate.link(this);
591
592    ASSERT((JSValue::UndefinedTag + 1 == JSValue::NullTag) && (JSValue::NullTag & 0x1));
593    or32(TrustedImm32(1), regT1);
594    addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::NullTag)), target);
595
596    wasNotImmediate.link(this);
597}
598
599void JIT::emit_op_jneq_ptr(Instruction* currentInstruction)
600{
601    unsigned src = currentInstruction[1].u.operand;
602    Special::Pointer ptr = currentInstruction[2].u.specialPointer;
603    unsigned target = currentInstruction[3].u.operand;
604
605    emitLoad(src, regT1, regT0);
606    addJump(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)), target);
607    addJump(branchPtr(NotEqual, regT0, TrustedImmPtr(actualPointerFor(m_codeBlock, ptr))), target);
608}
609
610void JIT::emit_op_eq(Instruction* currentInstruction)
611{
612    unsigned dst = currentInstruction[1].u.operand;
613    unsigned src1 = currentInstruction[2].u.operand;
614    unsigned src2 = currentInstruction[3].u.operand;
615
616    emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
617    addSlowCase(branch32(NotEqual, regT1, regT3));
618    addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
619    addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
620
621    compare32(Equal, regT0, regT2, regT0);
622
623    emitStoreBool(dst, regT0);
624}
625
626void JIT::emitSlow_op_eq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
627{
628    unsigned dst = currentInstruction[1].u.operand;
629    unsigned op1 = currentInstruction[2].u.operand;
630    unsigned op2 = currentInstruction[3].u.operand;
631
632    JumpList storeResult;
633    JumpList genericCase;
634
635    genericCase.append(getSlowCase(iter)); // tags not equal
636
637    linkSlowCase(iter); // tags equal and JSCell
638    genericCase.append(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
639    genericCase.append(branchPtr(NotEqual, Address(regT2, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
640
641    // String case.
642    JITStubCall stubCallEqStrings(this, cti_op_eq_strings);
643    stubCallEqStrings.addArgument(regT0);
644    stubCallEqStrings.addArgument(regT2);
645    stubCallEqStrings.call();
646    storeResult.append(jump());
647
648    // Generic case.
649    genericCase.append(getSlowCase(iter)); // doubles
650    genericCase.link(this);
651    JITStubCall stubCallEq(this, cti_op_eq);
652    stubCallEq.addArgument(op1);
653    stubCallEq.addArgument(op2);
654    stubCallEq.call(regT0);
655
656    storeResult.link(this);
657    emitStoreBool(dst, regT0);
658}
659
660void JIT::emit_op_neq(Instruction* currentInstruction)
661{
662    unsigned dst = currentInstruction[1].u.operand;
663    unsigned src1 = currentInstruction[2].u.operand;
664    unsigned src2 = currentInstruction[3].u.operand;
665
666    emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
667    addSlowCase(branch32(NotEqual, regT1, regT3));
668    addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::CellTag)));
669    addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
670
671    compare32(NotEqual, regT0, regT2, regT0);
672
673    emitStoreBool(dst, regT0);
674}
675
676void JIT::emitSlow_op_neq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
677{
678    unsigned dst = currentInstruction[1].u.operand;
679
680    JumpList storeResult;
681    JumpList genericCase;
682
683    genericCase.append(getSlowCase(iter)); // tags not equal
684
685    linkSlowCase(iter); // tags equal and JSCell
686    genericCase.append(branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
687    genericCase.append(branchPtr(NotEqual, Address(regT2, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
688
689    // String case.
690    JITStubCall stubCallEqStrings(this, cti_op_eq_strings);
691    stubCallEqStrings.addArgument(regT0);
692    stubCallEqStrings.addArgument(regT2);
693    stubCallEqStrings.call(regT0);
694    storeResult.append(jump());
695
696    // Generic case.
697    genericCase.append(getSlowCase(iter)); // doubles
698    genericCase.link(this);
699    JITStubCall stubCallEq(this, cti_op_eq);
700    stubCallEq.addArgument(regT1, regT0);
701    stubCallEq.addArgument(regT3, regT2);
702    stubCallEq.call(regT0);
703
704    storeResult.link(this);
705    xor32(TrustedImm32(0x1), regT0);
706    emitStoreBool(dst, regT0);
707}
708
709void JIT::compileOpStrictEq(Instruction* currentInstruction, CompileOpStrictEqType type)
710{
711    unsigned dst = currentInstruction[1].u.operand;
712    unsigned src1 = currentInstruction[2].u.operand;
713    unsigned src2 = currentInstruction[3].u.operand;
714
715    emitLoad2(src1, regT1, regT0, src2, regT3, regT2);
716
717    // Bail if the tags differ, or are double.
718    addSlowCase(branch32(NotEqual, regT1, regT3));
719    addSlowCase(branch32(Below, regT1, TrustedImm32(JSValue::LowestTag)));
720
721    // Jump to a slow case if both are strings.
722    Jump notCell = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
723    Jump firstNotString = branchPtr(NotEqual, Address(regT0, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get()));
724    addSlowCase(branchPtr(Equal, Address(regT2, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
725    notCell.link(this);
726    firstNotString.link(this);
727
728    // Simply compare the payloads.
729    if (type == OpStrictEq)
730        compare32(Equal, regT0, regT2, regT0);
731    else
732        compare32(NotEqual, regT0, regT2, regT0);
733
734    emitStoreBool(dst, regT0);
735}
736
737void JIT::emit_op_stricteq(Instruction* currentInstruction)
738{
739    compileOpStrictEq(currentInstruction, OpStrictEq);
740}
741
742void JIT::emitSlow_op_stricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
743{
744    unsigned dst = currentInstruction[1].u.operand;
745    unsigned src1 = currentInstruction[2].u.operand;
746    unsigned src2 = currentInstruction[3].u.operand;
747
748    linkSlowCase(iter);
749    linkSlowCase(iter);
750    linkSlowCase(iter);
751
752    JITStubCall stubCall(this, cti_op_stricteq);
753    stubCall.addArgument(src1);
754    stubCall.addArgument(src2);
755    stubCall.call(dst);
756}
757
758void JIT::emit_op_nstricteq(Instruction* currentInstruction)
759{
760    compileOpStrictEq(currentInstruction, OpNStrictEq);
761}
762
763void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
764{
765    unsigned dst = currentInstruction[1].u.operand;
766    unsigned src1 = currentInstruction[2].u.operand;
767    unsigned src2 = currentInstruction[3].u.operand;
768
769    linkSlowCase(iter);
770    linkSlowCase(iter);
771    linkSlowCase(iter);
772
773    JITStubCall stubCall(this, cti_op_nstricteq);
774    stubCall.addArgument(src1);
775    stubCall.addArgument(src2);
776    stubCall.call(dst);
777}
778
779void JIT::emit_op_eq_null(Instruction* currentInstruction)
780{
781    unsigned dst = currentInstruction[1].u.operand;
782    unsigned src = currentInstruction[2].u.operand;
783
784    emitLoad(src, regT1, regT0);
785    Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
786
787    loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
788    Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
789    move(TrustedImm32(0), regT1);
790    Jump wasNotMasqueradesAsUndefined = jump();
791
792    isMasqueradesAsUndefined.link(this);
793    move(TrustedImmPtr(m_codeBlock->globalObject()), regT0);
794    loadPtr(Address(regT2, Structure::globalObjectOffset()), regT2);
795    compare32(Equal, regT0, regT2, regT1);
796    Jump wasNotImmediate = jump();
797
798    isImmediate.link(this);
799
800    compare32(Equal, regT1, TrustedImm32(JSValue::NullTag), regT2);
801    compare32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
802    or32(regT2, regT1);
803
804    wasNotImmediate.link(this);
805    wasNotMasqueradesAsUndefined.link(this);
806
807    emitStoreBool(dst, regT1);
808}
809
810void JIT::emit_op_neq_null(Instruction* currentInstruction)
811{
812    unsigned dst = currentInstruction[1].u.operand;
813    unsigned src = currentInstruction[2].u.operand;
814
815    emitLoad(src, regT1, regT0);
816    Jump isImmediate = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
817
818    loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
819    Jump isMasqueradesAsUndefined = branchTest8(NonZero, Address(regT2, Structure::typeInfoFlagsOffset()), TrustedImm32(MasqueradesAsUndefined));
820    move(TrustedImm32(1), regT1);
821    Jump wasNotMasqueradesAsUndefined = jump();
822
823    isMasqueradesAsUndefined.link(this);
824    move(TrustedImmPtr(m_codeBlock->globalObject()), regT0);
825    loadPtr(Address(regT2, Structure::globalObjectOffset()), regT2);
826    compare32(NotEqual, regT0, regT2, regT1);
827    Jump wasNotImmediate = jump();
828
829    isImmediate.link(this);
830
831    compare32(NotEqual, regT1, TrustedImm32(JSValue::NullTag), regT2);
832    compare32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag), regT1);
833    and32(regT2, regT1);
834
835    wasNotImmediate.link(this);
836    wasNotMasqueradesAsUndefined.link(this);
837
838    emitStoreBool(dst, regT1);
839}
840
841void JIT::emit_op_throw(Instruction* currentInstruction)
842{
843    unsigned exception = currentInstruction[1].u.operand;
844    JITStubCall stubCall(this, cti_op_throw);
845    stubCall.addArgument(exception);
846    stubCall.call();
847
848#ifndef NDEBUG
849    // cti_op_throw always changes it's return address,
850    // this point in the code should never be reached.
851    breakpoint();
852#endif
853}
854
855void JIT::emit_op_get_pnames(Instruction* currentInstruction)
856{
857    int dst = currentInstruction[1].u.operand;
858    int base = currentInstruction[2].u.operand;
859    int i = currentInstruction[3].u.operand;
860    int size = currentInstruction[4].u.operand;
861    int breakTarget = currentInstruction[5].u.operand;
862
863    JumpList isNotObject;
864
865    emitLoad(base, regT1, regT0);
866    if (!m_codeBlock->isKnownNotImmediate(base))
867        isNotObject.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
868    if (base != m_codeBlock->thisRegister() || m_codeBlock->isStrictMode()) {
869        loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
870        isNotObject.append(emitJumpIfNotObject(regT2));
871    }
872
873    // We could inline the case where you have a valid cache, but
874    // this call doesn't seem to be hot.
875    Label isObject(this);
876    JITStubCall getPnamesStubCall(this, cti_op_get_pnames);
877    getPnamesStubCall.addArgument(regT0);
878    getPnamesStubCall.call(dst);
879    load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3);
880    store32(TrustedImm32(Int32Tag), intTagFor(i));
881    store32(TrustedImm32(0), intPayloadFor(i));
882    store32(TrustedImm32(Int32Tag), intTagFor(size));
883    store32(regT3, payloadFor(size));
884    Jump end = jump();
885
886    isNotObject.link(this);
887    addJump(branch32(Equal, regT1, TrustedImm32(JSValue::NullTag)), breakTarget);
888    addJump(branch32(Equal, regT1, TrustedImm32(JSValue::UndefinedTag)), breakTarget);
889    JITStubCall toObjectStubCall(this, cti_to_object);
890    toObjectStubCall.addArgument(regT1, regT0);
891    toObjectStubCall.call(base);
892    jump().linkTo(isObject, this);
893
894    end.link(this);
895}
896
897void JIT::emit_op_next_pname(Instruction* currentInstruction)
898{
899    int dst = currentInstruction[1].u.operand;
900    int base = currentInstruction[2].u.operand;
901    int i = currentInstruction[3].u.operand;
902    int size = currentInstruction[4].u.operand;
903    int it = currentInstruction[5].u.operand;
904    int target = currentInstruction[6].u.operand;
905
906    JumpList callHasProperty;
907
908    Label begin(this);
909    load32(intPayloadFor(i), regT0);
910    Jump end = branch32(Equal, regT0, intPayloadFor(size));
911
912    // Grab key @ i
913    loadPtr(payloadFor(it), regT1);
914    loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2);
915    load32(BaseIndex(regT2, regT0, TimesEight), regT2);
916    store32(TrustedImm32(JSValue::CellTag), tagFor(dst));
917    store32(regT2, payloadFor(dst));
918
919    // Increment i
920    add32(TrustedImm32(1), regT0);
921    store32(regT0, intPayloadFor(i));
922
923    // Verify that i is valid:
924    loadPtr(payloadFor(base), regT0);
925
926    // Test base's structure
927    loadPtr(Address(regT0, JSCell::structureOffset()), regT2);
928    callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))));
929
930    // Test base's prototype chain
931    loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3);
932    loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3);
933    addJump(branchTestPtr(Zero, Address(regT3)), target);
934
935    Label checkPrototype(this);
936    callHasProperty.append(branch32(Equal, Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::NullTag)));
937    loadPtr(Address(regT2, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2);
938    loadPtr(Address(regT2, JSCell::structureOffset()), regT2);
939    callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3)));
940    addPtr(TrustedImm32(sizeof(Structure*)), regT3);
941    branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this);
942
943    // Continue loop.
944    addJump(jump(), target);
945
946    // Slow case: Ask the object if i is valid.
947    callHasProperty.link(this);
948    loadPtr(addressFor(dst), regT1);
949    JITStubCall stubCall(this, cti_has_property);
950    stubCall.addArgument(regT0);
951    stubCall.addArgument(regT1);
952    stubCall.call();
953
954    // Test for valid key.
955    addJump(branchTest32(NonZero, regT0), target);
956    jump().linkTo(begin, this);
957
958    // End of loop.
959    end.link(this);
960}
961
962void JIT::emit_op_push_with_scope(Instruction* currentInstruction)
963{
964    JITStubCall stubCall(this, cti_op_push_with_scope);
965    stubCall.addArgument(currentInstruction[1].u.operand);
966    stubCall.call();
967}
968
969void JIT::emit_op_pop_scope(Instruction*)
970{
971    JITStubCall(this, cti_op_pop_scope).call();
972}
973
974void JIT::emit_op_to_number(Instruction* currentInstruction)
975{
976    int dst = currentInstruction[1].u.operand;
977    int src = currentInstruction[2].u.operand;
978
979    emitLoad(src, regT1, regT0);
980
981    Jump isInt32 = branch32(Equal, regT1, TrustedImm32(JSValue::Int32Tag));
982    addSlowCase(branch32(AboveOrEqual, regT1, TrustedImm32(JSValue::LowestTag)));
983    isInt32.link(this);
984
985    if (src != dst)
986        emitStore(dst, regT1, regT0);
987    map(m_bytecodeOffset + OPCODE_LENGTH(op_to_number), dst, regT1, regT0);
988}
989
990void JIT::emitSlow_op_to_number(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
991{
992    int dst = currentInstruction[1].u.operand;
993
994    linkSlowCase(iter);
995
996    JITStubCall stubCall(this, cti_op_to_number);
997    stubCall.addArgument(regT1, regT0);
998    stubCall.call(dst);
999}
1000
1001void JIT::emit_op_push_name_scope(Instruction* currentInstruction)
1002{
1003    JITStubCall stubCall(this, cti_op_push_name_scope);
1004    stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(currentInstruction[1].u.operand)));
1005    stubCall.addArgument(currentInstruction[2].u.operand);
1006    stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
1007    stubCall.call();
1008}
1009
1010void JIT::emit_op_catch(Instruction* currentInstruction)
1011{
1012    // cti_op_throw returns the callFrame for the handler.
1013    move(regT0, callFrameRegister);
1014
1015    // Now store the exception returned by cti_op_throw.
1016    loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(struct JITStackFrame, vm)), regT3);
1017    load32(Address(regT3, OBJECT_OFFSETOF(VM, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT0);
1018    load32(Address(regT3, OBJECT_OFFSETOF(VM, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), regT1);
1019    store32(TrustedImm32(JSValue().payload()), Address(regT3, OBJECT_OFFSETOF(VM, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1020    store32(TrustedImm32(JSValue().tag()), Address(regT3, OBJECT_OFFSETOF(VM, exception) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1021
1022    unsigned exception = currentInstruction[1].u.operand;
1023    emitStore(exception, regT1, regT0);
1024    map(m_bytecodeOffset + OPCODE_LENGTH(op_catch), exception, regT1, regT0);
1025}
1026
1027void JIT::emit_op_switch_imm(Instruction* currentInstruction)
1028{
1029    unsigned tableIndex = currentInstruction[1].u.operand;
1030    unsigned defaultOffset = currentInstruction[2].u.operand;
1031    unsigned scrutinee = currentInstruction[3].u.operand;
1032
1033    // create jump table for switch destinations, track this switch statement.
1034    SimpleJumpTable* jumpTable = &m_codeBlock->immediateSwitchJumpTable(tableIndex);
1035    m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Immediate));
1036    jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
1037
1038    JITStubCall stubCall(this, cti_op_switch_imm);
1039    stubCall.addArgument(scrutinee);
1040    stubCall.addArgument(TrustedImm32(tableIndex));
1041    stubCall.call();
1042    jump(regT0);
1043}
1044
1045void JIT::emit_op_switch_char(Instruction* currentInstruction)
1046{
1047    unsigned tableIndex = currentInstruction[1].u.operand;
1048    unsigned defaultOffset = currentInstruction[2].u.operand;
1049    unsigned scrutinee = currentInstruction[3].u.operand;
1050
1051    // create jump table for switch destinations, track this switch statement.
1052    SimpleJumpTable* jumpTable = &m_codeBlock->characterSwitchJumpTable(tableIndex);
1053    m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset, SwitchRecord::Character));
1054    jumpTable->ctiOffsets.grow(jumpTable->branchOffsets.size());
1055
1056    JITStubCall stubCall(this, cti_op_switch_char);
1057    stubCall.addArgument(scrutinee);
1058    stubCall.addArgument(TrustedImm32(tableIndex));
1059    stubCall.call();
1060    jump(regT0);
1061}
1062
1063void JIT::emit_op_switch_string(Instruction* currentInstruction)
1064{
1065    unsigned tableIndex = currentInstruction[1].u.operand;
1066    unsigned defaultOffset = currentInstruction[2].u.operand;
1067    unsigned scrutinee = currentInstruction[3].u.operand;
1068
1069    // create jump table for switch destinations, track this switch statement.
1070    StringJumpTable* jumpTable = &m_codeBlock->stringSwitchJumpTable(tableIndex);
1071    m_switches.append(SwitchRecord(jumpTable, m_bytecodeOffset, defaultOffset));
1072
1073    JITStubCall stubCall(this, cti_op_switch_string);
1074    stubCall.addArgument(scrutinee);
1075    stubCall.addArgument(TrustedImm32(tableIndex));
1076    stubCall.call();
1077    jump(regT0);
1078}
1079
1080void JIT::emit_op_throw_static_error(Instruction* currentInstruction)
1081{
1082    unsigned message = currentInstruction[1].u.operand;
1083
1084    JITStubCall stubCall(this, cti_op_throw_static_error);
1085    stubCall.addArgument(m_codeBlock->getConstant(message));
1086    stubCall.addArgument(TrustedImm32(currentInstruction[2].u.operand));
1087    stubCall.call();
1088}
1089
1090void JIT::emit_op_debug(Instruction* currentInstruction)
1091{
1092#if ENABLE(DEBUG_WITH_BREAKPOINT)
1093    UNUSED_PARAM(currentInstruction);
1094    breakpoint();
1095#else
1096    JITStubCall stubCall(this, cti_op_debug);
1097    stubCall.addArgument(Imm32(currentInstruction[1].u.operand));
1098    stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
1099    stubCall.addArgument(Imm32(currentInstruction[3].u.operand));
1100    stubCall.addArgument(Imm32(currentInstruction[4].u.operand));
1101    stubCall.call();
1102#endif
1103}
1104
1105
1106void JIT::emit_op_enter(Instruction*)
1107{
1108    emitEnterOptimizationCheck();
1109
1110    // Even though JIT code doesn't use them, we initialize our constant
1111    // registers to zap stale pointers, to avoid unnecessarily prolonging
1112    // object lifetime and increasing GC pressure.
1113    for (int i = 0; i < m_codeBlock->m_numVars; ++i)
1114        emitStore(i, jsUndefined());
1115}
1116
1117void JIT::emit_op_create_activation(Instruction* currentInstruction)
1118{
1119    unsigned activation = currentInstruction[1].u.operand;
1120
1121    Jump activationCreated = branch32(NotEqual, tagFor(activation), TrustedImm32(JSValue::EmptyValueTag));
1122    JITStubCall(this, cti_op_push_activation).call(activation);
1123    activationCreated.link(this);
1124}
1125
1126void JIT::emit_op_create_arguments(Instruction* currentInstruction)
1127{
1128    unsigned dst = currentInstruction[1].u.operand;
1129
1130    Jump argsCreated = branch32(NotEqual, tagFor(dst), TrustedImm32(JSValue::EmptyValueTag));
1131
1132    JITStubCall(this, cti_op_create_arguments).call();
1133    emitStore(dst, regT1, regT0);
1134    emitStore(unmodifiedArgumentsRegister(dst), regT1, regT0);
1135
1136    argsCreated.link(this);
1137}
1138
1139void JIT::emit_op_init_lazy_reg(Instruction* currentInstruction)
1140{
1141    unsigned dst = currentInstruction[1].u.operand;
1142
1143    emitStore(dst, JSValue());
1144}
1145
1146void JIT::emit_op_get_callee(Instruction* currentInstruction)
1147{
1148    int dst = currentInstruction[1].u.operand;
1149    emitGetFromCallFrameHeaderPtr(JSStack::Callee, regT0);
1150    move(TrustedImm32(JSValue::CellTag), regT1);
1151    emitValueProfilingSite();
1152    emitStore(dst, regT1, regT0);
1153}
1154
1155void JIT::emit_op_create_this(Instruction* currentInstruction)
1156{
1157    int callee = currentInstruction[2].u.operand;
1158    RegisterID calleeReg = regT0;
1159    RegisterID resultReg = regT0;
1160    RegisterID allocatorReg = regT1;
1161    RegisterID structureReg = regT2;
1162    RegisterID scratchReg = regT3;
1163
1164    emitLoadPayload(callee, calleeReg);
1165    loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()), allocatorReg);
1166    loadPtr(Address(calleeReg, JSFunction::offsetOfAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()), structureReg);
1167    addSlowCase(branchTestPtr(Zero, allocatorReg));
1168
1169    emitAllocateJSObject(allocatorReg, structureReg, resultReg, scratchReg);
1170    emitStoreCell(currentInstruction[1].u.operand, resultReg);
1171}
1172
1173void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1174{
1175    linkSlowCase(iter); // doesn't have an allocation profile
1176    linkSlowCase(iter); // allocation failed
1177
1178    JITStubCall stubCall(this, cti_op_create_this);
1179    stubCall.addArgument(TrustedImm32(currentInstruction[3].u.operand));
1180    stubCall.call(currentInstruction[1].u.operand);
1181}
1182
1183void JIT::emit_op_convert_this(Instruction* currentInstruction)
1184{
1185    unsigned thisRegister = currentInstruction[1].u.operand;
1186
1187    emitLoad(thisRegister, regT3, regT2);
1188
1189    addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::CellTag)));
1190    if (shouldEmitProfiling()) {
1191        loadPtr(Address(regT2, JSCell::structureOffset()), regT0);
1192        move(regT3, regT1);
1193        emitValueProfilingSite();
1194    }
1195    addSlowCase(branchPtr(Equal, Address(regT2, JSCell::structureOffset()), TrustedImmPtr(m_vm->stringStructure.get())));
1196}
1197
1198void JIT::emitSlow_op_convert_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1199{
1200    void* globalThis = m_codeBlock->globalObject()->globalThis();
1201    unsigned thisRegister = currentInstruction[1].u.operand;
1202
1203    linkSlowCase(iter);
1204    if (shouldEmitProfiling()) {
1205        move(TrustedImm32(JSValue::UndefinedTag), regT1);
1206        move(TrustedImm32(0), regT0);
1207    }
1208    Jump isNotUndefined = branch32(NotEqual, regT3, TrustedImm32(JSValue::UndefinedTag));
1209    emitValueProfilingSite();
1210    move(TrustedImmPtr(globalThis), regT0);
1211    move(TrustedImm32(JSValue::CellTag), regT1);
1212    emitStore(thisRegister, regT1, regT0);
1213    emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_convert_this));
1214
1215    linkSlowCase(iter);
1216    if (shouldEmitProfiling()) {
1217        move(TrustedImm32(JSValue::CellTag), regT1);
1218        move(TrustedImmPtr(m_vm->stringStructure.get()), regT0);
1219    }
1220    isNotUndefined.link(this);
1221    emitValueProfilingSite();
1222    JITStubCall stubCall(this, cti_op_convert_this);
1223    stubCall.addArgument(regT3, regT2);
1224    stubCall.call(thisRegister);
1225}
1226
1227void JIT::emit_op_profile_will_call(Instruction* currentInstruction)
1228{
1229    JITStubCall stubCall(this, cti_op_profile_will_call);
1230    stubCall.addArgument(currentInstruction[1].u.operand);
1231    stubCall.call();
1232}
1233
1234void JIT::emit_op_profile_did_call(Instruction* currentInstruction)
1235{
1236    JITStubCall stubCall(this, cti_op_profile_did_call);
1237    stubCall.addArgument(currentInstruction[1].u.operand);
1238    stubCall.call();
1239}
1240
1241void JIT::emit_op_get_arguments_length(Instruction* currentInstruction)
1242{
1243    int dst = currentInstruction[1].u.operand;
1244    int argumentsRegister = currentInstruction[2].u.operand;
1245    addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag)));
1246    load32(payloadFor(JSStack::ArgumentCount), regT0);
1247    sub32(TrustedImm32(1), regT0);
1248    emitStoreInt32(dst, regT0);
1249}
1250
1251void JIT::emitSlow_op_get_arguments_length(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1252{
1253    linkSlowCase(iter);
1254    int dst = currentInstruction[1].u.operand;
1255    int base = currentInstruction[2].u.operand;
1256    int ident = currentInstruction[3].u.operand;
1257
1258    JITStubCall stubCall(this, cti_op_get_by_id_generic);
1259    stubCall.addArgument(base);
1260    stubCall.addArgument(TrustedImmPtr(&(m_codeBlock->identifier(ident))));
1261    stubCall.call(dst);
1262}
1263
1264void JIT::emit_op_get_argument_by_val(Instruction* currentInstruction)
1265{
1266    int dst = currentInstruction[1].u.operand;
1267    int argumentsRegister = currentInstruction[2].u.operand;
1268    int property = currentInstruction[3].u.operand;
1269    addSlowCase(branch32(NotEqual, tagFor(argumentsRegister), TrustedImm32(JSValue::EmptyValueTag)));
1270    emitLoad(property, regT1, regT2);
1271    addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::Int32Tag)));
1272    add32(TrustedImm32(1), regT2);
1273    // regT2 now contains the integer index of the argument we want, including this
1274    load32(payloadFor(JSStack::ArgumentCount), regT3);
1275    addSlowCase(branch32(AboveOrEqual, regT2, regT3));
1276
1277    neg32(regT2);
1278    loadPtr(BaseIndex(callFrameRegister, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload) + CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))), regT0);
1279    loadPtr(BaseIndex(callFrameRegister, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag) + CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))), regT1);
1280    emitValueProfilingSite();
1281    emitStore(dst, regT1, regT0);
1282}
1283
1284void JIT::emitSlow_op_get_argument_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1285{
1286    unsigned dst = currentInstruction[1].u.operand;
1287    unsigned arguments = currentInstruction[2].u.operand;
1288    unsigned property = currentInstruction[3].u.operand;
1289
1290    linkSlowCase(iter);
1291    Jump skipArgumentsCreation = jump();
1292
1293    linkSlowCase(iter);
1294    linkSlowCase(iter);
1295    JITStubCall(this, cti_op_create_arguments).call();
1296    emitStore(arguments, regT1, regT0);
1297    emitStore(unmodifiedArgumentsRegister(arguments), regT1, regT0);
1298
1299    skipArgumentsCreation.link(this);
1300    JITStubCall stubCall(this, cti_op_get_by_val_generic);
1301    stubCall.addArgument(arguments);
1302    stubCall.addArgument(property);
1303    stubCall.callWithValueProfiling(dst);
1304}
1305
1306void JIT::emit_op_put_to_base(Instruction* currentInstruction)
1307{
1308    int base = currentInstruction[1].u.operand;
1309    int id = currentInstruction[2].u.operand;
1310    int value = currentInstruction[3].u.operand;
1311
1312    PutToBaseOperation* operation = currentInstruction[4].u.putToBaseOperation;
1313
1314
1315    switch (operation->m_kind) {
1316    case PutToBaseOperation::GlobalVariablePutChecked:
1317        addSlowCase(branchTest8(NonZero, AbsoluteAddress(operation->m_predicatePointer)));
1318    case PutToBaseOperation::GlobalVariablePut: {
1319        JSGlobalObject* globalObject = m_codeBlock->globalObject();
1320        if (operation->m_isDynamic)
1321            addSlowCase(branchPtr(NotEqual, payloadFor(base), TrustedImmPtr(globalObject)));
1322
1323        emitLoad(value, regT1, regT0);
1324        storePtr(regT0, reinterpret_cast<char*>(operation->m_registerAddress) + OBJECT_OFFSETOF(JSValue, u.asBits.payload));
1325        storePtr(regT1, reinterpret_cast<char*>(operation->m_registerAddress) + OBJECT_OFFSETOF(JSValue, u.asBits.tag));
1326        if (Heap::isWriteBarrierEnabled())
1327            emitWriteBarrier(globalObject, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
1328        break;
1329    }
1330    case PutToBaseOperation::VariablePut: {
1331        loadPtr(payloadFor(base), regT3);
1332        emitLoad(value, regT1, regT0);
1333        loadPtr(Address(regT3, JSVariableObject::offsetOfRegisters()), regT2);
1334        store32(regT0, Address(regT2, operation->m_offset * sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1335        store32(regT1, Address(regT2, operation->m_offset * sizeof(Register) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1336        if (Heap::isWriteBarrierEnabled())
1337            emitWriteBarrier(regT3, regT1, regT0, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
1338        break;
1339    }
1340
1341    case PutToBaseOperation::GlobalPropertyPut: {
1342        JSGlobalObject* globalObject = m_codeBlock->globalObject();
1343        loadPtr(payloadFor(base), regT3);
1344        emitLoad(value, regT1, regT0);
1345        loadPtr(&operation->m_structure, regT2);
1346        addSlowCase(branchPtr(NotEqual, Address(regT3, JSCell::structureOffset()), regT2));
1347        ASSERT(!operation->m_structure || !operation->m_structure->inlineCapacity());
1348        loadPtr(Address(regT3, JSObject::butterflyOffset()), regT2);
1349        load32(&operation->m_offsetInButterfly, regT3);
1350        storePtr(regT0, BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
1351        storePtr(regT1, BaseIndex(regT2, regT3, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
1352        if (Heap::isWriteBarrierEnabled())
1353            emitWriteBarrier(globalObject, regT1, regT2, ShouldFilterImmediates, WriteBarrierForVariableAccess);
1354        break;
1355    }
1356
1357    case PutToBaseOperation::Uninitialised:
1358    case PutToBaseOperation::Readonly:
1359    case PutToBaseOperation::Generic:
1360        JITStubCall stubCall(this, cti_op_put_to_base);
1361
1362        stubCall.addArgument(TrustedImm32(base));
1363        stubCall.addArgument(TrustedImmPtr(&m_codeBlock->identifier(id)));
1364        stubCall.addArgument(TrustedImm32(value));
1365        stubCall.addArgument(TrustedImmPtr(operation));
1366        stubCall.call();
1367        break;
1368    }
1369}
1370
1371} // namespace JSC
1372
1373#endif // USE(JSVALUE32_64)
1374#endif // ENABLE(JIT)
1375