Rename activation to be more in line with spec language
[WebKit-https.git] / Source / JavaScriptCore / llint / LowLevelInterpreter32_64.asm
1 # Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
6 # 1. Redistributions of source code must retain the above copyright
7 #    notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright
9 #    notice, this list of conditions and the following disclaimer in the
10 #    documentation and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
13 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
14 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
15 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
16 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
18 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
19 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
20 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
21 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
22 # THE POSSIBILITY OF SUCH DAMAGE.
23
24
25 # Crash course on the language that this is written in (which I just call
26 # "assembly" even though it's more than that):
27 #
28 # - Mostly gas-style operand ordering. The last operand tends to be the
29 #   destination. So "a := b" is written as "mov b, a". But unlike gas,
30 #   comparisons are in-order, so "if (a < b)" is written as
31 #   "bilt a, b, ...".
32 #
33 # - "b" = byte, "h" = 16-bit word, "i" = 32-bit word, "p" = pointer.
34 #   Currently this is just 32-bit so "i" and "p" are interchangeable
35 #   except when an op supports one but not the other.
36 #
37 # - In general, valid operands for macro invocations and instructions are
38 #   registers (eg "t0"), addresses (eg "4[t0]"), base-index addresses
39 #   (eg "7[t0, t1, 2]"), absolute addresses (eg "0xa0000000[]"), or labels
40 #   (eg "_foo" or ".foo"). Macro invocations can also take anonymous
41 #   macros as operands. Instructions cannot take anonymous macros.
42 #
43 # - Labels must have names that begin with either "_" or ".".  A "." label
44 #   is local and gets renamed before code gen to minimize namespace
45 #   pollution. A "_" label is an extern symbol (i.e. ".globl"). The "_"
46 #   may or may not be removed during code gen depending on whether the asm
47 #   conventions for C name mangling on the target platform mandate a "_"
48 #   prefix.
49 #
50 # - A "macro" is a lambda expression, which may be either anonymous or
51 #   named. But this has caveats. "macro" can take zero or more arguments,
52 #   which may be macros or any valid operands, but it can only return
53 #   code. But you can do Turing-complete things via continuation passing
54 #   style: "macro foo (a, b) b(a) end foo(foo, foo)". Actually, don't do
55 #   that, since you'll just crash the assembler.
56 #
57 # - An "if" is a conditional on settings. Any identifier supplied in the
58 #   predicate of an "if" is assumed to be a #define that is available
59 #   during code gen. So you can't use "if" for computation in a macro, but
60 #   you can use it to select different pieces of code for different
61 #   platforms.
62 #
63 # - Arguments to macros follow lexical scoping rather than dynamic scoping.
64 #   Const's also follow lexical scoping and may override (hide) arguments
65 #   or other consts. All variables (arguments and constants) can be bound
66 #   to operands. Additionally, arguments (but not constants) can be bound
67 #   to macros.
68
69
70 # Below we have a bunch of constant declarations. Each constant must have
71 # a corresponding ASSERT() in LLIntData.cpp.
72
73 # Utilities
74 macro dispatch(advance)
75     addp advance * 4, PC
76     jmp [PC]
77 end
78
79 macro dispatchBranchWithOffset(pcOffset)
80     lshifti 2, pcOffset
81     addp pcOffset, PC
82     jmp [PC]
83 end
84
85 macro dispatchBranch(pcOffset)
86     loadi pcOffset, t0
87     dispatchBranchWithOffset(t0)
88 end
89
90 macro dispatchAfterCall()
91     loadi ArgumentCount + TagOffset[cfr], PC
92     loadi 4[PC], t2
93     storei t1, TagOffset[cfr, t2, 8]
94     storei t0, PayloadOffset[cfr, t2, 8]
95     valueProfile(t1, t0, 4 * (CallOpCodeSize - 1), t3)
96     dispatch(CallOpCodeSize)
97 end
98
99 macro cCall2(function, arg1, arg2)
100     if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS
101         move arg1, a0
102         move arg2, a1
103         call function
104     elsif X86 or X86_WIN
105         subp 8, sp
106         push arg2
107         push arg1
108         call function
109         addp 16, sp
110     elsif SH4
111         setargs arg1, arg2
112         call function
113     elsif C_LOOP
114         cloopCallSlowPath function, arg1, arg2
115     else
116         error
117     end
118 end
119
120 macro cCall2Void(function, arg1, arg2)
121     if C_LOOP
122         cloopCallSlowPathVoid function, arg1, arg2
123     else
124         cCall2(function, arg1, arg2)
125     end
126 end
127
128 # This barely works. arg3 and arg4 should probably be immediates.
129 macro cCall4(function, arg1, arg2, arg3, arg4)
130     if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS
131         move arg1, a0
132         move arg2, a1
133         move arg3, a2
134         move arg4, a3
135         call function
136     elsif X86 or X86_WIN
137         push arg4
138         push arg3
139         push arg2
140         push arg1
141         call function
142         addp 16, sp
143     elsif SH4
144         setargs arg1, arg2, arg3, arg4
145         call function
146     elsif C_LOOP
147         error
148     else
149         error
150     end
151 end
152
153 macro callSlowPath(slowPath)
154     cCall2(slowPath, cfr, PC)
155     move t0, PC
156 end
157
158 macro doVMEntry(makeCall)
159     if X86 or X86_WIN
160         const entry = t4
161         const vm = t3
162         const protoCallFrame = t5
163
164         const temp1 = t0
165         const temp2 = t1
166         const temp3 = t2
167         const temp4 = t3 # same as vm
168     elsif ARM or ARMv7 or ARMv7_TRADITIONAL or C_LOOP
169         const entry = a0
170         const vm = a1
171         const protoCallFrame = a2
172
173         const temp1 = t3
174         const temp2 = t4
175         const temp3 = t5
176         const temp4 = t4 # Same as temp2
177     elsif MIPS
178         const entry = a0
179         const vm = a1
180         const protoCallFrame = a2
181
182         const temp1 = t3
183         const temp2 = t5
184         const temp3 = t4
185         const temp4 = t6
186     elsif SH4
187         const entry = a0
188         const vm = a1
189         const protoCallFrame = a2
190
191         const temp1 = t3
192         const temp2 = a3
193         const temp3 = t8
194         const temp4 = t9
195     end
196
197     functionPrologue()
198     pushCalleeSaves()
199
200     if X86 or X86_WIN
201         loadp 12[cfr], vm
202         loadp 8[cfr], entry
203     end
204
205     if ARMv7
206         vmEntryRecord(cfr, temp1)
207         move temp1, sp
208     else
209         vmEntryRecord(cfr, sp)
210     end
211
212     storep vm, VMEntryRecord::m_vm[sp]
213     loadp VM::topCallFrame[vm], temp2
214     storep temp2, VMEntryRecord::m_prevTopCallFrame[sp]
215     loadp VM::topVMEntryFrame[vm], temp2
216     storep temp2, VMEntryRecord::m_prevTopVMEntryFrame[sp]
217
218     # Align stack pointer
219     if X86_WIN
220         addp CallFrameAlignSlots * SlotSize, sp, temp1
221         andp ~StackAlignmentMask, temp1
222         subp temp1, CallFrameAlignSlots * SlotSize, sp
223     elsif ARM or ARMv7 or ARMv7_TRADITIONAL
224         addp CallFrameAlignSlots * SlotSize, sp, temp1
225         clrbp temp1, StackAlignmentMask, temp1
226         if ARMv7
227             subp temp1, CallFrameAlignSlots * SlotSize, temp1
228             move temp1, sp
229         else
230             subp temp1, CallFrameAlignSlots * SlotSize, sp
231         end
232     end
233
234     if X86 or X86_WIN
235         loadp 16[cfr], protoCallFrame
236     end
237
238     loadi ProtoCallFrame::paddedArgCount[protoCallFrame], temp2
239     addp CallFrameHeaderSlots, temp2, temp2
240     lshiftp 3, temp2
241     subp sp, temp2, temp1
242
243     # Ensure that we have enough additional stack capacity for the incoming args,
244     # and the frame for the JS code we're executing. We need to do this check
245     # before we start copying the args from the protoCallFrame below.
246     bpaeq temp1, VM::m_jsStackLimit[vm], .stackHeightOK
247
248     if C_LOOP
249         move entry, temp2
250         move vm, temp3
251         cloopCallSlowPath _llint_stack_check_at_vm_entry, vm, temp1
252         bpeq t0, 0, .stackCheckFailed
253         move temp2, entry
254         move temp3, vm
255         jmp .stackHeightOK
256
257 .stackCheckFailed:
258         move temp2, entry
259         move temp3, vm
260     end
261
262     cCall2(_llint_throw_stack_overflow_error, vm, protoCallFrame)
263
264     if ARMv7
265         vmEntryRecord(cfr, temp1)
266         move temp1, sp
267     else
268         vmEntryRecord(cfr, sp)
269     end
270
271     loadp VMEntryRecord::m_vm[sp], temp3
272     loadp VMEntryRecord::m_prevTopCallFrame[sp], temp4
273     storep temp4, VM::topCallFrame[temp3]
274     loadp VMEntryRecord::m_prevTopVMEntryFrame[sp], temp4
275     storep temp4, VM::topVMEntryFrame[temp3]
276
277     if ARMv7
278         subp cfr, CalleeRegisterSaveSize, temp3
279         move temp3, sp
280     else
281         subp cfr, CalleeRegisterSaveSize, sp
282     end
283
284     popCalleeSaves()
285     functionEpilogue()
286     ret
287
288 .stackHeightOK:
289     move temp1, sp
290     move 5, temp1
291
292 .copyHeaderLoop:
293     subi 1, temp1
294     loadi TagOffset[protoCallFrame, temp1, 8], temp3
295     storei temp3, TagOffset + CodeBlock[sp, temp1, 8]
296     loadi PayloadOffset[protoCallFrame, temp1, 8], temp3
297     storei temp3, PayloadOffset + CodeBlock[sp, temp1, 8]
298     btinz temp1, .copyHeaderLoop
299
300     loadi PayloadOffset + ProtoCallFrame::argCountAndCodeOriginValue[protoCallFrame], temp2
301     subi 1, temp2
302     loadi ProtoCallFrame::paddedArgCount[protoCallFrame], temp3
303     subi 1, temp3
304
305     bieq temp2, temp3, .copyArgs
306 .fillExtraArgsLoop:
307     subi 1, temp3
308     storei UndefinedTag, ThisArgumentOffset + 8 + TagOffset[sp, temp3, 8]
309     storei 0, ThisArgumentOffset + 8 + PayloadOffset[sp, temp3, 8]
310     bineq temp2, temp3, .fillExtraArgsLoop
311
312 .copyArgs:
313     loadp ProtoCallFrame::args[protoCallFrame], temp1
314
315 .copyArgsLoop:
316     btiz temp2, .copyArgsDone
317     subi 1, temp2
318     loadi TagOffset[temp1, temp2, 8], temp3
319     storei temp3, ThisArgumentOffset + 8 + TagOffset[sp, temp2, 8]
320     loadi PayloadOffset[temp1, temp2, 8], temp3
321     storei temp3, ThisArgumentOffset + 8 + PayloadOffset[sp, temp2, 8]
322     jmp .copyArgsLoop
323
324 .copyArgsDone:
325     storep sp, VM::topCallFrame[vm]
326     storep cfr, VM::topVMEntryFrame[vm]
327
328     makeCall(entry, temp1, temp2)
329
330     if ARMv7
331         vmEntryRecord(cfr, temp1)
332         move temp1, sp
333     else
334         vmEntryRecord(cfr, sp)
335     end
336
337     loadp VMEntryRecord::m_vm[sp], temp3
338     loadp VMEntryRecord::m_prevTopCallFrame[sp], temp4
339     storep temp4, VM::topCallFrame[temp3]
340     loadp VMEntryRecord::m_prevTopVMEntryFrame[sp], temp4
341     storep temp4, VM::topVMEntryFrame[temp3]
342
343     if ARMv7
344         subp cfr, CalleeRegisterSaveSize, temp3
345         move temp3, sp
346     else
347         subp cfr, CalleeRegisterSaveSize, sp
348     end
349
350     popCalleeSaves()
351     functionEpilogue()
352     ret
353 end
354
355 macro makeJavaScriptCall(entry, temp, unused)
356     addp CallerFrameAndPCSize, sp
357     checkStackPointerAlignment(t2, 0xbad0dc02)
358     if C_LOOP
359         cloopCallJSFunction entry
360     else
361         call entry
362     end
363     checkStackPointerAlignment(t2, 0xbad0dc03)
364     subp CallerFrameAndPCSize, sp
365 end
366
367 macro makeHostFunctionCall(entry, temp1, temp2)
368     move entry, temp1
369     storep cfr, [sp]
370     if C_LOOP
371         move sp, a0
372         storep lr, PtrSize[sp]
373         cloopCallNative temp1
374     elsif X86 or X86_WIN
375         # Put callee frame pointer on stack as arg0, also put it in ecx for "fastcall" targets
376         move 0, temp2
377         move temp2, 4[sp] # put 0 in ReturnPC
378         move sp, t2 # t2 is ecx
379         push temp2 # Push dummy arg1
380         push t2
381         call temp1
382         addp 8, sp
383     else
384         move sp, a0
385         call temp1
386     end
387 end
388
389 _handleUncaughtException:
390     loadp ScopeChain + PayloadOffset[cfr], t3
391     andp MarkedBlockMask, t3
392     loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
393     loadp VM::callFrameForThrow[t3], cfr
394
395     loadp CallerFrame + PayloadOffset[cfr], cfr
396
397     if ARMv7
398         vmEntryRecord(cfr, t3)
399         move t3, sp
400     else
401         vmEntryRecord(cfr, sp)
402     end
403
404     loadp VMEntryRecord::m_vm[sp], t3
405     loadp VMEntryRecord::m_prevTopCallFrame[sp], t5
406     storep t5, VM::topCallFrame[t3]
407     loadp VMEntryRecord::m_prevTopVMEntryFrame[sp], t5
408     storep t5, VM::topVMEntryFrame[t3]
409
410     if ARMv7
411         subp cfr, CalleeRegisterSaveSize, t3
412         move t3, sp
413     else
414         subp cfr, CalleeRegisterSaveSize, sp
415     end
416
417     popCalleeSaves()
418     functionEpilogue()
419     ret
420
421 macro doReturnFromHostFunction(extraStackSpace)
422     functionEpilogue(extraStackSpace)
423     ret
424 end
425
426 # Debugging operation if you'd like to print an operand in the instruction stream. fromWhere
427 # should be an immediate integer - any integer you like; use it to identify the place you're
428 # debugging from. operand should likewise be an immediate, and should identify the operand
429 # in the instruction stream you'd like to print out.
430 macro traceOperand(fromWhere, operand)
431     cCall4(_llint_trace_operand, cfr, PC, fromWhere, operand)
432     move t0, PC
433     move t1, cfr
434 end
435
436 # Debugging operation if you'd like to print the value of an operand in the instruction
437 # stream. Same as traceOperand(), but assumes that the operand is a register, and prints its
438 # value.
439 macro traceValue(fromWhere, operand)
440     cCall4(_llint_trace_value, cfr, PC, fromWhere, operand)
441     move t0, PC
442     move t1, cfr
443 end
444
445 # Call a slowPath for call opcodes.
446 macro callCallSlowPath(slowPath, action)
447     storep PC, ArgumentCount + TagOffset[cfr]
448     cCall2(slowPath, cfr, PC)
449     action(t0)
450 end
451
452 macro callWatchdogTimerHandler(throwHandler)
453     storei PC, ArgumentCount + TagOffset[cfr]
454     cCall2(_llint_slow_path_handle_watchdog_timer, cfr, PC)
455     btpnz t0, throwHandler
456     loadi ArgumentCount + TagOffset[cfr], PC
457 end
458
459 macro checkSwitchToJITForLoop()
460     checkSwitchToJIT(
461         1,
462         macro ()
463             storei PC, ArgumentCount + TagOffset[cfr]
464             cCall2(_llint_loop_osr, cfr, PC)
465             btpz t0, .recover
466             move t1, sp
467             jmp t0
468         .recover:
469             loadi ArgumentCount + TagOffset[cfr], PC
470         end)
471 end
472
473 macro loadVariable(operand, index, tag, payload)
474     loadisFromInstruction(operand, index)
475     loadi TagOffset[cfr, index, 8], tag
476     loadi PayloadOffset[cfr, index, 8], payload
477 end
478
479 # Index, tag, and payload must be different registers. Index is not
480 # changed.
481 macro loadConstantOrVariable(index, tag, payload)
482     bigteq index, FirstConstantRegisterIndex, .constant
483     loadi TagOffset[cfr, index, 8], tag
484     loadi PayloadOffset[cfr, index, 8], payload
485     jmp .done
486 .constant:
487     loadp CodeBlock[cfr], payload
488     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload
489     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
490     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
491     loadp TagOffset[payload, index, 8], tag
492     loadp PayloadOffset[payload, index, 8], payload
493 .done:
494 end
495
496 macro loadConstantOrVariableTag(index, tag)
497     bigteq index, FirstConstantRegisterIndex, .constant
498     loadi TagOffset[cfr, index, 8], tag
499     jmp .done
500 .constant:
501     loadp CodeBlock[cfr], tag
502     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[tag], tag
503     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
504     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
505     loadp TagOffset[tag, index, 8], tag
506 .done:
507 end
508
509 # Index and payload may be the same register. Index may be clobbered.
510 macro loadConstantOrVariable2Reg(index, tag, payload)
511     bigteq index, FirstConstantRegisterIndex, .constant
512     loadi TagOffset[cfr, index, 8], tag
513     loadi PayloadOffset[cfr, index, 8], payload
514     jmp .done
515 .constant:
516     loadp CodeBlock[cfr], tag
517     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[tag], tag
518     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
519     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
520     lshifti 3, index
521     addp index, tag
522     loadp PayloadOffset[tag], payload
523     loadp TagOffset[tag], tag
524 .done:
525 end
526
527 macro loadConstantOrVariablePayloadTagCustom(index, tagCheck, payload)
528     bigteq index, FirstConstantRegisterIndex, .constant
529     tagCheck(TagOffset[cfr, index, 8])
530     loadi PayloadOffset[cfr, index, 8], payload
531     jmp .done
532 .constant:
533     loadp CodeBlock[cfr], payload
534     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload
535     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
536     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
537     tagCheck(TagOffset[payload, index, 8])
538     loadp PayloadOffset[payload, index, 8], payload
539 .done:
540 end
541
542 # Index and payload must be different registers. Index is not mutated. Use
543 # this if you know what the tag of the variable should be. Doing the tag
544 # test as part of loading the variable reduces register use, but may not
545 # be faster than doing loadConstantOrVariable followed by a branch on the
546 # tag.
547 macro loadConstantOrVariablePayload(index, expectedTag, payload, slow)
548     loadConstantOrVariablePayloadTagCustom(
549         index,
550         macro (actualTag) bineq actualTag, expectedTag, slow end,
551         payload)
552 end
553
554 macro loadConstantOrVariablePayloadUnchecked(index, payload)
555     loadConstantOrVariablePayloadTagCustom(
556         index,
557         macro (actualTag) end,
558         payload)
559 end
560
561 macro storeStructureWithTypeInfo(cell, structure, scratch)
562     storep structure, JSCell::m_structureID[cell]
563
564     loadi Structure::m_blob + StructureIDBlob::u.words.word2[structure], scratch
565     storei scratch, JSCell::m_indexingType[cell]
566 end
567
568 macro writeBarrierOnOperand(cellOperand)
569     if GGC
570         loadisFromInstruction(cellOperand, t1)
571         loadConstantOrVariablePayload(t1, CellTag, t2, .writeBarrierDone)
572         checkMarkByte(t2, t1, t3, 
573             macro(gcData)
574                 btbnz gcData, .writeBarrierDone
575                 push cfr, PC
576                 # We make two extra slots because cCall2 will poke.
577                 subp 8, sp
578                 cCall2Void(_llint_write_barrier_slow, cfr, t2)
579                 addp 8, sp
580                 pop PC, cfr
581             end
582         )
583     .writeBarrierDone:
584     end
585 end
586
587 macro writeBarrierOnOperands(cellOperand, valueOperand)
588     if GGC
589         loadisFromInstruction(valueOperand, t1)
590         loadConstantOrVariableTag(t1, t0)
591         bineq t0, CellTag, .writeBarrierDone
592     
593         writeBarrierOnOperand(cellOperand)
594     .writeBarrierDone:
595     end
596 end
597
598 macro writeBarrierOnGlobalObject(valueOperand)
599     if GGC
600         loadisFromInstruction(valueOperand, t1)
601         loadConstantOrVariableTag(t1, t0)
602         bineq t0, CellTag, .writeBarrierDone
603     
604         loadp CodeBlock[cfr], t3
605         loadp CodeBlock::m_globalObject[t3], t3
606         checkMarkByte(t3, t1, t2,
607             macro(gcData)
608                 btbnz gcData, .writeBarrierDone
609                 push cfr, PC
610                 # We make two extra slots because cCall2 will poke.
611                 subp 8, sp
612                 cCall2Void(_llint_write_barrier_slow, cfr, t3)
613                 addp 8, sp
614                 pop PC, cfr
615             end
616         )
617     .writeBarrierDone:
618     end
619 end
620
621 macro valueProfile(tag, payload, operand, scratch)
622     loadp operand[PC], scratch
623     storei tag, ValueProfile::m_buckets + TagOffset[scratch]
624     storei payload, ValueProfile::m_buckets + PayloadOffset[scratch]
625 end
626
627
628 # Entrypoints into the interpreter
629
630 # Expects that CodeBlock is in t1, which is what prologue() leaves behind.
631 macro functionArityCheck(doneLabel, slowPath)
632     loadi PayloadOffset + ArgumentCount[cfr], t0
633     biaeq t0, CodeBlock::m_numParameters[t1], doneLabel
634     cCall2(slowPath, cfr, PC)   # This slowPath has a simple protocol: t0 = 0 => no error, t0 != 0 => error
635     btiz t0, .noError
636     move t1, cfr   # t1 contains caller frame
637     jmp _llint_throw_from_slow_path_trampoline
638
639 .noError:
640     # t1 points to ArityCheckData.
641     loadp CommonSlowPaths::ArityCheckData::thunkToCall[t1], t2
642     btpz t2, .proceedInline
643     
644     loadp CommonSlowPaths::ArityCheckData::returnPC[t1], t5
645     loadp CommonSlowPaths::ArityCheckData::paddedStackSpace[t1], t0
646     call t2
647     if ASSERT_ENABLED
648         loadp ReturnPC[cfr], t0
649         loadp [t0], t0
650     end
651     jmp .continue
652
653 .proceedInline:
654     loadi CommonSlowPaths::ArityCheckData::paddedStackSpace[t1], t1
655     btiz t1, .continue
656
657     // Move frame up "t1 * 2" slots
658     lshiftp 1, t1
659     negi t1
660     move cfr, t3
661     loadi PayloadOffset + ArgumentCount[cfr], t2
662     addi CallFrameHeaderSlots, t2
663 .copyLoop:
664     loadi PayloadOffset[t3], t0
665     storei t0, PayloadOffset[t3, t1, 8]
666     loadi TagOffset[t3], t0
667     storei t0, TagOffset[t3, t1, 8]
668     addp 8, t3
669     bsubinz 1, t2, .copyLoop
670
671     // Fill new slots with JSUndefined
672     move t1, t2
673 .fillLoop:
674     move 0, t0
675     storei t0, PayloadOffset[t3, t1, 8]
676     move UndefinedTag, t0
677     storei t0, TagOffset[t3, t1, 8]
678     addp 8, t3
679     baddinz 1, t2, .fillLoop
680
681     lshiftp 3, t1
682     addp t1, cfr
683     addp t1, sp
684 .continue:
685     # Reload CodeBlock and PC, since the slow_path clobbered it.
686     loadp CodeBlock[cfr], t1
687     loadp CodeBlock::m_instructions[t1], PC
688     jmp doneLabel
689 end
690
691 macro branchIfException(label)
692     loadp ScopeChain[cfr], t3
693     andp MarkedBlockMask, t3
694     loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
695     bieq VM::m_exception + TagOffset[t3], EmptyValueTag, .noException
696     jmp label
697 .noException:
698 end
699
700
701 # Instruction implementations
702
703 _llint_op_enter:
704     traceExecution()
705     checkStackPointerAlignment(t2, 0xdead00e1)
706     loadp CodeBlock[cfr], t2                // t2<CodeBlock> = cfr.CodeBlock
707     loadi CodeBlock::m_numVars[t2], t2      // t2<size_t> = t2<CodeBlock>.m_numVars
708     btiz t2, .opEnterDone
709     move UndefinedTag, t0
710     move 0, t1
711     negi t2
712 .opEnterLoop:
713     storei t0, TagOffset[cfr, t2, 8]
714     storei t1, PayloadOffset[cfr, t2, 8]
715     addi 1, t2
716     btinz t2, .opEnterLoop
717 .opEnterDone:
718     callSlowPath(_slow_path_enter)
719     dispatch(1)
720
721
722 _llint_op_create_lexical_environment:
723     traceExecution()
724     loadi 4[PC], t0
725     callSlowPath(_llint_slow_path_create_lexical_environment)
726     dispatch(2)
727
728
729 _llint_op_init_lazy_reg:
730     traceExecution()
731     loadi 4[PC], t0
732     storei EmptyValueTag, TagOffset[cfr, t0, 8]
733     storei 0, PayloadOffset[cfr, t0, 8]
734     dispatch(2)
735
736
737 _llint_op_create_arguments:
738     traceExecution()
739     loadi 4[PC], t0
740     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateArgumentsDone
741     callSlowPath(_slow_path_create_arguments)
742 .opCreateArgumentsDone:
743     dispatch(2)
744
745
746 _llint_op_create_this:
747     traceExecution()
748     loadi 8[PC], t0
749     loadp PayloadOffset[cfr, t0, 8], t0
750     loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_allocator[t0], t1
751     loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_structure[t0], t2
752     btpz t1, .opCreateThisSlow
753     allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
754     loadi 4[PC], t1
755     storei CellTag, TagOffset[cfr, t1, 8]
756     storei t0, PayloadOffset[cfr, t1, 8]
757     dispatch(4)
758
759 .opCreateThisSlow:
760     callSlowPath(_slow_path_create_this)
761     dispatch(4)
762
763
764 _llint_op_get_callee:
765     traceExecution()
766     loadi 4[PC], t0
767     loadp PayloadOffset + Callee[cfr], t1
768     loadpFromInstruction(2, t2)
769     bpneq t1, t2, .opGetCalleeSlow
770     storei CellTag, TagOffset[cfr, t0, 8]
771     storei t1, PayloadOffset[cfr, t0, 8]
772     dispatch(3)
773
774 .opGetCalleeSlow:
775     callSlowPath(_slow_path_get_callee)
776     dispatch(3)
777
778 _llint_op_to_this:
779     traceExecution()
780     loadi 4[PC], t0
781     bineq TagOffset[cfr, t0, 8], CellTag, .opToThisSlow
782     loadi PayloadOffset[cfr, t0, 8], t0
783     bbneq JSCell::m_type[t0], FinalObjectType, .opToThisSlow
784     loadpFromInstruction(2, t2)
785     bpneq JSCell::m_structureID[t0], t2, .opToThisSlow
786     dispatch(4)
787
788 .opToThisSlow:
789     callSlowPath(_slow_path_to_this)
790     dispatch(4)
791
792
793 _llint_op_new_object:
794     traceExecution()
795     loadpFromInstruction(3, t0)
796     loadp ObjectAllocationProfile::m_allocator[t0], t1
797     loadp ObjectAllocationProfile::m_structure[t0], t2
798     allocateJSObject(t1, t2, t0, t3, .opNewObjectSlow)
799     loadi 4[PC], t1
800     storei CellTag, TagOffset[cfr, t1, 8]
801     storei t0, PayloadOffset[cfr, t1, 8]
802     dispatch(4)
803
804 .opNewObjectSlow:
805     callSlowPath(_llint_slow_path_new_object)
806     dispatch(4)
807
808
809 _llint_op_mov:
810     traceExecution()
811     loadi 8[PC], t1
812     loadi 4[PC], t0
813     loadConstantOrVariable(t1, t2, t3)
814     storei t2, TagOffset[cfr, t0, 8]
815     storei t3, PayloadOffset[cfr, t0, 8]
816     dispatch(3)
817
818
819 macro notifyWrite(set, valueTag, valuePayload, scratch, slow)
820     loadb VariableWatchpointSet::m_state[set], scratch
821     bieq scratch, IsInvalidated, .done
822     bineq valuePayload, VariableWatchpointSet::m_inferredValue + PayloadOffset[set], slow
823     bineq valueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set], slow
824 .done:
825 end
826
827 _llint_op_captured_mov:
828     traceExecution()
829     loadi 8[PC], t1
830     loadConstantOrVariable(t1, t2, t3)
831     loadpFromInstruction(3, t0)
832     btpz t0, .opCapturedMovReady
833     notifyWrite(t0, t2, t3, t1, .opCapturedMovSlow)
834 .opCapturedMovReady:
835     loadi 4[PC], t0
836     storei t2, TagOffset[cfr, t0, 8]
837     storei t3, PayloadOffset[cfr, t0, 8]
838     dispatch(4)
839
840 .opCapturedMovSlow:
841     callSlowPath(_slow_path_captured_mov)
842     dispatch(4)
843
844
845 _llint_op_not:
846     traceExecution()
847     loadi 8[PC], t0
848     loadi 4[PC], t1
849     loadConstantOrVariable(t0, t2, t3)
850     bineq t2, BooleanTag, .opNotSlow
851     xori 1, t3
852     storei t2, TagOffset[cfr, t1, 8]
853     storei t3, PayloadOffset[cfr, t1, 8]
854     dispatch(3)
855
856 .opNotSlow:
857     callSlowPath(_slow_path_not)
858     dispatch(3)
859
860
861 _llint_op_eq:
862     traceExecution()
863     loadi 12[PC], t2
864     loadi 8[PC], t0
865     loadConstantOrVariable(t2, t3, t1)
866     loadConstantOrVariable2Reg(t0, t2, t0)
867     bineq t2, t3, .opEqSlow
868     bieq t2, CellTag, .opEqSlow
869     bib t2, LowestTag, .opEqSlow
870     loadi 4[PC], t2
871     cieq t0, t1, t0
872     storei BooleanTag, TagOffset[cfr, t2, 8]
873     storei t0, PayloadOffset[cfr, t2, 8]
874     dispatch(4)
875
876 .opEqSlow:
877     callSlowPath(_slow_path_eq)
878     dispatch(4)
879
880
881 _llint_op_eq_null:
882     traceExecution()
883     loadi 8[PC], t0
884     loadi 4[PC], t3
885     assertNotConstant(t0)
886     loadi TagOffset[cfr, t0, 8], t1
887     loadi PayloadOffset[cfr, t0, 8], t0
888     bineq t1, CellTag, .opEqNullImmediate
889     btbnz JSCell::m_flags[t0], MasqueradesAsUndefined, .opEqNullMasqueradesAsUndefined
890     move 0, t1
891     jmp .opEqNullNotImmediate
892 .opEqNullMasqueradesAsUndefined:
893     loadp JSCell::m_structureID[t0], t1
894     loadp CodeBlock[cfr], t0
895     loadp CodeBlock::m_globalObject[t0], t0
896     cpeq Structure::m_globalObject[t1], t0, t1
897     jmp .opEqNullNotImmediate
898 .opEqNullImmediate:
899     cieq t1, NullTag, t2
900     cieq t1, UndefinedTag, t1
901     ori t2, t1
902 .opEqNullNotImmediate:
903     storei BooleanTag, TagOffset[cfr, t3, 8]
904     storei t1, PayloadOffset[cfr, t3, 8]
905     dispatch(3)
906
907
908 _llint_op_neq:
909     traceExecution()
910     loadi 12[PC], t2
911     loadi 8[PC], t0
912     loadConstantOrVariable(t2, t3, t1)
913     loadConstantOrVariable2Reg(t0, t2, t0)
914     bineq t2, t3, .opNeqSlow
915     bieq t2, CellTag, .opNeqSlow
916     bib t2, LowestTag, .opNeqSlow
917     loadi 4[PC], t2
918     cineq t0, t1, t0
919     storei BooleanTag, TagOffset[cfr, t2, 8]
920     storei t0, PayloadOffset[cfr, t2, 8]
921     dispatch(4)
922
923 .opNeqSlow:
924     callSlowPath(_slow_path_neq)
925     dispatch(4)
926     
927
928 _llint_op_neq_null:
929     traceExecution()
930     loadi 8[PC], t0
931     loadi 4[PC], t3
932     assertNotConstant(t0)
933     loadi TagOffset[cfr, t0, 8], t1
934     loadi PayloadOffset[cfr, t0, 8], t0
935     bineq t1, CellTag, .opNeqNullImmediate
936     btbnz JSCell::m_flags[t0], MasqueradesAsUndefined, .opNeqNullMasqueradesAsUndefined
937     move 1, t1
938     jmp .opNeqNullNotImmediate
939 .opNeqNullMasqueradesAsUndefined:
940     loadp JSCell::m_structureID[t0], t1
941     loadp CodeBlock[cfr], t0
942     loadp CodeBlock::m_globalObject[t0], t0
943     cpneq Structure::m_globalObject[t1], t0, t1
944     jmp .opNeqNullNotImmediate
945 .opNeqNullImmediate:
946     cineq t1, NullTag, t2
947     cineq t1, UndefinedTag, t1
948     andi t2, t1
949 .opNeqNullNotImmediate:
950     storei BooleanTag, TagOffset[cfr, t3, 8]
951     storei t1, PayloadOffset[cfr, t3, 8]
952     dispatch(3)
953
954
955 macro strictEq(equalityOperation, slowPath)
956     loadi 12[PC], t2
957     loadi 8[PC], t0
958     loadConstantOrVariable(t2, t3, t1)
959     loadConstantOrVariable2Reg(t0, t2, t0)
960     bineq t2, t3, .slow
961     bib t2, LowestTag, .slow
962     bineq t2, CellTag, .notString
963     bbneq JSCell::m_type[t0], StringType, .notString
964     bbeq JSCell::m_type[t1], StringType, .slow
965 .notString:
966     loadi 4[PC], t2
967     equalityOperation(t0, t1, t0)
968     storei BooleanTag, TagOffset[cfr, t2, 8]
969     storei t0, PayloadOffset[cfr, t2, 8]
970     dispatch(4)
971
972 .slow:
973     callSlowPath(slowPath)
974     dispatch(4)
975 end
976
977 _llint_op_stricteq:
978     traceExecution()
979     strictEq(macro (left, right, result) cieq left, right, result end, _slow_path_stricteq)
980
981
982 _llint_op_nstricteq:
983     traceExecution()
984     strictEq(macro (left, right, result) cineq left, right, result end, _slow_path_nstricteq)
985
986
987 _llint_op_inc:
988     traceExecution()
989     loadi 4[PC], t0
990     bineq TagOffset[cfr, t0, 8], Int32Tag, .opIncSlow
991     loadi PayloadOffset[cfr, t0, 8], t1
992     baddio 1, t1, .opIncSlow
993     storei t1, PayloadOffset[cfr, t0, 8]
994     dispatch(2)
995
996 .opIncSlow:
997     callSlowPath(_slow_path_inc)
998     dispatch(2)
999
1000
1001 _llint_op_dec:
1002     traceExecution()
1003     loadi 4[PC], t0
1004     bineq TagOffset[cfr, t0, 8], Int32Tag, .opDecSlow
1005     loadi PayloadOffset[cfr, t0, 8], t1
1006     bsubio 1, t1, .opDecSlow
1007     storei t1, PayloadOffset[cfr, t0, 8]
1008     dispatch(2)
1009
1010 .opDecSlow:
1011     callSlowPath(_slow_path_dec)
1012     dispatch(2)
1013
1014
1015 _llint_op_to_number:
1016     traceExecution()
1017     loadi 8[PC], t0
1018     loadi 4[PC], t1
1019     loadConstantOrVariable(t0, t2, t3)
1020     bieq t2, Int32Tag, .opToNumberIsInt
1021     biaeq t2, LowestTag, .opToNumberSlow
1022 .opToNumberIsInt:
1023     storei t2, TagOffset[cfr, t1, 8]
1024     storei t3, PayloadOffset[cfr, t1, 8]
1025     dispatch(3)
1026
1027 .opToNumberSlow:
1028     callSlowPath(_slow_path_to_number)
1029     dispatch(3)
1030
1031
1032 _llint_op_negate:
1033     traceExecution()
1034     loadi 8[PC], t0
1035     loadi 4[PC], t3
1036     loadConstantOrVariable(t0, t1, t2)
1037     bineq t1, Int32Tag, .opNegateSrcNotInt
1038     btiz t2, 0x7fffffff, .opNegateSlow
1039     negi t2
1040     storei Int32Tag, TagOffset[cfr, t3, 8]
1041     storei t2, PayloadOffset[cfr, t3, 8]
1042     dispatch(3)
1043 .opNegateSrcNotInt:
1044     bia t1, LowestTag, .opNegateSlow
1045     xori 0x80000000, t1
1046     storei t1, TagOffset[cfr, t3, 8]
1047     storei t2, PayloadOffset[cfr, t3, 8]
1048     dispatch(3)
1049
1050 .opNegateSlow:
1051     callSlowPath(_slow_path_negate)
1052     dispatch(3)
1053
1054
1055 macro binaryOpCustomStore(integerOperationAndStore, doubleOperation, slowPath)
1056     loadi 12[PC], t2
1057     loadi 8[PC], t0
1058     loadConstantOrVariable(t2, t3, t1)
1059     loadConstantOrVariable2Reg(t0, t2, t0)
1060     bineq t2, Int32Tag, .op1NotInt
1061     bineq t3, Int32Tag, .op2NotInt
1062     loadi 4[PC], t2
1063     integerOperationAndStore(t3, t1, t0, .slow, t2)
1064     dispatch(5)
1065
1066 .op1NotInt:
1067     # First operand is definitely not an int, the second operand could be anything.
1068     bia t2, LowestTag, .slow
1069     bib t3, LowestTag, .op1NotIntOp2Double
1070     bineq t3, Int32Tag, .slow
1071     ci2d t1, ft1
1072     jmp .op1NotIntReady
1073 .op1NotIntOp2Double:
1074     fii2d t1, t3, ft1
1075 .op1NotIntReady:
1076     loadi 4[PC], t1
1077     fii2d t0, t2, ft0
1078     doubleOperation(ft1, ft0)
1079     stored ft0, [cfr, t1, 8]
1080     dispatch(5)
1081
1082 .op2NotInt:
1083     # First operand is definitely an int, the second operand is definitely not.
1084     loadi 4[PC], t2
1085     bia t3, LowestTag, .slow
1086     ci2d t0, ft0
1087     fii2d t1, t3, ft1
1088     doubleOperation(ft1, ft0)
1089     stored ft0, [cfr, t2, 8]
1090     dispatch(5)
1091
1092 .slow:
1093     callSlowPath(slowPath)
1094     dispatch(5)
1095 end
1096
1097 macro binaryOp(integerOperation, doubleOperation, slowPath)
1098     binaryOpCustomStore(
1099         macro (int32Tag, left, right, slow, index)
1100             integerOperation(left, right, slow)
1101             storei int32Tag, TagOffset[cfr, index, 8]
1102             storei right, PayloadOffset[cfr, index, 8]
1103         end,
1104         doubleOperation, slowPath)
1105 end
1106
1107 _llint_op_add:
1108     traceExecution()
1109     binaryOp(
1110         macro (left, right, slow) baddio left, right, slow end,
1111         macro (left, right) addd left, right end,
1112         _slow_path_add)
1113
1114
1115 _llint_op_mul:
1116     traceExecution()
1117     binaryOpCustomStore(
1118         macro (int32Tag, left, right, slow, index)
1119             const scratch = int32Tag   # We know that we can reuse the int32Tag register since it has a constant.
1120             move right, scratch
1121             bmulio left, scratch, slow
1122             btinz scratch, .done
1123             bilt left, 0, slow
1124             bilt right, 0, slow
1125         .done:
1126             storei Int32Tag, TagOffset[cfr, index, 8]
1127             storei scratch, PayloadOffset[cfr, index, 8]
1128         end,
1129         macro (left, right) muld left, right end,
1130         _slow_path_mul)
1131
1132
1133 _llint_op_sub:
1134     traceExecution()
1135     binaryOp(
1136         macro (left, right, slow) bsubio left, right, slow end,
1137         macro (left, right) subd left, right end,
1138         _slow_path_sub)
1139
1140
1141 _llint_op_div:
1142     traceExecution()
1143     binaryOpCustomStore(
1144         macro (int32Tag, left, right, slow, index)
1145             ci2d left, ft0
1146             ci2d right, ft1
1147             divd ft0, ft1
1148             bcd2i ft1, right, .notInt
1149             storei int32Tag, TagOffset[cfr, index, 8]
1150             storei right, PayloadOffset[cfr, index, 8]
1151             jmp .done
1152         .notInt:
1153             stored ft1, [cfr, index, 8]
1154         .done:
1155         end,
1156         macro (left, right) divd left, right end,
1157         _slow_path_div)
1158
1159
1160 macro bitOp(operation, slowPath, advance)
1161     loadi 12[PC], t2
1162     loadi 8[PC], t0
1163     loadConstantOrVariable(t2, t3, t1)
1164     loadConstantOrVariable2Reg(t0, t2, t0)
1165     bineq t3, Int32Tag, .slow
1166     bineq t2, Int32Tag, .slow
1167     loadi 4[PC], t2
1168     operation(t1, t0)
1169     storei t3, TagOffset[cfr, t2, 8]
1170     storei t0, PayloadOffset[cfr, t2, 8]
1171     dispatch(advance)
1172
1173 .slow:
1174     callSlowPath(slowPath)
1175     dispatch(advance)
1176 end
1177
1178 _llint_op_lshift:
1179     traceExecution()
1180     bitOp(
1181         macro (left, right) lshifti left, right end,
1182         _slow_path_lshift,
1183         4)
1184
1185
1186 _llint_op_rshift:
1187     traceExecution()
1188     bitOp(
1189         macro (left, right) rshifti left, right end,
1190         _slow_path_rshift,
1191         4)
1192
1193
1194 _llint_op_urshift:
1195     traceExecution()
1196     bitOp(
1197         macro (left, right) urshifti left, right end,
1198         _slow_path_urshift,
1199         4)
1200
1201
1202 _llint_op_unsigned:
1203     traceExecution()
1204     loadi 4[PC], t0
1205     loadi 8[PC], t1
1206     loadConstantOrVariablePayload(t1, Int32Tag, t2, .opUnsignedSlow)
1207     bilt t2, 0, .opUnsignedSlow
1208     storei t2, PayloadOffset[cfr, t0, 8]
1209     storei Int32Tag, TagOffset[cfr, t0, 8]
1210     dispatch(3)
1211 .opUnsignedSlow:
1212     callSlowPath(_slow_path_unsigned)
1213     dispatch(3)
1214
1215
1216 _llint_op_bitand:
1217     traceExecution()
1218     bitOp(
1219         macro (left, right) andi left, right end,
1220         _slow_path_bitand,
1221         5)
1222
1223
1224 _llint_op_bitxor:
1225     traceExecution()
1226     bitOp(
1227         macro (left, right) xori left, right end,
1228         _slow_path_bitxor,
1229         5)
1230
1231
1232 _llint_op_bitor:
1233     traceExecution()
1234     bitOp(
1235         macro (left, right) ori left, right end,
1236         _slow_path_bitor,
1237         5)
1238
1239
1240 _llint_op_check_has_instance:
1241     traceExecution()
1242     loadi 12[PC], t1
1243     loadConstantOrVariablePayload(t1, CellTag, t0, .opCheckHasInstanceSlow)
1244     btbz JSCell::m_flags[t0], ImplementsDefaultHasInstance, .opCheckHasInstanceSlow
1245     dispatch(5)
1246
1247 .opCheckHasInstanceSlow:
1248     callSlowPath(_llint_slow_path_check_has_instance)
1249     dispatch(0)
1250
1251
1252 _llint_op_instanceof:
1253     traceExecution()
1254     # Actually do the work.
1255     loadi 12[PC], t0
1256     loadi 4[PC], t3
1257     loadConstantOrVariablePayload(t0, CellTag, t1, .opInstanceofSlow)
1258     bbb JSCell::m_type[t1], ObjectType, .opInstanceofSlow
1259     loadi 8[PC], t0
1260     loadConstantOrVariablePayload(t0, CellTag, t2, .opInstanceofSlow)
1261     
1262     # Register state: t1 = prototype, t2 = value
1263     move 1, t0
1264 .opInstanceofLoop:
1265     loadp JSCell::m_structureID[t2], t2
1266     loadi Structure::m_prototype + PayloadOffset[t2], t2
1267     bpeq t2, t1, .opInstanceofDone
1268     btinz t2, .opInstanceofLoop
1269
1270     move 0, t0
1271 .opInstanceofDone:
1272     storei BooleanTag, TagOffset[cfr, t3, 8]
1273     storei t0, PayloadOffset[cfr, t3, 8]
1274     dispatch(4)
1275
1276 .opInstanceofSlow:
1277     callSlowPath(_llint_slow_path_instanceof)
1278     dispatch(4)
1279
1280
1281 _llint_op_is_undefined:
1282     traceExecution()
1283     loadi 8[PC], t1
1284     loadi 4[PC], t0
1285     loadConstantOrVariable(t1, t2, t3)
1286     storei BooleanTag, TagOffset[cfr, t0, 8]
1287     bieq t2, CellTag, .opIsUndefinedCell
1288     cieq t2, UndefinedTag, t3
1289     storei t3, PayloadOffset[cfr, t0, 8]
1290     dispatch(3)
1291 .opIsUndefinedCell:
1292     btbnz JSCell::m_flags[t3], MasqueradesAsUndefined, .opIsUndefinedMasqueradesAsUndefined
1293     move 0, t1
1294     storei t1, PayloadOffset[cfr, t0, 8]
1295     dispatch(3)
1296 .opIsUndefinedMasqueradesAsUndefined:
1297     loadp JSCell::m_structureID[t3], t1
1298     loadp CodeBlock[cfr], t3
1299     loadp CodeBlock::m_globalObject[t3], t3
1300     cpeq Structure::m_globalObject[t1], t3, t1
1301     storei t1, PayloadOffset[cfr, t0, 8]
1302     dispatch(3)
1303
1304
1305 _llint_op_is_boolean:
1306     traceExecution()
1307     loadi 8[PC], t1
1308     loadi 4[PC], t2
1309     loadConstantOrVariableTag(t1, t0)
1310     cieq t0, BooleanTag, t0
1311     storei BooleanTag, TagOffset[cfr, t2, 8]
1312     storei t0, PayloadOffset[cfr, t2, 8]
1313     dispatch(3)
1314
1315
1316 _llint_op_is_number:
1317     traceExecution()
1318     loadi 8[PC], t1
1319     loadi 4[PC], t2
1320     loadConstantOrVariableTag(t1, t0)
1321     storei BooleanTag, TagOffset[cfr, t2, 8]
1322     addi 1, t0
1323     cib t0, LowestTag + 1, t1
1324     storei t1, PayloadOffset[cfr, t2, 8]
1325     dispatch(3)
1326
1327
1328 _llint_op_is_string:
1329     traceExecution()
1330     loadi 8[PC], t1
1331     loadi 4[PC], t2
1332     loadConstantOrVariable(t1, t0, t3)
1333     storei BooleanTag, TagOffset[cfr, t2, 8]
1334     bineq t0, CellTag, .opIsStringNotCell
1335     cbeq JSCell::m_type[t3], StringType, t1
1336     storei t1, PayloadOffset[cfr, t2, 8]
1337     dispatch(3)
1338 .opIsStringNotCell:
1339     storep 0, PayloadOffset[cfr, t2, 8]
1340     dispatch(3)
1341
1342
1343 macro loadPropertyAtVariableOffsetKnownNotInline(propertyOffset, objectAndStorage, tag, payload)
1344     assert(macro (ok) bigteq propertyOffset, firstOutOfLineOffset, ok end)
1345     negi propertyOffset
1346     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
1347     loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag
1348     loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload
1349 end
1350
1351 macro loadPropertyAtVariableOffset(propertyOffset, objectAndStorage, tag, payload)
1352     bilt propertyOffset, firstOutOfLineOffset, .isInline
1353     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
1354     negi propertyOffset
1355     jmp .ready
1356 .isInline:
1357     addp sizeof JSObject - (firstOutOfLineOffset - 2) * 8, objectAndStorage
1358 .ready:
1359     loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag
1360     loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload
1361 end
1362
1363 macro storePropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, tag, payload)
1364     bilt propertyOffsetAsInt, firstOutOfLineOffset, .isInline
1365     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
1366     negi propertyOffsetAsInt
1367     jmp .ready
1368 .isInline:
1369     addp sizeof JSObject - (firstOutOfLineOffset - 2) * 8, objectAndStorage
1370 .ready:
1371     storei tag, TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8]
1372     storei payload, PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8]
1373 end
1374
1375
1376 _llint_op_init_global_const:
1377     traceExecution()
1378     writeBarrierOnGlobalObject(2)
1379     loadi 8[PC], t1
1380     loadi 4[PC], t0
1381     loadConstantOrVariable(t1, t2, t3)
1382     storei t2, TagOffset[t0]
1383     storei t3, PayloadOffset[t0]
1384     dispatch(5)
1385
1386
1387 # We only do monomorphic get_by_id caching for now, and we do not modify the
1388 # opcode. We do, however, allow for the cache to change anytime if fails, since
1389 # ping-ponging is free. At best we get lucky and the get_by_id will continue
1390 # to take fast path on the new cache. At worst we take slow path, which is what
1391 # we would have been doing anyway.
1392
1393 macro getById(getPropertyStorage)
1394     traceExecution()
1395     loadi 8[PC], t0
1396     loadi 16[PC], t1
1397     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow)
1398     loadi 20[PC], t2
1399     getPropertyStorage(
1400         t3,
1401         t0,
1402         macro (propertyStorage, scratch)
1403             bpneq JSCell::m_structureID[t3], t1, .opGetByIdSlow
1404             loadi 4[PC], t1
1405             loadi TagOffset[propertyStorage, t2], scratch
1406             loadi PayloadOffset[propertyStorage, t2], t2
1407             storei scratch, TagOffset[cfr, t1, 8]
1408             storei t2, PayloadOffset[cfr, t1, 8]
1409             valueProfile(scratch, t2, 32, t1)
1410             dispatch(9)
1411         end)
1412
1413     .opGetByIdSlow:
1414         callSlowPath(_llint_slow_path_get_by_id)
1415         dispatch(9)
1416 end
1417
1418 _llint_op_get_by_id:
1419     getById(withInlineStorage)
1420
1421
1422 _llint_op_get_by_id_out_of_line:
1423     getById(withOutOfLineStorage)
1424
1425
1426 _llint_op_get_array_length:
1427     traceExecution()
1428     loadi 8[PC], t0
1429     loadp 16[PC], t1
1430     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetArrayLengthSlow)
1431     move t3, t2
1432     arrayProfile(t2, t1, t0)
1433     btiz t2, IsArray, .opGetArrayLengthSlow
1434     btiz t2, IndexingShapeMask, .opGetArrayLengthSlow
1435     loadi 4[PC], t1
1436     loadp JSObject::m_butterfly[t3], t0
1437     loadi -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], t0
1438     bilt t0, 0, .opGetArrayLengthSlow
1439     valueProfile(Int32Tag, t0, 32, t2)
1440     storep t0, PayloadOffset[cfr, t1, 8]
1441     storep Int32Tag, TagOffset[cfr, t1, 8]
1442     dispatch(9)
1443
1444 .opGetArrayLengthSlow:
1445     callSlowPath(_llint_slow_path_get_by_id)
1446     dispatch(9)
1447
1448
1449 _llint_op_get_arguments_length:
1450     traceExecution()
1451     loadi 8[PC], t0
1452     loadi 4[PC], t1
1453     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentsLengthSlow
1454     loadi ArgumentCount + PayloadOffset[cfr], t2
1455     subi 1, t2
1456     storei Int32Tag, TagOffset[cfr, t1, 8]
1457     storei t2, PayloadOffset[cfr, t1, 8]
1458     dispatch(4)
1459
1460 .opGetArgumentsLengthSlow:
1461     callSlowPath(_llint_slow_path_get_arguments_length)
1462     dispatch(4)
1463
1464
1465 macro putById(getPropertyStorage)
1466     traceExecution()
1467     writeBarrierOnOperands(1, 3)
1468     loadi 4[PC], t3
1469     loadi 16[PC], t1
1470     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1471     loadi 12[PC], t2
1472     getPropertyStorage(
1473         t0,
1474         t3,
1475         macro (propertyStorage, scratch)
1476             bpneq JSCell::m_structureID[t0], t1, .opPutByIdSlow
1477             loadi 20[PC], t1
1478             loadConstantOrVariable2Reg(t2, scratch, t2)
1479             storei scratch, TagOffset[propertyStorage, t1]
1480             storei t2, PayloadOffset[propertyStorage, t1]
1481             dispatch(9)
1482         end)
1483
1484     .opPutByIdSlow:
1485         callSlowPath(_llint_slow_path_put_by_id)
1486         dispatch(9)
1487 end
1488
1489 _llint_op_put_by_id:
1490     putById(withInlineStorage)
1491
1492
1493 _llint_op_put_by_id_out_of_line:
1494     putById(withOutOfLineStorage)
1495
1496
1497 macro putByIdTransition(additionalChecks, getPropertyStorage)
1498     traceExecution()
1499     writeBarrierOnOperand(1)
1500     loadi 4[PC], t3
1501     loadi 16[PC], t1
1502     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1503     loadi 12[PC], t2
1504     bpneq JSCell::m_structureID[t0], t1, .opPutByIdSlow
1505     additionalChecks(t1, t3, .opPutByIdSlow)
1506     loadi 20[PC], t1
1507     getPropertyStorage(
1508         t0,
1509         t3,
1510         macro (propertyStorage, scratch)
1511             addp t1, propertyStorage, t3
1512             loadConstantOrVariable2Reg(t2, t1, t2)
1513             storei t1, TagOffset[t3]
1514             loadi 24[PC], t1
1515             storei t2, PayloadOffset[t3]
1516             storep t1, JSCell::m_structureID[t0]
1517             dispatch(9)
1518         end)
1519
1520     .opPutByIdSlow:
1521         callSlowPath(_llint_slow_path_put_by_id)
1522         dispatch(9)
1523 end
1524
1525 macro noAdditionalChecks(oldStructure, scratch, slowPath)
1526 end
1527
1528 macro structureChainChecks(oldStructure, scratch, slowPath)
1529     const protoCell = oldStructure   # Reusing the oldStructure register for the proto
1530
1531     loadp 28[PC], scratch
1532     assert(macro (ok) btpnz scratch, ok end)
1533     loadp StructureChain::m_vector[scratch], scratch
1534     assert(macro (ok) btpnz scratch, ok end)
1535     bieq Structure::m_prototype + TagOffset[oldStructure], NullTag, .done
1536 .loop:
1537     loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell
1538     loadp JSCell::m_structureID[protoCell], oldStructure
1539     bpneq oldStructure, [scratch], slowPath
1540     addp 4, scratch
1541     bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop
1542 .done:
1543 end
1544
1545 _llint_op_put_by_id_transition_direct:
1546     putByIdTransition(noAdditionalChecks, withInlineStorage)
1547
1548
1549 _llint_op_put_by_id_transition_direct_out_of_line:
1550     putByIdTransition(noAdditionalChecks, withOutOfLineStorage)
1551
1552
1553 _llint_op_put_by_id_transition_normal:
1554     putByIdTransition(structureChainChecks, withInlineStorage)
1555
1556
1557 _llint_op_put_by_id_transition_normal_out_of_line:
1558     putByIdTransition(structureChainChecks, withOutOfLineStorage)
1559
1560
1561 _llint_op_get_by_val:
1562     traceExecution()
1563     loadi 8[PC], t2
1564     loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow)
1565     move t0, t2
1566     loadp 16[PC], t3
1567     arrayProfile(t2, t3, t1)
1568     loadi 12[PC], t3
1569     loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
1570     loadp JSObject::m_butterfly[t0], t3
1571     andi IndexingShapeMask, t2
1572     bieq t2, Int32Shape, .opGetByValIsContiguous
1573     bineq t2, ContiguousShape, .opGetByValNotContiguous
1574 .opGetByValIsContiguous:
1575     
1576     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds
1577     loadi TagOffset[t3, t1, 8], t2
1578     loadi PayloadOffset[t3, t1, 8], t1
1579     jmp .opGetByValDone
1580
1581 .opGetByValNotContiguous:
1582     bineq t2, DoubleShape, .opGetByValNotDouble
1583     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds
1584     loadd [t3, t1, 8], ft0
1585     bdnequn ft0, ft0, .opGetByValSlow
1586     # FIXME: This could be massively optimized.
1587     fd2ii ft0, t1, t2
1588     loadi 4[PC], t0
1589     jmp .opGetByValNotEmpty
1590
1591 .opGetByValNotDouble:
1592     subi ArrayStorageShape, t2
1593     bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow
1594     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t3], .opGetByValOutOfBounds
1595     loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2
1596     loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1
1597
1598 .opGetByValDone:
1599     loadi 4[PC], t0
1600     bieq t2, EmptyValueTag, .opGetByValOutOfBounds
1601 .opGetByValNotEmpty:
1602     storei t2, TagOffset[cfr, t0, 8]
1603     storei t1, PayloadOffset[cfr, t0, 8]
1604     valueProfile(t2, t1, 20, t0)
1605     dispatch(6)
1606
1607 .opGetByValOutOfBounds:
1608     loadpFromInstruction(4, t0)
1609     storeb 1, ArrayProfile::m_outOfBounds[t0]
1610 .opGetByValSlow:
1611     callSlowPath(_llint_slow_path_get_by_val)
1612     dispatch(6)
1613
1614
1615 _llint_op_get_argument_by_val:
1616     # FIXME: At some point we should array profile this. Right now it isn't necessary
1617     # since the DFG will never turn a get_argument_by_val into a GetByVal.
1618     traceExecution()
1619     loadi 8[PC], t0
1620     loadi 12[PC], t1
1621     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentByValSlow
1622     loadConstantOrVariablePayload(t1, Int32Tag, t2, .opGetArgumentByValSlow)
1623     addi 1, t2
1624     loadi ArgumentCount + PayloadOffset[cfr], t1
1625     biaeq t2, t1, .opGetArgumentByValSlow
1626     loadi 4[PC], t3
1627     loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0
1628     loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t1
1629     storei t0, TagOffset[cfr, t3, 8]
1630     storei t1, PayloadOffset[cfr, t3, 8]
1631     valueProfile(t0, t1, 20, t2)
1632     dispatch(6)
1633
1634 .opGetArgumentByValSlow:
1635     callSlowPath(_llint_slow_path_get_argument_by_val)
1636     dispatch(6)
1637
1638
1639 macro contiguousPutByVal(storeCallback)
1640     biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .outOfBounds
1641 .storeResult:
1642     loadi 12[PC], t2
1643     storeCallback(t2, t1, t0, t3)
1644     dispatch(5)
1645
1646 .outOfBounds:
1647     biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t0], .opPutByValOutOfBounds
1648     loadp 16[PC], t2
1649     storeb 1, ArrayProfile::m_mayStoreToHole[t2]
1650     addi 1, t3, t2
1651     storei t2, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0]
1652     jmp .storeResult
1653 end
1654
1655 macro putByVal(slowPath)
1656     traceExecution()
1657     writeBarrierOnOperands(1, 3)
1658     loadi 4[PC], t0
1659     loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
1660     move t1, t2
1661     loadp 16[PC], t3
1662     arrayProfile(t2, t3, t0)
1663     loadi 8[PC], t0
1664     loadConstantOrVariablePayload(t0, Int32Tag, t3, .opPutByValSlow)
1665     loadp JSObject::m_butterfly[t1], t0
1666     andi IndexingShapeMask, t2
1667     bineq t2, Int32Shape, .opPutByValNotInt32
1668     contiguousPutByVal(
1669         macro (operand, scratch, base, index)
1670             loadConstantOrVariablePayload(operand, Int32Tag, scratch, .opPutByValSlow)
1671             storei Int32Tag, TagOffset[base, index, 8]
1672             storei scratch, PayloadOffset[base, index, 8]
1673         end)
1674
1675 .opPutByValNotInt32:
1676     bineq t2, DoubleShape, .opPutByValNotDouble
1677     contiguousPutByVal(
1678         macro (operand, scratch, base, index)
1679             const tag = scratch
1680             const payload = operand
1681             loadConstantOrVariable2Reg(operand, tag, payload)
1682             bineq tag, Int32Tag, .notInt
1683             ci2d payload, ft0
1684             jmp .ready
1685         .notInt:
1686             fii2d payload, tag, ft0
1687             bdnequn ft0, ft0, .opPutByValSlow
1688         .ready:
1689             stored ft0, [base, index, 8]
1690         end)
1691
1692 .opPutByValNotDouble:
1693     bineq t2, ContiguousShape, .opPutByValNotContiguous
1694     contiguousPutByVal(
1695         macro (operand, scratch, base, index)
1696             const tag = scratch
1697             const payload = operand
1698             loadConstantOrVariable2Reg(operand, tag, payload)
1699             storei tag, TagOffset[base, index, 8]
1700             storei payload, PayloadOffset[base, index, 8]
1701         end)
1702
1703 .opPutByValNotContiguous:
1704     bineq t2, ArrayStorageShape, .opPutByValSlow
1705     biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t0], .opPutByValOutOfBounds
1706     bieq ArrayStorage::m_vector + TagOffset[t0, t3, 8], EmptyValueTag, .opPutByValArrayStorageEmpty
1707 .opPutByValArrayStorageStoreResult:
1708     loadi 12[PC], t2
1709     loadConstantOrVariable2Reg(t2, t1, t2)
1710     storei t1, ArrayStorage::m_vector + TagOffset[t0, t3, 8]
1711     storei t2, ArrayStorage::m_vector + PayloadOffset[t0, t3, 8]
1712     dispatch(5)
1713
1714 .opPutByValArrayStorageEmpty:
1715     loadp 16[PC], t1
1716     storeb 1, ArrayProfile::m_mayStoreToHole[t1]
1717     addi 1, ArrayStorage::m_numValuesInVector[t0]
1718     bib t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .opPutByValArrayStorageStoreResult
1719     addi 1, t3, t1
1720     storei t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0]
1721     jmp .opPutByValArrayStorageStoreResult
1722
1723 .opPutByValOutOfBounds:
1724     loadpFromInstruction(4, t0)
1725     storeb 1, ArrayProfile::m_outOfBounds[t0]
1726 .opPutByValSlow:
1727     callSlowPath(slowPath)
1728     dispatch(5)
1729 end
1730
1731 _llint_op_put_by_val:
1732     putByVal(_llint_slow_path_put_by_val)
1733
1734 _llint_op_put_by_val_direct:
1735     putByVal(_llint_slow_path_put_by_val_direct)
1736
1737 _llint_op_jmp:
1738     traceExecution()
1739     dispatchBranch(4[PC])
1740
1741
1742 macro jumpTrueOrFalse(conditionOp, slow)
1743     loadi 4[PC], t1
1744     loadConstantOrVariablePayload(t1, BooleanTag, t0, .slow)
1745     conditionOp(t0, .target)
1746     dispatch(3)
1747
1748 .target:
1749     dispatchBranch(8[PC])
1750
1751 .slow:
1752     callSlowPath(slow)
1753     dispatch(0)
1754 end
1755
1756
1757 macro equalNull(cellHandler, immediateHandler)
1758     loadi 4[PC], t0
1759     assertNotConstant(t0)
1760     loadi TagOffset[cfr, t0, 8], t1
1761     loadi PayloadOffset[cfr, t0, 8], t0
1762     bineq t1, CellTag, .immediate
1763     loadp JSCell::m_structureID[t0], t2
1764     cellHandler(t2, JSCell::m_flags[t0], .target)
1765     dispatch(3)
1766
1767 .target:
1768     dispatchBranch(8[PC])
1769
1770 .immediate:
1771     ori 1, t1
1772     immediateHandler(t1, .target)
1773     dispatch(3)
1774 end
1775
1776 _llint_op_jeq_null:
1777     traceExecution()
1778     equalNull(
1779         macro (structure, value, target) 
1780             btbz value, MasqueradesAsUndefined, .opJeqNullNotMasqueradesAsUndefined
1781             loadp CodeBlock[cfr], t0
1782             loadp CodeBlock::m_globalObject[t0], t0
1783             bpeq Structure::m_globalObject[structure], t0, target
1784 .opJeqNullNotMasqueradesAsUndefined:
1785         end,
1786         macro (value, target) bieq value, NullTag, target end)
1787     
1788
1789 _llint_op_jneq_null:
1790     traceExecution()
1791     equalNull(
1792         macro (structure, value, target) 
1793             btbz value, MasqueradesAsUndefined, target 
1794             loadp CodeBlock[cfr], t0
1795             loadp CodeBlock::m_globalObject[t0], t0
1796             bpneq Structure::m_globalObject[structure], t0, target
1797         end,
1798         macro (value, target) bineq value, NullTag, target end)
1799
1800
1801 _llint_op_jneq_ptr:
1802     traceExecution()
1803     loadi 4[PC], t0
1804     loadi 8[PC], t1
1805     loadp CodeBlock[cfr], t2
1806     loadp CodeBlock::m_globalObject[t2], t2
1807     bineq TagOffset[cfr, t0, 8], CellTag, .opJneqPtrBranch
1808     loadp JSGlobalObject::m_specialPointers[t2, t1, 4], t1
1809     bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough
1810 .opJneqPtrBranch:
1811     dispatchBranch(12[PC])
1812 .opJneqPtrFallThrough:
1813     dispatch(4)
1814
1815
1816 macro compare(integerCompare, doubleCompare, slowPath)
1817     loadi 4[PC], t2
1818     loadi 8[PC], t3
1819     loadConstantOrVariable(t2, t0, t1)
1820     loadConstantOrVariable2Reg(t3, t2, t3)
1821     bineq t0, Int32Tag, .op1NotInt
1822     bineq t2, Int32Tag, .op2NotInt
1823     integerCompare(t1, t3, .jumpTarget)
1824     dispatch(4)
1825
1826 .op1NotInt:
1827     bia t0, LowestTag, .slow
1828     bib t2, LowestTag, .op1NotIntOp2Double
1829     bineq t2, Int32Tag, .slow
1830     ci2d t3, ft1
1831     jmp .op1NotIntReady
1832 .op1NotIntOp2Double:
1833     fii2d t3, t2, ft1
1834 .op1NotIntReady:
1835     fii2d t1, t0, ft0
1836     doubleCompare(ft0, ft1, .jumpTarget)
1837     dispatch(4)
1838
1839 .op2NotInt:
1840     ci2d t1, ft0
1841     bia t2, LowestTag, .slow
1842     fii2d t3, t2, ft1
1843     doubleCompare(ft0, ft1, .jumpTarget)
1844     dispatch(4)
1845
1846 .jumpTarget:
1847     dispatchBranch(12[PC])
1848
1849 .slow:
1850     callSlowPath(slowPath)
1851     dispatch(0)
1852 end
1853
1854
1855 _llint_op_switch_imm:
1856     traceExecution()
1857     loadi 12[PC], t2
1858     loadi 4[PC], t3
1859     loadConstantOrVariable(t2, t1, t0)
1860     loadp CodeBlock[cfr], t2
1861     loadp CodeBlock::m_rareData[t2], t2
1862     muli sizeof SimpleJumpTable, t3   # FIXME: would be nice to peephole this!
1863     loadp CodeBlock::RareData::m_switchJumpTables + VectorBufferOffset[t2], t2
1864     addp t3, t2
1865     bineq t1, Int32Tag, .opSwitchImmNotInt
1866     subi SimpleJumpTable::min[t2], t0
1867     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchImmFallThrough
1868     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t3
1869     loadi [t3, t0, 4], t1
1870     btiz t1, .opSwitchImmFallThrough
1871     dispatchBranchWithOffset(t1)
1872
1873 .opSwitchImmNotInt:
1874     bib t1, LowestTag, .opSwitchImmSlow  # Go to slow path if it's a double.
1875 .opSwitchImmFallThrough:
1876     dispatchBranch(8[PC])
1877
1878 .opSwitchImmSlow:
1879     callSlowPath(_llint_slow_path_switch_imm)
1880     dispatch(0)
1881
1882
1883 _llint_op_switch_char:
1884     traceExecution()
1885     loadi 12[PC], t2
1886     loadi 4[PC], t3
1887     loadConstantOrVariable(t2, t1, t0)
1888     loadp CodeBlock[cfr], t2
1889     loadp CodeBlock::m_rareData[t2], t2
1890     muli sizeof SimpleJumpTable, t3
1891     loadp CodeBlock::RareData::m_switchJumpTables + VectorBufferOffset[t2], t2
1892     addp t3, t2
1893     bineq t1, CellTag, .opSwitchCharFallThrough
1894     bbneq JSCell::m_type[t0], StringType, .opSwitchCharFallThrough
1895     bineq JSString::m_length[t0], 1, .opSwitchCharFallThrough
1896     loadp JSString::m_value[t0], t0
1897     btpz  t0, .opSwitchOnRope
1898     loadp StringImpl::m_data8[t0], t1
1899     btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
1900     loadh [t1], t0
1901     jmp .opSwitchCharReady
1902 .opSwitchChar8Bit:
1903     loadb [t1], t0
1904 .opSwitchCharReady:
1905     subi SimpleJumpTable::min[t2], t0
1906     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchCharFallThrough
1907     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t2
1908     loadi [t2, t0, 4], t1
1909     btiz t1, .opSwitchCharFallThrough
1910     dispatchBranchWithOffset(t1)
1911
1912 .opSwitchCharFallThrough:
1913     dispatchBranch(8[PC])
1914
1915 .opSwitchOnRope:
1916     callSlowPath(_llint_slow_path_switch_char)
1917     dispatch(0)
1918
1919
1920 _llint_op_new_func:
1921     traceExecution()
1922     btiz 12[PC], .opNewFuncUnchecked
1923     loadi 4[PC], t1
1924     bineq TagOffset[cfr, t1, 8], EmptyValueTag, .opNewFuncDone
1925 .opNewFuncUnchecked:
1926     callSlowPath(_llint_slow_path_new_func)
1927 .opNewFuncDone:
1928     dispatch(4)
1929
1930
1931 _llint_op_new_captured_func:
1932     traceExecution()
1933     callSlowPath(_slow_path_new_captured_func)
1934     dispatch(4)
1935
1936
1937 macro arrayProfileForCall()
1938     loadi 16[PC], t3
1939     negi t3
1940     bineq ThisArgumentOffset + TagOffset[cfr, t3, 8], CellTag, .done
1941     loadi ThisArgumentOffset + PayloadOffset[cfr, t3, 8], t0
1942     loadp JSCell::m_structureID[t0], t0
1943     loadpFromInstruction(CallOpCodeSize - 2, t1)
1944     storep t0, ArrayProfile::m_lastSeenStructureID[t1]
1945 .done:
1946 end
1947
1948 macro doCall(slowPath)
1949     loadi 8[PC], t0
1950     loadi 20[PC], t1
1951     loadp LLIntCallLinkInfo::callee[t1], t2
1952     loadConstantOrVariablePayload(t0, CellTag, t3, .opCallSlow)
1953     bineq t3, t2, .opCallSlow
1954     loadi 16[PC], t3
1955     lshifti 3, t3
1956     negi t3
1957     addp cfr, t3  # t3 contains the new value of cfr
1958     loadp JSFunction::m_scope[t2], t0
1959     storei t2, Callee + PayloadOffset[t3]
1960     storei t0, ScopeChain + PayloadOffset[t3]
1961     loadi 12[PC], t2
1962     storei PC, ArgumentCount + TagOffset[cfr]
1963     storei t2, ArgumentCount + PayloadOffset[t3]
1964     storei CellTag, Callee + TagOffset[t3]
1965     storei CellTag, ScopeChain + TagOffset[t3]
1966     addp CallerFrameAndPCSize, t3
1967     callTargetFunction(t1, t3)
1968
1969 .opCallSlow:
1970     slowPathForCall(slowPath)
1971 end
1972
1973
1974 _llint_op_tear_off_lexical_environment:
1975     traceExecution()
1976     loadi 4[PC], t0
1977     bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffActivationNotCreated
1978     callSlowPath(_llint_slow_path_tear_off_lexical_environment)
1979 .opTearOffActivationNotCreated:
1980     dispatch(2)
1981
1982
1983 _llint_op_tear_off_arguments:
1984     traceExecution()
1985     loadi 4[PC], t0
1986     addi 1, t0   # Get the unmodifiedArgumentsRegister
1987     bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffArgumentsNotCreated
1988     callSlowPath(_llint_slow_path_tear_off_arguments)
1989 .opTearOffArgumentsNotCreated:
1990     dispatch(3)
1991
1992
1993 _llint_op_ret:
1994     traceExecution()
1995     checkSwitchToJITForEpilogue()
1996     loadi 4[PC], t2
1997     loadConstantOrVariable(t2, t1, t0)
1998     doReturn()
1999
2000
2001 _llint_op_ret_object_or_this:
2002     traceExecution()
2003     checkSwitchToJITForEpilogue()
2004     loadi 4[PC], t2
2005     loadConstantOrVariable(t2, t1, t0)
2006     bineq t1, CellTag, .opRetObjectOrThisNotObject
2007     bbb JSCell::m_type[t0], ObjectType, .opRetObjectOrThisNotObject
2008     doReturn()
2009
2010 .opRetObjectOrThisNotObject:
2011     loadi 8[PC], t2
2012     loadConstantOrVariable(t2, t1, t0)
2013     doReturn()
2014
2015
2016 _llint_op_to_primitive:
2017     traceExecution()
2018     loadi 8[PC], t2
2019     loadi 4[PC], t3
2020     loadConstantOrVariable(t2, t1, t0)
2021     bineq t1, CellTag, .opToPrimitiveIsImm
2022     bbneq JSCell::m_type[t0], StringType, .opToPrimitiveSlowCase
2023 .opToPrimitiveIsImm:
2024     storei t1, TagOffset[cfr, t3, 8]
2025     storei t0, PayloadOffset[cfr, t3, 8]
2026     dispatch(3)
2027
2028 .opToPrimitiveSlowCase:
2029     callSlowPath(_slow_path_to_primitive)
2030     dispatch(3)
2031
2032
2033 _llint_op_catch:
2034     # This is where we end up from the JIT's throw trampoline (because the
2035     # machine code return address will be set to _llint_op_catch), and from
2036     # the interpreter's throw trampoline (see _llint_throw_trampoline).
2037     # The throwing code must have known that we were throwing to the interpreter,
2038     # and have set VM::targetInterpreterPCForThrow.
2039     loadp ScopeChain + PayloadOffset[cfr], t3
2040     andp MarkedBlockMask, t3
2041     loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
2042     loadp VM::callFrameForThrow[t3], cfr
2043     loadp VM::vmEntryFrameForThrow[t3], t0
2044     storep t0, VM::topVMEntryFrame[t3]
2045     restoreStackPointerAfterCall()
2046
2047     loadi VM::targetInterpreterPCForThrow[t3], PC
2048     loadi VM::m_exception + PayloadOffset[t3], t0
2049     loadi VM::m_exception + TagOffset[t3], t1
2050     storei 0, VM::m_exception + PayloadOffset[t3]
2051     storei EmptyValueTag, VM::m_exception + TagOffset[t3]
2052     loadi 4[PC], t2
2053     storei t0, PayloadOffset[cfr, t2, 8]
2054     storei t1, TagOffset[cfr, t2, 8]
2055     traceExecution()  # This needs to be here because we don't want to clobber t0, t1, t2, t3 above.
2056     dispatch(2)
2057
2058
2059 # Gives you the scope in t0, while allowing you to optionally perform additional checks on the
2060 # scopes as they are traversed. scopeCheck() is called with two arguments: the register
2061 # holding the scope, and a register that can be used for scratch. Note that this does not
2062 # use t3, so you can hold stuff in t3 if need be.
2063 macro getDeBruijnScope(deBruijinIndexOperand, scopeCheck)
2064     loadp ScopeChain + PayloadOffset[cfr], t0
2065     loadi deBruijinIndexOperand, t2
2066
2067     btiz t2, .done
2068
2069     loadp CodeBlock[cfr], t1
2070     bineq CodeBlock::m_codeType[t1], FunctionCode, .loop
2071     btbz CodeBlock::m_needsActivation[t1], .loop
2072
2073     loadi CodeBlock::m_lexicalEnvironmentRegister[t1], t1
2074
2075     # Need to conditionally skip over one scope.
2076     bieq TagOffset[cfr, t1, 8], EmptyValueTag, .noActivation
2077     scopeCheck(t0, t1)
2078     loadp JSScope::m_next[t0], t0
2079 .noActivation:
2080     subi 1, t2
2081
2082     btiz t2, .done
2083 .loop:
2084     scopeCheck(t0, t1)
2085     loadp JSScope::m_next[t0], t0
2086     subi 1, t2
2087     btinz t2, .loop
2088
2089 .done:
2090
2091 end
2092
2093 _llint_op_end:
2094     traceExecution()
2095     checkSwitchToJITForEpilogue()
2096     loadi 4[PC], t0
2097     assertNotConstant(t0)
2098     loadi TagOffset[cfr, t0, 8], t1
2099     loadi PayloadOffset[cfr, t0, 8], t0
2100     doReturn()
2101
2102
2103 _llint_throw_from_slow_path_trampoline:
2104     callSlowPath(_llint_slow_path_handle_exception)
2105
2106     # When throwing from the interpreter (i.e. throwing from LLIntSlowPaths), so
2107     # the throw target is not necessarily interpreted code, we come to here.
2108     # This essentially emulates the JIT's throwing protocol.
2109     loadp CodeBlock[cfr], t1
2110     loadp CodeBlock::m_vm[t1], t1
2111     jmp VM::targetMachinePCForThrow[t1]
2112
2113
2114 _llint_throw_during_call_trampoline:
2115     preserveReturnAddressAfterCall(t2)
2116     jmp _llint_throw_from_slow_path_trampoline
2117
2118
2119 macro nativeCallTrampoline(executableOffsetToFunction)
2120
2121     functionPrologue()
2122     storep 0, CodeBlock[cfr]
2123     loadp CallerFrame[cfr], t0
2124     loadi ScopeChain + PayloadOffset[t0], t1
2125     storei CellTag, ScopeChain + TagOffset[cfr]
2126     storei t1, ScopeChain + PayloadOffset[cfr]
2127     if X86 or X86_WIN
2128         subp 8, sp # align stack pointer
2129         andp MarkedBlockMask, t1
2130         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t3
2131         storep cfr, VM::topCallFrame[t3]
2132         move cfr, t2  # t2 = ecx
2133         storep t2, [sp]
2134         loadi Callee + PayloadOffset[cfr], t1
2135         loadp JSFunction::m_executable[t1], t1
2136         checkStackPointerAlignment(t3, 0xdead0001)
2137         call executableOffsetToFunction[t1]
2138         loadp ScopeChain[cfr], t3
2139         andp MarkedBlockMask, t3
2140         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
2141         addp 8, sp
2142     elsif ARM or ARMv7 or ARMv7_TRADITIONAL or C_LOOP or MIPS or SH4
2143         subp 8, sp # align stack pointer
2144         # t1 already contains the ScopeChain.
2145         andp MarkedBlockMask, t1
2146         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t1
2147         storep cfr, VM::topCallFrame[t1]
2148         if MIPS or SH4
2149             move cfr, a0
2150         else
2151             move cfr, t0
2152         end
2153         loadi Callee + PayloadOffset[cfr], t1
2154         loadp JSFunction::m_executable[t1], t1
2155         checkStackPointerAlignment(t3, 0xdead0001)
2156         if C_LOOP
2157             cloopCallNative executableOffsetToFunction[t1]
2158         else
2159             call executableOffsetToFunction[t1]
2160         end
2161         loadp ScopeChain[cfr], t3
2162         andp MarkedBlockMask, t3
2163         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
2164         addp 8, sp
2165     else
2166         error
2167     end
2168     
2169     functionEpilogue()
2170     bineq VM::m_exception + TagOffset[t3], EmptyValueTag, .handleException
2171     ret
2172
2173 .handleException:
2174     storep cfr, VM::topCallFrame[t3]
2175     restoreStackPointerAfterCall()
2176     jmp _llint_throw_from_slow_path_trampoline
2177 end
2178
2179
2180 macro getGlobalObject(dst)
2181     loadp CodeBlock[cfr], t0
2182     loadp CodeBlock::m_globalObject[t0], t0
2183     loadisFromInstruction(dst, t1)
2184     storei CellTag, TagOffset[cfr, t1, 8]
2185     storei t0, PayloadOffset[cfr, t1, 8]
2186 end
2187
2188 macro varInjectionCheck(slowPath)
2189     loadp CodeBlock[cfr], t0
2190     loadp CodeBlock::m_globalObject[t0], t0
2191     loadp JSGlobalObject::m_varInjectionWatchpoint[t0], t0
2192     bbeq WatchpointSet::m_state[t0], IsInvalidated, slowPath
2193 end
2194
2195 macro resolveScope()
2196     loadp CodeBlock[cfr], t0
2197     loadisFromInstruction(4, t2)
2198
2199     loadp ScopeChain[cfr], t0
2200     btiz t2, .resolveScopeLoopEnd
2201
2202 .resolveScopeLoop:
2203     loadp JSScope::m_next[t0], t0
2204     subi 1, t2
2205     btinz t2, .resolveScopeLoop
2206
2207 .resolveScopeLoopEnd:
2208     loadisFromInstruction(1, t1)
2209     storei CellTag, TagOffset[cfr, t1, 8]
2210     storei t0, PayloadOffset[cfr, t1, 8]
2211 end
2212
2213
2214 _llint_op_resolve_scope:
2215     traceExecution()
2216     loadisFromInstruction(3, t0)
2217
2218 #rGlobalProperty:
2219     bineq t0, GlobalProperty, .rGlobalVar
2220     getGlobalObject(1)
2221     dispatch(6)
2222
2223 .rGlobalVar:
2224     bineq t0, GlobalVar, .rClosureVar
2225     getGlobalObject(1)
2226     dispatch(6)
2227
2228 .rClosureVar:
2229     bineq t0, ClosureVar, .rGlobalPropertyWithVarInjectionChecks
2230     resolveScope()
2231     dispatch(6)
2232
2233 .rGlobalPropertyWithVarInjectionChecks:
2234     bineq t0, GlobalPropertyWithVarInjectionChecks, .rGlobalVarWithVarInjectionChecks
2235     varInjectionCheck(.rDynamic)
2236     getGlobalObject(1)
2237     dispatch(6)
2238
2239 .rGlobalVarWithVarInjectionChecks:
2240     bineq t0, GlobalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks
2241     varInjectionCheck(.rDynamic)
2242     getGlobalObject(1)
2243     dispatch(6)
2244
2245 .rClosureVarWithVarInjectionChecks:
2246     bineq t0, ClosureVarWithVarInjectionChecks, .rDynamic
2247     varInjectionCheck(.rDynamic)
2248     resolveScope()
2249     dispatch(6)
2250
2251 .rDynamic:
2252     callSlowPath(_llint_slow_path_resolve_scope)
2253     dispatch(6)
2254
2255
2256 macro loadWithStructureCheck(operand, slowPath)
2257     loadisFromInstruction(operand, t0)
2258     loadp [cfr, t0, 8], t0
2259     loadpFromInstruction(5, t1)
2260     bpneq JSCell::m_structureID[t0], t1, slowPath
2261 end
2262
2263 macro getProperty()
2264     loadisFromInstruction(6, t3)
2265     loadPropertyAtVariableOffset(t3, t0, t1, t2)
2266     valueProfile(t1, t2, 28, t0)
2267     loadisFromInstruction(1, t0)
2268     storei t1, TagOffset[cfr, t0, 8]
2269     storei t2, PayloadOffset[cfr, t0, 8]
2270 end
2271
2272 macro getGlobalVar()
2273     loadpFromInstruction(6, t0)
2274     loadp TagOffset[t0], t1
2275     loadp PayloadOffset[t0], t2
2276     valueProfile(t1, t2, 28, t0)
2277     loadisFromInstruction(1, t0)
2278     storei t1, TagOffset[cfr, t0, 8]
2279     storei t2, PayloadOffset[cfr, t0, 8]
2280 end
2281
2282 macro getClosureVar()
2283     loadp JSEnvironmentRecord::m_registers[t0], t0
2284     loadisFromInstruction(6, t3)
2285     loadp TagOffset[t0, t3, 8], t1
2286     loadp PayloadOffset[t0, t3, 8], t2
2287     valueProfile(t1, t2, 28, t0)
2288     loadisFromInstruction(1, t0)
2289     storei t1, TagOffset[cfr, t0, 8]
2290     storei t2, PayloadOffset[cfr, t0, 8]
2291 end
2292
2293 _llint_op_get_from_scope:
2294     traceExecution()
2295     loadisFromInstruction(4, t0)
2296     andi ResolveModeMask, t0
2297
2298 #gGlobalProperty:
2299     bineq t0, GlobalProperty, .gGlobalVar
2300     loadWithStructureCheck(2, .gDynamic)
2301     getProperty()
2302     dispatch(8)
2303
2304 .gGlobalVar:
2305     bineq t0, GlobalVar, .gClosureVar
2306     getGlobalVar()
2307     dispatch(8)
2308
2309 .gClosureVar:
2310     bineq t0, ClosureVar, .gGlobalPropertyWithVarInjectionChecks
2311     loadVariable(2, t2, t1, t0)
2312     getClosureVar()
2313     dispatch(8)
2314
2315 .gGlobalPropertyWithVarInjectionChecks:
2316     bineq t0, GlobalPropertyWithVarInjectionChecks, .gGlobalVarWithVarInjectionChecks
2317     loadWithStructureCheck(2, .gDynamic)
2318     getProperty()
2319     dispatch(8)
2320
2321 .gGlobalVarWithVarInjectionChecks:
2322     bineq t0, GlobalVarWithVarInjectionChecks, .gClosureVarWithVarInjectionChecks
2323     varInjectionCheck(.gDynamic)
2324     loadVariable(2, t2, t1, t0)
2325     getGlobalVar()
2326     dispatch(8)
2327
2328 .gClosureVarWithVarInjectionChecks:
2329     bineq t0, ClosureVarWithVarInjectionChecks, .gDynamic
2330     varInjectionCheck(.gDynamic)
2331     loadVariable(2, t2, t1, t0)
2332     getClosureVar()
2333     dispatch(8)
2334
2335 .gDynamic:
2336     callSlowPath(_llint_slow_path_get_from_scope)
2337     dispatch(8)
2338
2339
2340 macro putProperty()
2341     loadisFromInstruction(3, t1)
2342     loadConstantOrVariable(t1, t2, t3)
2343     loadisFromInstruction(6, t1)
2344     storePropertyAtVariableOffset(t1, t0, t2, t3)
2345 end
2346
2347 macro putGlobalVar()
2348     loadisFromInstruction(3, t0)
2349     loadConstantOrVariable(t0, t1, t2)
2350     loadpFromInstruction(5, t3)
2351     notifyWrite(t3, t1, t2, t0, .pDynamic)
2352     loadpFromInstruction(6, t0)
2353     storei t1, TagOffset[t0]
2354     storei t2, PayloadOffset[t0]
2355 end
2356
2357 macro putClosureVar()
2358     loadisFromInstruction(3, t1)
2359     loadConstantOrVariable(t1, t2, t3)
2360     loadp JSEnvironmentRecord::m_registers[t0], t0
2361     loadisFromInstruction(6, t1)
2362     storei t2, TagOffset[t0, t1, 8]
2363     storei t3, PayloadOffset[t0, t1, 8]
2364 end
2365
2366
2367 _llint_op_put_to_scope:
2368     traceExecution()
2369     loadisFromInstruction(4, t0)
2370     andi ResolveModeMask, t0
2371
2372 #pGlobalProperty:
2373     bineq t0, GlobalProperty, .pGlobalVar
2374     writeBarrierOnOperands(1, 3)
2375     loadWithStructureCheck(1, .pDynamic)
2376     putProperty()
2377     dispatch(7)
2378
2379 .pGlobalVar:
2380     bineq t0, GlobalVar, .pClosureVar
2381     writeBarrierOnGlobalObject(3)
2382     putGlobalVar()
2383     dispatch(7)
2384
2385 .pClosureVar:
2386     bineq t0, ClosureVar, .pGlobalPropertyWithVarInjectionChecks
2387     writeBarrierOnOperands(1, 3)
2388     loadVariable(1, t2, t1, t0)
2389     putClosureVar()
2390     dispatch(7)
2391
2392 .pGlobalPropertyWithVarInjectionChecks:
2393     bineq t0, GlobalPropertyWithVarInjectionChecks, .pGlobalVarWithVarInjectionChecks
2394     writeBarrierOnOperands(1, 3)
2395     loadWithStructureCheck(1, .pDynamic)
2396     putProperty()
2397     dispatch(7)
2398
2399 .pGlobalVarWithVarInjectionChecks:
2400     bineq t0, GlobalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
2401     writeBarrierOnGlobalObject(3)
2402     varInjectionCheck(.pDynamic)
2403     putGlobalVar()
2404     dispatch(7)
2405
2406 .pClosureVarWithVarInjectionChecks:
2407     bineq t0, ClosureVarWithVarInjectionChecks, .pDynamic
2408     writeBarrierOnOperands(1, 3)
2409     varInjectionCheck(.pDynamic)
2410     loadVariable(1, t2, t1, t0)
2411     putClosureVar()
2412     dispatch(7)
2413
2414 .pDynamic:
2415     callSlowPath(_llint_slow_path_put_to_scope)
2416     dispatch(7)