0bcb05411156d6439c765190787d3ed49bef1611
[WebKit-https.git] / Source / JavaScriptCore / llint / LowLevelInterpreter32_64.asm
1 # Copyright (C) 2011-2018 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 # Utilities
26 macro dispatch(advance)
27     addp advance * 4, PC
28     jmp [PC]
29 end
30
31 macro dispatchBranchWithOffset(pcOffset)
32     lshifti 2, pcOffset
33     addp pcOffset, PC
34     jmp [PC]
35 end
36
37 macro dispatchBranch(pcOffset)
38     loadi pcOffset, t0
39     dispatchBranchWithOffset(t0)
40 end
41
42 macro dispatchAfterCall()
43     loadi ArgumentCount + TagOffset[cfr], PC
44     loadi 4[PC], t3
45     storei r1, TagOffset[cfr, t3, 8]
46     storei r0, PayloadOffset[cfr, t3, 8]
47     valueProfile(r1, r0, 4 * (CallOpCodeSize - 1), t3)
48     dispatch(CallOpCodeSize)
49 end
50
51 macro cCall2(function)
52     if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS
53         call function
54     elsif X86 or X86_WIN
55         subp 8, sp
56         push a1
57         push a0
58         call function
59         addp 16, sp
60     elsif C_LOOP
61         cloopCallSlowPath function, a0, a1
62     else
63         error
64     end
65 end
66
67 macro cCall2Void(function)
68     if C_LOOP
69         cloopCallSlowPathVoid function, a0, a1
70     else
71         cCall2(function)
72     end
73 end
74
75 macro cCall4(function)
76     if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS
77         call function
78     elsif X86 or X86_WIN
79         push a3
80         push a2
81         push a1
82         push a0
83         call function
84         addp 16, sp
85     elsif C_LOOP
86         error
87     else
88         error
89     end
90 end
91
92 macro callSlowPath(slowPath)
93     move cfr, a0
94     move PC, a1
95     cCall2(slowPath)
96     move r0, PC
97 end
98
99 macro doVMEntry(makeCall)
100     functionPrologue()
101     pushCalleeSaves()
102
103     # x86 needs to load arguments from the stack
104     if X86 or X86_WIN
105         loadp 16[cfr], a2
106         loadp 12[cfr], a1
107         loadp 8[cfr], a0
108     end
109
110     const entry = a0
111     const vm = a1
112     const protoCallFrame = a2
113
114     # We are using t3, t4 and t5 as temporaries through the function.
115     # Since we have the guarantee that tX != aY when X != Y, we are safe from
116     # aliasing problems with our arguments.
117
118     if ARMv7
119         vmEntryRecord(cfr, t3)
120         move t3, sp
121     else
122         vmEntryRecord(cfr, sp)
123     end
124
125     storep vm, VMEntryRecord::m_vm[sp]
126     loadp VM::topCallFrame[vm], t4
127     storep t4, VMEntryRecord::m_prevTopCallFrame[sp]
128     loadp VM::topEntryFrame[vm], t4
129     storep t4, VMEntryRecord::m_prevTopEntryFrame[sp]
130     loadp ProtoCallFrame::calleeValue[protoCallFrame], t4
131     storep t4, VMEntryRecord::m_callee[sp]
132
133     # Align stack pointer
134     if X86_WIN or MIPS
135         addp CallFrameAlignSlots * SlotSize, sp, t3
136         andp ~StackAlignmentMask, t3
137         subp t3, CallFrameAlignSlots * SlotSize, sp
138     elsif ARM or ARMv7 or ARMv7_TRADITIONAL
139         addp CallFrameAlignSlots * SlotSize, sp, t3
140         clrbp t3, StackAlignmentMask, t3
141         if ARMv7
142             subp t3, CallFrameAlignSlots * SlotSize, t3
143             move t3, sp
144         else
145             subp t3, CallFrameAlignSlots * SlotSize, sp
146         end
147     end
148
149     loadi ProtoCallFrame::paddedArgCount[protoCallFrame], t4
150     addp CallFrameHeaderSlots, t4, t4
151     lshiftp 3, t4
152     subp sp, t4, t3
153     bpa t3, sp, .throwStackOverflow
154
155     # Ensure that we have enough additional stack capacity for the incoming args,
156     # and the frame for the JS code we're executing. We need to do this check
157     # before we start copying the args from the protoCallFrame below.
158     if C_LOOP
159         bpaeq t3, VM::m_cloopStackLimit[vm], .stackHeightOK
160     else
161         bpaeq t3, VM::m_softStackLimit[vm], .stackHeightOK
162     end
163
164     if C_LOOP
165         move entry, t4
166         move vm, t5
167         cloopCallSlowPath _llint_stack_check_at_vm_entry, vm, t3
168         bpeq t0, 0, .stackCheckFailed
169         move t4, entry
170         move t5, vm
171         jmp .stackHeightOK
172
173 .stackCheckFailed:
174         move t4, entry
175         move t5, vm
176     end
177
178 .throwStackOverflow:
179     subp 8, sp # Align stack for cCall2() to make a call.
180     move vm, a0
181     move protoCallFrame, a1
182     cCall2(_llint_throw_stack_overflow_error)
183
184     if ARMv7
185         vmEntryRecord(cfr, t3)
186         move t3, sp
187     else
188         vmEntryRecord(cfr, sp)
189     end
190
191     loadp VMEntryRecord::m_vm[sp], t5
192     loadp VMEntryRecord::m_prevTopCallFrame[sp], t4
193     storep t4, VM::topCallFrame[t5]
194     loadp VMEntryRecord::m_prevTopEntryFrame[sp], t4
195     storep t4, VM::topEntryFrame[t5]
196
197     if ARMv7
198         subp cfr, CalleeRegisterSaveSize, t5
199         move t5, sp
200     else
201         subp cfr, CalleeRegisterSaveSize, sp
202     end
203
204     popCalleeSaves()
205     functionEpilogue()
206     ret
207
208 .stackHeightOK:
209     move t3, sp
210     move 4, t3
211
212 .copyHeaderLoop:
213     subi 1, t3
214     loadi TagOffset[protoCallFrame, t3, 8], t5
215     storei t5, TagOffset + CodeBlock[sp, t3, 8]
216     loadi PayloadOffset[protoCallFrame, t3, 8], t5
217     storei t5, PayloadOffset + CodeBlock[sp, t3, 8]
218     btinz t3, .copyHeaderLoop
219
220     loadi PayloadOffset + ProtoCallFrame::argCountAndCodeOriginValue[protoCallFrame], t4
221     subi 1, t4
222     loadi ProtoCallFrame::paddedArgCount[protoCallFrame], t5
223     subi 1, t5
224
225     bieq t4, t5, .copyArgs
226 .fillExtraArgsLoop:
227     subi 1, t5
228     storei UndefinedTag, ThisArgumentOffset + 8 + TagOffset[sp, t5, 8]
229     storei 0, ThisArgumentOffset + 8 + PayloadOffset[sp, t5, 8]
230     bineq t4, t5, .fillExtraArgsLoop
231
232 .copyArgs:
233     loadp ProtoCallFrame::args[protoCallFrame], t3
234
235 .copyArgsLoop:
236     btiz t4, .copyArgsDone
237     subi 1, t4
238     loadi TagOffset[t3, t4, 8], t5
239     storei t5, ThisArgumentOffset + 8 + TagOffset[sp, t4, 8]
240     loadi PayloadOffset[t3, t4, 8], t5
241     storei t5, ThisArgumentOffset + 8 + PayloadOffset[sp, t4, 8]
242     jmp .copyArgsLoop
243
244 .copyArgsDone:
245     storep sp, VM::topCallFrame[vm]
246     storep cfr, VM::topEntryFrame[vm]
247
248     makeCall(entry, t3, t4)
249
250     if ARMv7
251         vmEntryRecord(cfr, t3)
252         move t3, sp
253     else
254         vmEntryRecord(cfr, sp)
255     end
256
257     loadp VMEntryRecord::m_vm[sp], t5
258     loadp VMEntryRecord::m_prevTopCallFrame[sp], t4
259     storep t4, VM::topCallFrame[t5]
260     loadp VMEntryRecord::m_prevTopEntryFrame[sp], t4
261     storep t4, VM::topEntryFrame[t5]
262
263     if ARMv7
264         subp cfr, CalleeRegisterSaveSize, t5
265         move t5, sp
266     else
267         subp cfr, CalleeRegisterSaveSize, sp
268     end
269
270     popCalleeSaves()
271     functionEpilogue()
272     ret
273 end
274
275 macro makeJavaScriptCall(entry, temp, unused)
276     addp CallerFrameAndPCSize, sp
277     checkStackPointerAlignment(temp, 0xbad0dc02)
278     if C_LOOP
279         cloopCallJSFunction entry
280     else
281         call entry
282     end
283     checkStackPointerAlignment(temp, 0xbad0dc03)
284     subp CallerFrameAndPCSize, sp
285 end
286
287 macro makeHostFunctionCall(entry, temp1, temp2)
288     move entry, temp1
289     storep cfr, [sp]
290     if C_LOOP
291         move sp, a0
292         storep lr, PtrSize[sp]
293         cloopCallNative temp1
294     elsif X86 or X86_WIN
295         # Put callee frame pointer on stack as arg0, also put it in ecx for "fastcall" targets
296         move 0, temp2
297         move temp2, 4[sp] # put 0 in ReturnPC
298         move sp, a0 # a0 is ecx
299         push temp2 # Push dummy arg1
300         push a0
301         call temp1
302         addp 8, sp
303     else
304         move sp, a0
305         call temp1
306     end
307 end
308
309 _handleUncaughtException:
310     loadp Callee + PayloadOffset[cfr], t3
311     andp MarkedBlockMask, t3
312     loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t3], t3
313     restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer(t3, t0)
314     storep 0, VM::callFrameForCatch[t3]
315
316     loadp VM::topEntryFrame[t3], cfr
317     if ARMv7
318         vmEntryRecord(cfr, t3)
319         move t3, sp
320     else
321         vmEntryRecord(cfr, sp)
322     end
323
324     loadp VMEntryRecord::m_vm[sp], t3
325     loadp VMEntryRecord::m_prevTopCallFrame[sp], t5
326     storep t5, VM::topCallFrame[t3]
327     loadp VMEntryRecord::m_prevTopEntryFrame[sp], t5
328     storep t5, VM::topEntryFrame[t3]
329
330     if ARMv7
331         subp cfr, CalleeRegisterSaveSize, t3
332         move t3, sp
333     else
334         subp cfr, CalleeRegisterSaveSize, sp
335     end
336
337     popCalleeSaves()
338     functionEpilogue()
339     ret
340
341 macro doReturnFromHostFunction(extraStackSpace)
342     functionEpilogue(extraStackSpace)
343     ret
344 end
345
346 # Debugging operation if you'd like to print an operand in the instruction stream. fromWhere
347 # should be an immediate integer - any integer you like; use it to identify the place you're
348 # debugging from. operand should likewise be an immediate, and should identify the operand
349 # in the instruction stream you'd like to print out.
350 macro traceOperand(fromWhere, operand)
351     move fromWhere, a2
352     move operand, a3
353     move cfr, a0
354     move PC, a1
355     cCall4(_llint_trace_operand)
356     move r0, PC
357     move r1, cfr
358 end
359
360 # Debugging operation if you'd like to print the value of an operand in the instruction
361 # stream. Same as traceOperand(), but assumes that the operand is a register, and prints its
362 # value.
363 macro traceValue(fromWhere, operand)
364     move fromWhere, a2
365     move operand, a3
366     move cfr, a0
367     move PC, a1
368     cCall4(_llint_trace_value)
369     move r0, PC
370     move r1, cfr
371 end
372
373 # Call a slowPath for call opcodes.
374 macro callCallSlowPath(slowPath, action)
375     storep PC, ArgumentCount + TagOffset[cfr]
376     move cfr, a0
377     move PC, a1
378     cCall2(slowPath)
379     action(r0, r1)
380 end
381
382 macro callTrapHandler(throwHandler)
383     storei PC, ArgumentCount + TagOffset[cfr]
384     move cfr, a0
385     move PC, a1
386     cCall2(_llint_slow_path_handle_traps)
387     btpnz r0, throwHandler
388     loadi ArgumentCount + TagOffset[cfr], PC
389 end
390
391 macro checkSwitchToJITForLoop()
392     checkSwitchToJIT(
393         1,
394         macro ()
395             storei PC, ArgumentCount + TagOffset[cfr]
396             move cfr, a0
397             move PC, a1
398             cCall2(_llint_loop_osr)
399             btpz r0, .recover
400             move r1, sp
401             jmp r0
402         .recover:
403             loadi ArgumentCount + TagOffset[cfr], PC
404         end)
405 end
406
407 macro loadVariable(operand, index, tag, payload)
408     loadisFromInstruction(operand, index)
409     loadi TagOffset[cfr, index, 8], tag
410     loadi PayloadOffset[cfr, index, 8], payload
411 end
412
413 # Index, tag, and payload must be different registers. Index is not
414 # changed.
415 macro loadConstantOrVariable(index, tag, payload)
416     bigteq index, FirstConstantRegisterIndex, .constant
417     loadi TagOffset[cfr, index, 8], tag
418     loadi PayloadOffset[cfr, index, 8], payload
419     jmp .done
420 .constant:
421     loadp CodeBlock[cfr], payload
422     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload
423     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
424     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
425     loadp TagOffset[payload, index, 8], tag
426     loadp PayloadOffset[payload, index, 8], payload
427 .done:
428 end
429
430 macro loadConstantOrVariableTag(index, tag)
431     bigteq index, FirstConstantRegisterIndex, .constant
432     loadi TagOffset[cfr, index, 8], tag
433     jmp .done
434 .constant:
435     loadp CodeBlock[cfr], tag
436     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[tag], tag
437     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
438     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
439     loadp TagOffset[tag, index, 8], tag
440 .done:
441 end
442
443 # Index and payload may be the same register. Index may be clobbered.
444 macro loadConstantOrVariable2Reg(index, tag, payload)
445     bigteq index, FirstConstantRegisterIndex, .constant
446     loadi TagOffset[cfr, index, 8], tag
447     loadi PayloadOffset[cfr, index, 8], payload
448     jmp .done
449 .constant:
450     loadp CodeBlock[cfr], tag
451     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[tag], tag
452     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
453     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
454     lshifti 3, index
455     addp index, tag
456     loadp PayloadOffset[tag], payload
457     loadp TagOffset[tag], tag
458 .done:
459 end
460
461 macro loadConstantOrVariablePayloadTagCustom(index, tagCheck, payload)
462     bigteq index, FirstConstantRegisterIndex, .constant
463     tagCheck(TagOffset[cfr, index, 8])
464     loadi PayloadOffset[cfr, index, 8], payload
465     jmp .done
466 .constant:
467     loadp CodeBlock[cfr], payload
468     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload
469     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
470     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
471     tagCheck(TagOffset[payload, index, 8])
472     loadp PayloadOffset[payload, index, 8], payload
473 .done:
474 end
475
476 # Index and payload must be different registers. Index is not mutated. Use
477 # this if you know what the tag of the variable should be. Doing the tag
478 # test as part of loading the variable reduces register use, but may not
479 # be faster than doing loadConstantOrVariable followed by a branch on the
480 # tag.
481 macro loadConstantOrVariablePayload(index, expectedTag, payload, slow)
482     loadConstantOrVariablePayloadTagCustom(
483         index,
484         macro (actualTag) bineq actualTag, expectedTag, slow end,
485         payload)
486 end
487
488 macro loadConstantOrVariablePayloadUnchecked(index, payload)
489     loadConstantOrVariablePayloadTagCustom(
490         index,
491         macro (actualTag) end,
492         payload)
493 end
494
495 macro writeBarrierOnOperand(cellOperand)
496     loadisFromInstruction(cellOperand, t1)
497     loadConstantOrVariablePayload(t1, CellTag, t2, .writeBarrierDone)
498     skipIfIsRememberedOrInEden(
499         t2, 
500         macro()
501             push cfr, PC
502             # We make two extra slots because cCall2 will poke.
503             subp 8, sp
504             move t2, a1 # t2 can be a0 on x86
505             move cfr, a0
506             cCall2Void(_llint_write_barrier_slow)
507             addp 8, sp
508             pop PC, cfr
509         end)
510 .writeBarrierDone:
511 end
512
513 macro writeBarrierOnOperands(cellOperand, valueOperand)
514     loadisFromInstruction(valueOperand, t1)
515     loadConstantOrVariableTag(t1, t0)
516     bineq t0, CellTag, .writeBarrierDone
517
518     writeBarrierOnOperand(cellOperand)
519 .writeBarrierDone:
520 end
521
522 macro writeBarrierOnGlobal(valueOperand, loadHelper)
523     loadisFromInstruction(valueOperand, t1)
524     loadConstantOrVariableTag(t1, t0)
525     bineq t0, CellTag, .writeBarrierDone
526
527     loadHelper(t3)
528
529     skipIfIsRememberedOrInEden(
530         t3,
531         macro()
532             push cfr, PC
533             # We make two extra slots because cCall2 will poke.
534             subp 8, sp
535             move cfr, a0
536             move t3, a1
537             cCall2Void(_llint_write_barrier_slow)
538             addp 8, sp
539             pop PC, cfr
540         end)
541 .writeBarrierDone:
542 end
543
544 macro writeBarrierOnGlobalObject(valueOperand)
545     writeBarrierOnGlobal(valueOperand,
546         macro(registerToStoreGlobal)
547             loadp CodeBlock[cfr], registerToStoreGlobal
548             loadp CodeBlock::m_globalObject[registerToStoreGlobal], registerToStoreGlobal
549         end)
550 end
551
552 macro writeBarrierOnGlobalLexicalEnvironment(valueOperand)
553     writeBarrierOnGlobal(valueOperand,
554         macro(registerToStoreGlobal)
555             loadp CodeBlock[cfr], registerToStoreGlobal
556             loadp CodeBlock::m_globalObject[registerToStoreGlobal], registerToStoreGlobal
557             loadp JSGlobalObject::m_globalLexicalEnvironment[registerToStoreGlobal], registerToStoreGlobal
558         end)
559 end
560
561 macro valueProfile(tag, payload, operand, scratch)
562     loadp operand[PC], scratch
563     storei tag, ValueProfile::m_buckets + TagOffset[scratch]
564     storei payload, ValueProfile::m_buckets + PayloadOffset[scratch]
565 end
566
567
568 # Entrypoints into the interpreter
569
570 # Expects that CodeBlock is in t1, which is what prologue() leaves behind.
571 macro functionArityCheck(doneLabel, slowPath)
572     loadi PayloadOffset + ArgumentCount[cfr], t0
573     biaeq t0, CodeBlock::m_numParameters[t1], doneLabel
574     move cfr, a0
575     move PC, a1
576     cCall2(slowPath)   # This slowPath has a simple protocol: t0 = 0 => no error, t0 != 0 => error
577     btiz r0, .noError
578
579     # We're throwing before the frame is fully set up. This frame will be
580     # ignored by the unwinder. So, let's restore the callee saves before we
581     # start unwinding. We need to do this before we change the cfr.
582     restoreCalleeSavesUsedByLLInt()
583
584     move r1, cfr   # r1 contains caller frame
585     jmp _llint_throw_from_slow_path_trampoline
586
587 .noError:
588     move r1, t1 # r1 contains slotsToAdd.
589     btiz t1, .continue
590     loadi PayloadOffset + ArgumentCount[cfr], t2
591     addi CallFrameHeaderSlots, t2
592
593     // Check if there are some unaligned slots we can use
594     move t1, t3
595     andi StackAlignmentSlots - 1, t3
596     btiz t3, .noExtraSlot
597 .fillExtraSlots:
598     move 0, t0
599     storei t0, PayloadOffset[cfr, t2, 8]
600     move UndefinedTag, t0
601     storei t0, TagOffset[cfr, t2, 8]
602     addi 1, t2
603     bsubinz 1, t3, .fillExtraSlots
604     andi ~(StackAlignmentSlots - 1), t1
605     btiz t1, .continue
606
607 .noExtraSlot:
608     // Move frame up t1 slots
609     negi t1
610     move cfr, t3
611     move t1, t0
612     lshiftp 3, t0
613     addp t0, cfr
614     addp t0, sp
615 .copyLoop:
616     loadi PayloadOffset[t3], t0
617     storei t0, PayloadOffset[t3, t1, 8]
618     loadi TagOffset[t3], t0
619     storei t0, TagOffset[t3, t1, 8]
620     addp 8, t3
621     bsubinz 1, t2, .copyLoop
622
623     // Fill new slots with JSUndefined
624     move t1, t2
625 .fillLoop:
626     move 0, t0
627     storei t0, PayloadOffset[t3, t1, 8]
628     move UndefinedTag, t0
629     storei t0, TagOffset[t3, t1, 8]
630     addp 8, t3
631     baddinz 1, t2, .fillLoop
632
633 .continue:
634     # Reload CodeBlock and PC, since the slow_path clobbered it.
635     loadp CodeBlock[cfr], t1
636     loadp CodeBlock::m_instructions[t1], PC
637     jmp doneLabel
638 end
639
640 macro branchIfException(label)
641     loadp Callee + PayloadOffset[cfr], t3
642     andp MarkedBlockMask, t3
643     loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t3], t3
644     btiz VM::m_exception[t3], .noException
645     jmp label
646 .noException:
647 end
648
649
650 # Instruction implementations
651
652 _llint_op_enter:
653     traceExecution()
654     checkStackPointerAlignment(t2, 0xdead00e1)
655     loadp CodeBlock[cfr], t2                // t2<CodeBlock> = cfr.CodeBlock
656     loadi CodeBlock::m_numVars[t2], t2      // t2<size_t> = t2<CodeBlock>.m_numVars
657     btiz t2, .opEnterDone
658     move UndefinedTag, t0
659     move 0, t1
660     negi t2
661 .opEnterLoop:
662     storei t0, TagOffset[cfr, t2, 8]
663     storei t1, PayloadOffset[cfr, t2, 8]
664     addi 1, t2
665     btinz t2, .opEnterLoop
666 .opEnterDone:
667     callSlowPath(_slow_path_enter)
668     dispatch(constexpr op_enter_length)
669
670
671 _llint_op_get_argument:
672     traceExecution()
673     loadisFromInstruction(1, t1)
674     loadisFromInstruction(2, t2)
675     loadi PayloadOffset + ArgumentCount[cfr], t0
676     bilteq t0, t2, .opGetArgumentOutOfBounds
677     loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0
678     loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t3
679     storei t0, TagOffset[cfr, t1, 8]
680     storei t3, PayloadOffset[cfr, t1, 8]
681     valueProfile(t0, t3, 12, t1)
682     dispatch(constexpr op_get_argument_length)
683
684 .opGetArgumentOutOfBounds:
685     storei UndefinedTag, TagOffset[cfr, t1, 8]
686     storei 0, PayloadOffset[cfr, t1, 8]
687     valueProfile(UndefinedTag, 0, 12, t1)
688     dispatch(constexpr op_get_argument_length)
689
690
691 _llint_op_argument_count:
692     traceExecution()
693     loadisFromInstruction(1, t2)
694     loadi PayloadOffset + ArgumentCount[cfr], t0
695     subi 1, t0
696     move Int32Tag, t1
697     storei t1, TagOffset[cfr, t2, 8]
698     storei t0, PayloadOffset[cfr, t2, 8]
699     dispatch(constexpr op_argument_count_length)
700
701
702 _llint_op_get_scope:
703     traceExecution()
704     loadi Callee + PayloadOffset[cfr], t0
705     loadi JSCallee::m_scope[t0], t0
706     loadisFromInstruction(1, t1)
707     storei CellTag, TagOffset[cfr, t1, 8]
708     storei t0, PayloadOffset[cfr, t1, 8]
709     dispatch(constexpr op_get_scope_length)
710
711
712 _llint_op_to_this:
713     traceExecution()
714     loadi 4[PC], t0
715     bineq TagOffset[cfr, t0, 8], CellTag, .opToThisSlow
716     loadi PayloadOffset[cfr, t0, 8], t0
717     bbneq JSCell::m_type[t0], FinalObjectType, .opToThisSlow
718     loadpFromInstruction(2, t2)
719     bpneq JSCell::m_structureID[t0], t2, .opToThisSlow
720     dispatch(constexpr op_to_this_length)
721
722 .opToThisSlow:
723     callSlowPath(_slow_path_to_this)
724     dispatch(constexpr op_to_this_length)
725
726
727 _llint_op_check_tdz:
728     traceExecution()
729     loadisFromInstruction(1, t0)
730     loadConstantOrVariableTag(t0, t1)
731     bineq t1, EmptyValueTag, .opNotTDZ
732     callSlowPath(_slow_path_throw_tdz_error)
733
734 .opNotTDZ:
735     dispatch(constexpr op_check_tdz_length)
736
737
738 _llint_op_mov:
739     traceExecution()
740     loadi 8[PC], t1
741     loadi 4[PC], t0
742     loadConstantOrVariable(t1, t2, t3)
743     storei t2, TagOffset[cfr, t0, 8]
744     storei t3, PayloadOffset[cfr, t0, 8]
745     dispatch(constexpr op_mov_length)
746
747
748 _llint_op_not:
749     traceExecution()
750     loadi 8[PC], t0
751     loadi 4[PC], t1
752     loadConstantOrVariable(t0, t2, t3)
753     bineq t2, BooleanTag, .opNotSlow
754     xori 1, t3
755     storei t2, TagOffset[cfr, t1, 8]
756     storei t3, PayloadOffset[cfr, t1, 8]
757     dispatch(constexpr op_not_length)
758
759 .opNotSlow:
760     callSlowPath(_slow_path_not)
761     dispatch(constexpr op_not_length)
762
763
764 macro equalityComparison(integerComparison, slowPath)
765     loadi 12[PC], t2
766     loadi 8[PC], t0
767     loadConstantOrVariable(t2, t3, t1)
768     loadConstantOrVariable2Reg(t0, t2, t0)
769     bineq t2, t3, .opEqSlow
770     bieq t2, CellTag, .opEqSlow
771     bib t2, LowestTag, .opEqSlow
772     loadi 4[PC], t2
773     integerComparison(t0, t1, t0)
774     storei BooleanTag, TagOffset[cfr, t2, 8]
775     storei t0, PayloadOffset[cfr, t2, 8]
776     dispatch(constexpr op_eq_length)
777
778 .opEqSlow:
779     callSlowPath(slowPath)
780     dispatch(constexpr op_eq_length)
781 end
782
783
784 macro equalityJump(integerComparison, slowPath)
785     loadi 8[PC], t2
786     loadi 4[PC], t0
787     loadConstantOrVariable(t2, t3, t1)
788     loadConstantOrVariable2Reg(t0, t2, t0)
789     bineq t2, t3, .slow
790     bieq t2, CellTag, .slow
791     bib t2, LowestTag, .slow
792     integerComparison(t0, t1, .jumpTarget)
793     dispatch(constexpr op_jeq_length)
794
795 .jumpTarget:
796     dispatchBranch(12[PC])
797
798 .slow:
799     callSlowPath(slowPath)
800     dispatch(0)
801 end
802
803
804 _llint_op_eq_null:
805     traceExecution()
806     loadi 8[PC], t0
807     loadi 4[PC], t3
808     assertNotConstant(t0)
809     loadi TagOffset[cfr, t0, 8], t1
810     loadi PayloadOffset[cfr, t0, 8], t0
811     bineq t1, CellTag, .opEqNullImmediate
812     btbnz JSCell::m_flags[t0], MasqueradesAsUndefined, .opEqNullMasqueradesAsUndefined
813     move 0, t1
814     jmp .opEqNullNotImmediate
815 .opEqNullMasqueradesAsUndefined:
816     loadp JSCell::m_structureID[t0], t1
817     loadp CodeBlock[cfr], t0
818     loadp CodeBlock::m_globalObject[t0], t0
819     cpeq Structure::m_globalObject[t1], t0, t1
820     jmp .opEqNullNotImmediate
821 .opEqNullImmediate:
822     cieq t1, NullTag, t2
823     cieq t1, UndefinedTag, t1
824     ori t2, t1
825 .opEqNullNotImmediate:
826     storei BooleanTag, TagOffset[cfr, t3, 8]
827     storei t1, PayloadOffset[cfr, t3, 8]
828     dispatch(constexpr op_eq_null_length)
829
830
831 _llint_op_neq_null:
832     traceExecution()
833     loadi 8[PC], t0
834     loadi 4[PC], t3
835     assertNotConstant(t0)
836     loadi TagOffset[cfr, t0, 8], t1
837     loadi PayloadOffset[cfr, t0, 8], t0
838     bineq t1, CellTag, .opNeqNullImmediate
839     btbnz JSCell::m_flags[t0], MasqueradesAsUndefined, .opNeqNullMasqueradesAsUndefined
840     move 1, t1
841     jmp .opNeqNullNotImmediate
842 .opNeqNullMasqueradesAsUndefined:
843     loadp JSCell::m_structureID[t0], t1
844     loadp CodeBlock[cfr], t0
845     loadp CodeBlock::m_globalObject[t0], t0
846     cpneq Structure::m_globalObject[t1], t0, t1
847     jmp .opNeqNullNotImmediate
848 .opNeqNullImmediate:
849     cineq t1, NullTag, t2
850     cineq t1, UndefinedTag, t1
851     andi t2, t1
852 .opNeqNullNotImmediate:
853     storei BooleanTag, TagOffset[cfr, t3, 8]
854     storei t1, PayloadOffset[cfr, t3, 8]
855     dispatch(constexpr op_neq_null_length)
856
857
858 macro strictEq(equalityOperation, slowPath)
859     loadi 12[PC], t2
860     loadi 8[PC], t0
861     loadConstantOrVariable(t2, t3, t1)
862     loadConstantOrVariable2Reg(t0, t2, t0)
863     bineq t2, t3, .slow
864     bib t2, LowestTag, .slow
865     bineq t2, CellTag, .notStringOrSymbol
866     bbaeq JSCell::m_type[t0], ObjectType, .notStringOrSymbol
867     bbb JSCell::m_type[t1], ObjectType, .slow
868 .notStringOrSymbol:
869     loadi 4[PC], t2
870     equalityOperation(t0, t1, t0)
871     storei BooleanTag, TagOffset[cfr, t2, 8]
872     storei t0, PayloadOffset[cfr, t2, 8]
873     dispatch(4)
874
875 .slow:
876     callSlowPath(slowPath)
877     dispatch(4)
878 end
879
880
881 macro strictEqualityJump(equalityOperation, slowPath)
882     loadi 8[PC], t2
883     loadi 4[PC], t0
884     loadConstantOrVariable(t2, t3, t1)
885     loadConstantOrVariable2Reg(t0, t2, t0)
886     bineq t2, t3, .slow
887     bib t2, LowestTag, .slow
888     bineq t2, CellTag, .notStringOrSymbol
889     bbaeq JSCell::m_type[t0], ObjectType, .notStringOrSymbol
890     bbb JSCell::m_type[t1], ObjectType, .slow
891 .notStringOrSymbol:
892     equalityOperation(t0, t1, .jumpTarget)
893     dispatch(constexpr op_jstricteq_length)
894
895 .jumpTarget:
896     dispatchBranch(12[PC])
897
898 .slow:
899     callSlowPath(slowPath)
900     dispatch(0)
901 end
902
903
904 _llint_op_stricteq:
905     traceExecution()
906     strictEq(macro (left, right, result) cieq left, right, result end, _slow_path_stricteq)
907
908
909 _llint_op_nstricteq:
910     traceExecution()
911     strictEq(macro (left, right, result) cineq left, right, result end, _slow_path_nstricteq)
912
913
914 _llint_op_jstricteq:
915     traceExecution()
916     strictEqualityJump(
917         macro (left, right, target) bieq left, right, target end,
918         _llint_slow_path_jstricteq)
919
920
921 _llint_op_jnstricteq:
922     traceExecution()
923     strictEqualityJump(
924         macro (left, right, target) bineq left, right, target end,
925         _llint_slow_path_jnstricteq)
926
927
928 _llint_op_inc:
929     traceExecution()
930     loadi 4[PC], t0
931     bineq TagOffset[cfr, t0, 8], Int32Tag, .opIncSlow
932     loadi PayloadOffset[cfr, t0, 8], t1
933     baddio 1, t1, .opIncSlow
934     storei t1, PayloadOffset[cfr, t0, 8]
935     dispatch(constexpr op_inc_length)
936
937 .opIncSlow:
938     callSlowPath(_slow_path_inc)
939     dispatch(constexpr op_inc_length)
940
941
942 _llint_op_dec:
943     traceExecution()
944     loadi 4[PC], t0
945     bineq TagOffset[cfr, t0, 8], Int32Tag, .opDecSlow
946     loadi PayloadOffset[cfr, t0, 8], t1
947     bsubio 1, t1, .opDecSlow
948     storei t1, PayloadOffset[cfr, t0, 8]
949     dispatch(constexpr op_dec_length)
950
951 .opDecSlow:
952     callSlowPath(_slow_path_dec)
953     dispatch(constexpr op_dec_length)
954
955
956 _llint_op_to_number:
957     traceExecution()
958     loadi 8[PC], t0
959     loadi 4[PC], t1
960     loadConstantOrVariable(t0, t2, t3)
961     bieq t2, Int32Tag, .opToNumberIsInt
962     biaeq t2, LowestTag, .opToNumberSlow
963 .opToNumberIsInt:
964     storei t2, TagOffset[cfr, t1, 8]
965     storei t3, PayloadOffset[cfr, t1, 8]
966     valueProfile(t2, t3, 12, t1)
967     dispatch(constexpr op_to_number_length)
968
969 .opToNumberSlow:
970     callSlowPath(_slow_path_to_number)
971     dispatch(constexpr op_to_number_length)
972
973
974 _llint_op_to_string:
975     traceExecution()
976     loadi 8[PC], t0
977     loadi 4[PC], t1
978     loadConstantOrVariable(t0, t2, t3)
979     bineq t2, CellTag, .opToStringSlow
980     bbneq JSCell::m_type[t3], StringType, .opToStringSlow
981 .opToStringIsString:
982     storei t2, TagOffset[cfr, t1, 8]
983     storei t3, PayloadOffset[cfr, t1, 8]
984     dispatch(constexpr op_to_string_length)
985
986 .opToStringSlow:
987     callSlowPath(_slow_path_to_string)
988     dispatch(constexpr op_to_string_length)
989
990
991 _llint_op_to_object:
992     traceExecution()
993     loadi 8[PC], t0
994     loadi 4[PC], t1
995     loadConstantOrVariable(t0, t2, t3)
996     bineq t2, CellTag, .opToObjectSlow
997     bbb JSCell::m_type[t3], ObjectType, .opToObjectSlow
998     storei t2, TagOffset[cfr, t1, 8]
999     storei t3, PayloadOffset[cfr, t1, 8]
1000     valueProfile(t2, t3, 16, t1)
1001     dispatch(constexpr op_to_object_length)
1002
1003 .opToObjectSlow:
1004     callSlowPath(_slow_path_to_object)
1005     dispatch(constexpr op_to_object_length)
1006
1007
1008 _llint_op_negate:
1009     traceExecution()
1010     loadi 8[PC], t0
1011     loadi 4[PC], t3
1012     loadConstantOrVariable(t0, t1, t2)
1013     loadisFromInstruction(3, t0)
1014     bineq t1, Int32Tag, .opNegateSrcNotInt
1015     btiz t2, 0x7fffffff, .opNegateSlow
1016     negi t2
1017     ori ArithProfileInt, t0
1018     storei Int32Tag, TagOffset[cfr, t3, 8]
1019     storeisToInstruction(t0, 3)
1020     storei t2, PayloadOffset[cfr, t3, 8]
1021     dispatch(constexpr op_negate_length)
1022 .opNegateSrcNotInt:
1023     bia t1, LowestTag, .opNegateSlow
1024     xori 0x80000000, t1
1025     ori ArithProfileNumber, t0
1026     storei t2, PayloadOffset[cfr, t3, 8]
1027     storeisToInstruction(t0, 3)
1028     storei t1, TagOffset[cfr, t3, 8]
1029     dispatch(constexpr op_negate_length)
1030
1031 .opNegateSlow:
1032     callSlowPath(_slow_path_negate)
1033     dispatch(constexpr op_negate_length)
1034
1035
1036 macro binaryOpCustomStore(integerOperationAndStore, doubleOperation, slowPath)
1037     loadi 12[PC], t2
1038     loadi 8[PC], t0
1039     loadConstantOrVariable(t2, t3, t1)
1040     loadConstantOrVariable2Reg(t0, t2, t0)
1041     bineq t2, Int32Tag, .op1NotInt
1042     bineq t3, Int32Tag, .op2NotInt
1043     loadisFromInstruction(4, t5)
1044     ori ArithProfileIntInt, t5
1045     storeisToInstruction(t5, 4)
1046     loadi 4[PC], t2
1047     integerOperationAndStore(t3, t1, t0, .slow, t2)
1048     dispatch(5)
1049
1050 .op1NotInt:
1051     # First operand is definitely not an int, the second operand could be anything.
1052     bia t2, LowestTag, .slow
1053     bib t3, LowestTag, .op1NotIntOp2Double
1054     bineq t3, Int32Tag, .slow
1055     loadisFromInstruction(4, t5)
1056     ori ArithProfileNumberInt, t5
1057     storeisToInstruction(t5, 4)
1058     ci2d t1, ft1
1059     jmp .op1NotIntReady
1060 .op1NotIntOp2Double:
1061     fii2d t1, t3, ft1
1062     loadisFromInstruction(4, t5)
1063     ori ArithProfileNumberNumber, t5
1064     storeisToInstruction(t5, 4)
1065 .op1NotIntReady:
1066     loadi 4[PC], t1
1067     fii2d t0, t2, ft0
1068     doubleOperation(ft1, ft0)
1069     stored ft0, [cfr, t1, 8]
1070     dispatch(5)
1071
1072 .op2NotInt:
1073     # First operand is definitely an int, the second operand is definitely not.
1074     loadi 4[PC], t2
1075     bia t3, LowestTag, .slow
1076     loadisFromInstruction(4, t5)
1077     ori ArithProfileIntNumber, t5
1078     storeisToInstruction(t5, 4)
1079     ci2d t0, ft0
1080     fii2d t1, t3, ft1
1081     doubleOperation(ft1, ft0)
1082     stored ft0, [cfr, t2, 8]
1083     dispatch(5)
1084
1085 .slow:
1086     callSlowPath(slowPath)
1087     dispatch(5)
1088 end
1089
1090 macro binaryOp(integerOperation, doubleOperation, slowPath)
1091     binaryOpCustomStore(
1092         macro (int32Tag, left, right, slow, index)
1093             integerOperation(left, right, slow)
1094             storei int32Tag, TagOffset[cfr, index, 8]
1095             storei right, PayloadOffset[cfr, index, 8]
1096         end,
1097         doubleOperation, slowPath)
1098 end
1099
1100 _llint_op_add:
1101     traceExecution()
1102     binaryOp(
1103         macro (left, right, slow) baddio left, right, slow end,
1104         macro (left, right) addd left, right end,
1105         _slow_path_add)
1106
1107
1108 _llint_op_mul:
1109     traceExecution()
1110     binaryOpCustomStore(
1111         macro (int32Tag, left, right, slow, index)
1112             const scratch = int32Tag   # We know that we can reuse the int32Tag register since it has a constant.
1113             move right, scratch
1114             bmulio left, scratch, slow
1115             btinz scratch, .done
1116             bilt left, 0, slow
1117             bilt right, 0, slow
1118         .done:
1119             storei Int32Tag, TagOffset[cfr, index, 8]
1120             storei scratch, PayloadOffset[cfr, index, 8]
1121         end,
1122         macro (left, right) muld left, right end,
1123         _slow_path_mul)
1124
1125
1126 _llint_op_sub:
1127     traceExecution()
1128     binaryOp(
1129         macro (left, right, slow) bsubio left, right, slow end,
1130         macro (left, right) subd left, right end,
1131         _slow_path_sub)
1132
1133
1134 _llint_op_div:
1135     traceExecution()
1136     binaryOpCustomStore(
1137         macro (int32Tag, left, right, slow, index)
1138             ci2d left, ft0
1139             ci2d right, ft1
1140             divd ft0, ft1
1141             bcd2i ft1, right, .notInt
1142             storei int32Tag, TagOffset[cfr, index, 8]
1143             storei right, PayloadOffset[cfr, index, 8]
1144             jmp .done
1145         .notInt:
1146             stored ft1, [cfr, index, 8]
1147         .done:
1148         end,
1149         macro (left, right) divd left, right end,
1150         _slow_path_div)
1151
1152
1153 macro bitOp(operation, slowPath, advance)
1154     loadi 12[PC], t2
1155     loadi 8[PC], t0
1156     loadConstantOrVariable(t2, t3, t1)
1157     loadConstantOrVariable2Reg(t0, t2, t0)
1158     bineq t3, Int32Tag, .slow
1159     bineq t2, Int32Tag, .slow
1160     loadi 4[PC], t2
1161     operation(t1, t0)
1162     storei t3, TagOffset[cfr, t2, 8]
1163     storei t0, PayloadOffset[cfr, t2, 8]
1164     dispatch(advance)
1165
1166 .slow:
1167     callSlowPath(slowPath)
1168     dispatch(advance)
1169 end
1170
1171 _llint_op_lshift:
1172     traceExecution()
1173     bitOp(
1174         macro (left, right) lshifti left, right end,
1175         _slow_path_lshift,
1176         constexpr op_lshift_length)
1177
1178
1179 _llint_op_rshift:
1180     traceExecution()
1181     bitOp(
1182         macro (left, right) rshifti left, right end,
1183         _slow_path_rshift,
1184         constexpr op_rshift_length)
1185
1186
1187 _llint_op_urshift:
1188     traceExecution()
1189     bitOp(
1190         macro (left, right) urshifti left, right end,
1191         _slow_path_urshift,
1192         constexpr op_urshift_length)
1193
1194
1195 _llint_op_unsigned:
1196     traceExecution()
1197     loadi 4[PC], t0
1198     loadi 8[PC], t1
1199     loadConstantOrVariablePayload(t1, Int32Tag, t2, .opUnsignedSlow)
1200     bilt t2, 0, .opUnsignedSlow
1201     storei t2, PayloadOffset[cfr, t0, 8]
1202     storei Int32Tag, TagOffset[cfr, t0, 8]
1203     dispatch(constexpr op_unsigned_length)
1204 .opUnsignedSlow:
1205     callSlowPath(_slow_path_unsigned)
1206     dispatch(constexpr op_unsigned_length)
1207
1208
1209 _llint_op_bitand:
1210     traceExecution()
1211     bitOp(
1212         macro (left, right) andi left, right end,
1213         _slow_path_bitand,
1214         constexpr op_bitand_length)
1215
1216
1217 _llint_op_bitxor:
1218     traceExecution()
1219     bitOp(
1220         macro (left, right) xori left, right end,
1221         _slow_path_bitxor,
1222         constexpr op_bitxor_length)
1223
1224
1225 _llint_op_bitor:
1226     traceExecution()
1227     bitOp(
1228         macro (left, right) ori left, right end,
1229         _slow_path_bitor,
1230         constexpr op_bitor_length)
1231
1232
1233 _llint_op_overrides_has_instance:
1234     traceExecution()
1235
1236     loadisFromStruct(OpOverridesHasInstance::m_dst, t3)
1237     storei BooleanTag, TagOffset[cfr, t3, 8]
1238
1239     # First check if hasInstanceValue is the one on Function.prototype[Symbol.hasInstance]
1240     loadisFromStruct(OpOverridesHasInstance::m_hasInstanceValue, t0)
1241     loadConstantOrVariablePayload(t0, CellTag, t2, .opOverrideshasInstanceValueNotCell)
1242     loadConstantOrVariable(t0, t1, t2)
1243     bineq t1, CellTag, .opOverrideshasInstanceValueNotCell
1244
1245     # We don't need hasInstanceValue's tag register anymore.
1246     loadp CodeBlock[cfr], t1
1247     loadp CodeBlock::m_globalObject[t1], t1
1248     loadp JSGlobalObject::m_functionProtoHasInstanceSymbolFunction[t1], t1
1249     bineq t1, t2, .opOverrideshasInstanceValueNotDefault
1250
1251     # We know the constructor is a cell.
1252     loadisFromStruct(OpOverridesHasInstance::m_constructor, t0)
1253     loadConstantOrVariablePayloadUnchecked(t0, t1)
1254     tbz JSCell::m_flags[t1], ImplementsDefaultHasInstance, t0
1255     storei t0, PayloadOffset[cfr, t3, 8]
1256     dispatch(constexpr op_overrides_has_instance_length)
1257
1258 .opOverrideshasInstanceValueNotCell:
1259 .opOverrideshasInstanceValueNotDefault:
1260     storei 1, PayloadOffset[cfr, t3, 8]
1261     dispatch(constexpr op_overrides_has_instance_length)
1262
1263 _llint_op_instanceof_custom:
1264     traceExecution()
1265     callSlowPath(_llint_slow_path_instanceof_custom)
1266     dispatch(constexpr op_instanceof_custom_length)
1267
1268
1269 _llint_op_is_empty:
1270     traceExecution()
1271     loadi 8[PC], t1
1272     loadi 4[PC], t0
1273     loadConstantOrVariable(t1, t2, t3)
1274     cieq t2, EmptyValueTag, t3
1275     storei BooleanTag, TagOffset[cfr, t0, 8]
1276     storei t3, PayloadOffset[cfr, t0, 8]
1277     dispatch(constexpr op_is_empty_length)
1278
1279
1280 _llint_op_is_undefined:
1281     traceExecution()
1282     loadi 8[PC], t1
1283     loadi 4[PC], t0
1284     loadConstantOrVariable(t1, t2, t3)
1285     storei BooleanTag, TagOffset[cfr, t0, 8]
1286     bieq t2, CellTag, .opIsUndefinedCell
1287     cieq t2, UndefinedTag, t3
1288     storei t3, PayloadOffset[cfr, t0, 8]
1289     dispatch(constexpr op_is_undefined_length)
1290 .opIsUndefinedCell:
1291     btbnz JSCell::m_flags[t3], MasqueradesAsUndefined, .opIsUndefinedMasqueradesAsUndefined
1292     move 0, t1
1293     storei t1, PayloadOffset[cfr, t0, 8]
1294     dispatch(constexpr op_is_undefined_length)
1295 .opIsUndefinedMasqueradesAsUndefined:
1296     loadp JSCell::m_structureID[t3], t1
1297     loadp CodeBlock[cfr], t3
1298     loadp CodeBlock::m_globalObject[t3], t3
1299     cpeq Structure::m_globalObject[t1], t3, t1
1300     storei t1, PayloadOffset[cfr, t0, 8]
1301     dispatch(constexpr op_is_undefined_length)
1302
1303
1304 _llint_op_is_boolean:
1305     traceExecution()
1306     loadi 8[PC], t1
1307     loadi 4[PC], t2
1308     loadConstantOrVariableTag(t1, t0)
1309     cieq t0, BooleanTag, t0
1310     storei BooleanTag, TagOffset[cfr, t2, 8]
1311     storei t0, PayloadOffset[cfr, t2, 8]
1312     dispatch(constexpr op_is_boolean_length)
1313
1314
1315 _llint_op_is_number:
1316     traceExecution()
1317     loadi 8[PC], t1
1318     loadi 4[PC], t2
1319     loadConstantOrVariableTag(t1, t0)
1320     storei BooleanTag, TagOffset[cfr, t2, 8]
1321     addi 1, t0
1322     cib t0, LowestTag + 1, t1
1323     storei t1, PayloadOffset[cfr, t2, 8]
1324     dispatch(constexpr op_is_number_length)
1325
1326
1327 _llint_op_is_cell_with_type:
1328     traceExecution()
1329     loadi 8[PC], t1
1330     loadi 4[PC], t2
1331     loadConstantOrVariable(t1, t0, t3)
1332     storei BooleanTag, TagOffset[cfr, t2, 8]
1333     bineq t0, CellTag, .notCellCase
1334     loadi 12[PC], t0
1335     cbeq JSCell::m_type[t3], t0, t1
1336     storei t1, PayloadOffset[cfr, t2, 8]
1337     dispatch(constexpr op_is_cell_with_type_length)
1338 .notCellCase:
1339     storep 0, PayloadOffset[cfr, t2, 8]
1340     dispatch(constexpr op_is_cell_with_type_length)
1341
1342
1343 _llint_op_is_object:
1344     traceExecution()
1345     loadi 8[PC], t1
1346     loadi 4[PC], t2
1347     loadConstantOrVariable(t1, t0, t3)
1348     storei BooleanTag, TagOffset[cfr, t2, 8]
1349     bineq t0, CellTag, .opIsObjectNotCell
1350     cbaeq JSCell::m_type[t3], ObjectType, t1
1351     storei t1, PayloadOffset[cfr, t2, 8]
1352     dispatch(constexpr op_is_object_length)
1353 .opIsObjectNotCell:
1354     storep 0, PayloadOffset[cfr, t2, 8]
1355     dispatch(constexpr op_is_object_length)
1356
1357
1358 macro loadPropertyAtVariableOffsetKnownNotInline(propertyOffset, objectAndStorage, tag, payload)
1359     assert(macro (ok) bigteq propertyOffset, firstOutOfLineOffset, ok end)
1360     negi propertyOffset
1361     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
1362     loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag
1363     loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload
1364 end
1365
1366 macro loadPropertyAtVariableOffset(propertyOffset, objectAndStorage, tag, payload)
1367     bilt propertyOffset, firstOutOfLineOffset, .isInline
1368     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
1369     negi propertyOffset
1370     jmp .ready
1371 .isInline:
1372     addp sizeof JSObject - (firstOutOfLineOffset - 2) * 8, objectAndStorage
1373 .ready:
1374     loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag
1375     loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload
1376 end
1377
1378 macro storePropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, tag, payload)
1379     bilt propertyOffsetAsInt, firstOutOfLineOffset, .isInline
1380     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
1381     negi propertyOffsetAsInt
1382     jmp .ready
1383 .isInline:
1384     addp sizeof JSObject - (firstOutOfLineOffset - 2) * 8, objectAndStorage
1385 .ready:
1386     storei tag, TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8]
1387     storei payload, PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8]
1388 end
1389
1390
1391 # We only do monomorphic get_by_id caching for now, and we do not modify the
1392 # opcode for own properties. We also allow for the cache to change anytime it fails,
1393 # since ping-ponging is free. At best we get lucky and the get_by_id will continue
1394 # to take fast path on the new cache. At worst we take slow path, which is what
1395 # we would have been doing anyway. For prototype/unset properties, we will attempt to
1396 # convert opcode into a get_by_id_proto_load/get_by_id_unset, respectively, after an
1397 # execution counter hits zero.
1398
1399 _llint_op_get_by_id_direct:
1400     traceExecution()
1401     loadi 8[PC], t0
1402     loadi 16[PC], t1
1403     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdDirectSlow)
1404     loadi 20[PC], t2
1405     bineq JSCell::m_structureID[t3], t1, .opGetByIdDirectSlow
1406     loadPropertyAtVariableOffset(t2, t3, t0, t1)
1407     loadi 4[PC], t2
1408     storei t0, TagOffset[cfr, t2, 8]
1409     storei t1, PayloadOffset[cfr, t2, 8]
1410     valueProfile(t0, t1, 24, t2)
1411     dispatch(constexpr op_get_by_id_direct_length)
1412
1413 .opGetByIdDirectSlow:
1414     callSlowPath(_llint_slow_path_get_by_id_direct)
1415     dispatch(constexpr op_get_by_id_direct_length)
1416
1417
1418 _llint_op_get_by_id:
1419     traceExecution()
1420     loadi 8[PC], t0
1421     loadi 16[PC], t1
1422     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow)
1423     loadi 20[PC], t2
1424     bineq JSCell::m_structureID[t3], t1, .opGetByIdSlow
1425     loadPropertyAtVariableOffset(t2, t3, t0, t1)
1426     loadi 4[PC], t2
1427     storei t0, TagOffset[cfr, t2, 8]
1428     storei t1, PayloadOffset[cfr, t2, 8]
1429     valueProfile(t0, t1, 32, t2)
1430     dispatch(constexpr op_get_by_id_length)
1431
1432 .opGetByIdSlow:
1433     callSlowPath(_llint_slow_path_get_by_id)
1434     dispatch(constexpr op_get_by_id_length)
1435
1436
1437 _llint_op_get_by_id_proto_load:
1438     traceExecution()
1439     loadi 8[PC], t0
1440     loadi 16[PC], t1
1441     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdProtoSlow)
1442     loadi 20[PC], t2
1443     bineq JSCell::m_structureID[t3], t1, .opGetByIdProtoSlow
1444     loadpFromInstruction(6, t3)
1445     loadPropertyAtVariableOffset(t2, t3, t0, t1)
1446     loadi 4[PC], t2
1447     storei t0, TagOffset[cfr, t2, 8]
1448     storei t1, PayloadOffset[cfr, t2, 8]
1449     valueProfile(t0, t1, 32, t2)
1450     dispatch(constexpr op_get_by_id_proto_load_length)
1451
1452 .opGetByIdProtoSlow:
1453     callSlowPath(_llint_slow_path_get_by_id)
1454     dispatch(constexpr op_get_by_id_proto_load_length)
1455
1456
1457 _llint_op_get_by_id_unset:
1458     traceExecution()
1459     loadi 8[PC], t0
1460     loadi 16[PC], t1
1461     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdUnsetSlow)
1462     bineq JSCell::m_structureID[t3], t1, .opGetByIdUnsetSlow
1463     loadi 4[PC], t2
1464     storei UndefinedTag, TagOffset[cfr, t2, 8]
1465     storei 0, PayloadOffset[cfr, t2, 8]
1466     valueProfile(UndefinedTag, 0, 32, t2)
1467     dispatch(constexpr op_get_by_id_unset_length)
1468
1469 .opGetByIdUnsetSlow:
1470     callSlowPath(_llint_slow_path_get_by_id)
1471     dispatch(constexpr op_get_by_id_unset_length)
1472
1473
1474 _llint_op_get_array_length:
1475     traceExecution()
1476     loadi 8[PC], t0
1477     loadp 16[PC], t1
1478     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetArrayLengthSlow)
1479     move t3, t2
1480     arrayProfile(t2, t1, t0)
1481     btiz t2, IsArray, .opGetArrayLengthSlow
1482     btiz t2, IndexingShapeMask, .opGetArrayLengthSlow
1483     loadi 4[PC], t1
1484     loadp JSObject::m_butterfly[t3], t0
1485     loadi -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], t0
1486     bilt t0, 0, .opGetArrayLengthSlow
1487     valueProfile(Int32Tag, t0, 32, t2)
1488     storep t0, PayloadOffset[cfr, t1, 8]
1489     storep Int32Tag, TagOffset[cfr, t1, 8]
1490     dispatch(constexpr op_get_array_length_length)
1491
1492 .opGetArrayLengthSlow:
1493     callSlowPath(_llint_slow_path_get_by_id)
1494     dispatch(constexpr op_get_array_length_length)
1495
1496
1497 _llint_op_put_by_id:
1498     traceExecution()
1499     writeBarrierOnOperands(1, 3)
1500     loadi 4[PC], t3
1501     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1502     loadi JSCell::m_structureID[t0], t2
1503     bineq t2, 16[PC], .opPutByIdSlow
1504
1505     # At this point, we have:
1506     # t2 -> currentStructureID
1507     # t0 -> object base
1508     # We will lose currentStructureID in the shenanigans below.
1509
1510     loadi 12[PC], t1
1511     loadConstantOrVariable(t1, t2, t3)
1512     loadi 32[PC], t1
1513
1514     # At this point, we have:
1515     # t0 -> object base
1516     # t1 -> put by id flags
1517     # t2 -> value tag
1518     # t3 -> value payload
1519
1520     btinz t1, PutByIdPrimaryTypeMask, .opPutByIdTypeCheckObjectWithStructureOrOther
1521
1522     # We have one of the non-structure type checks. Find out which one.
1523     andi PutByIdSecondaryTypeMask, t1
1524     bilt t1, PutByIdSecondaryTypeString, .opPutByIdTypeCheckLessThanString
1525
1526     # We are one of the following: String, Symbol, Object, ObjectOrOther, Top
1527     bilt t1, PutByIdSecondaryTypeObjectOrOther, .opPutByIdTypeCheckLessThanObjectOrOther
1528
1529     # We are either ObjectOrOther or Top.
1530     bieq t1, PutByIdSecondaryTypeTop, .opPutByIdDoneCheckingTypes
1531
1532     # Check if we are ObjectOrOther.
1533     bieq t2, CellTag, .opPutByIdTypeCheckObject
1534 .opPutByIdTypeCheckOther:
1535     bieq t2, NullTag, .opPutByIdDoneCheckingTypes
1536     bieq t2, UndefinedTag, .opPutByIdDoneCheckingTypes
1537     jmp .opPutByIdSlow
1538
1539 .opPutByIdTypeCheckLessThanObjectOrOther:
1540     # We are either String, Symbol or Object.
1541     bineq t2, CellTag, .opPutByIdSlow
1542     bieq t1, PutByIdSecondaryTypeObject, .opPutByIdTypeCheckObject
1543     bieq t1, PutByIdSecondaryTypeSymbol, .opPutByIdTypeCheckSymbol
1544     bbeq JSCell::m_type[t3], StringType, .opPutByIdDoneCheckingTypes
1545     jmp .opPutByIdSlow
1546 .opPutByIdTypeCheckObject:
1547     bbaeq JSCell::m_type[t3], ObjectType, .opPutByIdDoneCheckingTypes
1548     jmp .opPutByIdSlow
1549 .opPutByIdTypeCheckSymbol:
1550     bbeq JSCell::m_type[t3], SymbolType, .opPutByIdDoneCheckingTypes
1551     jmp .opPutByIdSlow
1552
1553 .opPutByIdTypeCheckLessThanString:
1554     # We are one of the following: Bottom, Boolean, Other, Int32, Number.
1555     bilt t1, PutByIdSecondaryTypeInt32, .opPutByIdTypeCheckLessThanInt32
1556
1557     # We are either Int32 or Number.
1558     bieq t1, PutByIdSecondaryTypeNumber, .opPutByIdTypeCheckNumber
1559
1560     bieq t2, Int32Tag, .opPutByIdDoneCheckingTypes
1561     jmp .opPutByIdSlow
1562
1563 .opPutByIdTypeCheckNumber:
1564     bib t2, LowestTag + 1, .opPutByIdDoneCheckingTypes
1565     jmp .opPutByIdSlow
1566
1567 .opPutByIdTypeCheckLessThanInt32:
1568     # We are one of the following: Bottom, Boolean, Other
1569     bineq t1, PutByIdSecondaryTypeBoolean, .opPutByIdTypeCheckBottomOrOther
1570     bieq t2, BooleanTag, .opPutByIdDoneCheckingTypes
1571     jmp .opPutByIdSlow
1572
1573 .opPutByIdTypeCheckBottomOrOther:
1574     bieq t1, PutByIdSecondaryTypeOther, .opPutByIdTypeCheckOther
1575     jmp .opPutByIdSlow
1576
1577 .opPutByIdTypeCheckObjectWithStructureOrOther:
1578     bieq t2, CellTag, .opPutByIdTypeCheckObjectWithStructure
1579     btinz t1, PutByIdPrimaryTypeObjectWithStructureOrOther, .opPutByIdTypeCheckOther
1580     jmp .opPutByIdSlow
1581
1582 .opPutByIdTypeCheckObjectWithStructure:
1583     andi PutByIdSecondaryTypeMask, t1
1584     bineq t1, JSCell::m_structureID[t3], .opPutByIdSlow
1585
1586 .opPutByIdDoneCheckingTypes:
1587     loadi 24[PC], t1
1588
1589     btiz t1, .opPutByIdNotTransition
1590
1591     # This is the transition case. t1 holds the new Structure*. If we have a chain, we need to
1592     # check it. t0 is the base. We may clobber t1 to use it as scratch.
1593     loadp 28[PC], t3
1594     btpz t3, .opPutByIdTransitionDirect
1595
1596     loadi 16[PC], t2 # Need old structure again.
1597     loadp StructureChain::m_vector[t3], t3
1598     assert(macro (ok) btpnz t3, ok end)
1599
1600     loadp Structure::m_prototype[t2], t2
1601     btpz t2, .opPutByIdTransitionChainDone
1602 .opPutByIdTransitionChainLoop:
1603     loadp [t3], t1
1604     bpneq t1, JSCell::m_structureID[t2], .opPutByIdSlow
1605     addp 4, t3
1606     loadp Structure::m_prototype[t1], t2
1607     btpnz t2, .opPutByIdTransitionChainLoop
1608
1609 .opPutByIdTransitionChainDone:
1610     loadi 24[PC], t1
1611
1612 .opPutByIdTransitionDirect:
1613     storei t1, JSCell::m_structureID[t0]
1614     loadi 12[PC], t1
1615     loadConstantOrVariable(t1, t2, t3)
1616     loadi 20[PC], t1
1617     storePropertyAtVariableOffset(t1, t0, t2, t3)
1618     writeBarrierOnOperand(1)
1619     dispatch(constexpr op_put_by_id_length)
1620
1621 .opPutByIdNotTransition:
1622     # The only thing live right now is t0, which holds the base.
1623     loadi 12[PC], t1
1624     loadConstantOrVariable(t1, t2, t3)
1625     loadi 20[PC], t1
1626     storePropertyAtVariableOffset(t1, t0, t2, t3)
1627     dispatch(constexpr op_put_by_id_length)
1628
1629 .opPutByIdSlow:
1630     callSlowPath(_llint_slow_path_put_by_id)
1631     dispatch(constexpr op_put_by_id_length)
1632
1633
1634 _llint_op_get_by_val:
1635     traceExecution()
1636     loadi 8[PC], t2
1637     loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow)
1638     move t0, t2
1639     loadp 16[PC], t3
1640     arrayProfile(t2, t3, t1)
1641     loadi 12[PC], t3
1642     loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
1643     loadp JSObject::m_butterfly[t0], t3
1644     andi IndexingShapeMask, t2
1645     bieq t2, Int32Shape, .opGetByValIsContiguous
1646     bineq t2, ContiguousShape, .opGetByValNotContiguous
1647
1648 .opGetByValIsContiguous:
1649     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValSlow
1650     loadi TagOffset[t3, t1, 8], t2
1651     loadi PayloadOffset[t3, t1, 8], t1
1652     jmp .opGetByValDone
1653
1654 .opGetByValNotContiguous:
1655     bineq t2, DoubleShape, .opGetByValNotDouble
1656     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValSlow
1657     loadd [t3, t1, 8], ft0
1658     bdnequn ft0, ft0, .opGetByValSlow
1659     # FIXME: This could be massively optimized.
1660     fd2ii ft0, t1, t2
1661     loadi 4[PC], t0
1662     jmp .opGetByValNotEmpty
1663
1664 .opGetByValNotDouble:
1665     subi ArrayStorageShape, t2
1666     bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow
1667     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t3], .opGetByValSlow
1668     loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2
1669     loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1
1670
1671 .opGetByValDone:
1672     loadi 4[PC], t0
1673     bieq t2, EmptyValueTag, .opGetByValSlow
1674 .opGetByValNotEmpty:
1675     storei t2, TagOffset[cfr, t0, 8]
1676     storei t1, PayloadOffset[cfr, t0, 8]
1677     valueProfile(t2, t1, 20, t0)
1678     dispatch(constexpr op_get_by_val_length)
1679
1680 .opGetByValSlow:
1681     callSlowPath(_llint_slow_path_get_by_val)
1682     dispatch(constexpr op_get_by_val_length)
1683
1684
1685 macro contiguousPutByVal(storeCallback)
1686     biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .outOfBounds
1687 .storeResult:
1688     loadi 12[PC], t2
1689     storeCallback(t2, t1, t0, t3)
1690     dispatch(5)
1691
1692 .outOfBounds:
1693     biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t0], .opPutByValOutOfBounds
1694     loadp 16[PC], t2
1695     storeb 1, ArrayProfile::m_mayStoreToHole[t2]
1696     addi 1, t3, t2
1697     storei t2, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0]
1698     jmp .storeResult
1699 end
1700
1701 macro putByVal(slowPath)
1702     traceExecution()
1703     writeBarrierOnOperands(1, 3)
1704     loadi 4[PC], t0
1705     loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
1706     move t1, t2
1707     loadp 16[PC], t3
1708     arrayProfile(t2, t3, t0)
1709     loadi 8[PC], t0
1710     loadConstantOrVariablePayload(t0, Int32Tag, t3, .opPutByValSlow)
1711     loadp JSObject::m_butterfly[t1], t0
1712     btinz t2, CopyOnWrite, .opPutByValSlow
1713     andi IndexingShapeMask, t2
1714     bineq t2, Int32Shape, .opPutByValNotInt32
1715     contiguousPutByVal(
1716         macro (operand, scratch, base, index)
1717             loadConstantOrVariablePayload(operand, Int32Tag, scratch, .opPutByValSlow)
1718             storei Int32Tag, TagOffset[base, index, 8]
1719             storei scratch, PayloadOffset[base, index, 8]
1720         end)
1721
1722 .opPutByValNotInt32:
1723     bineq t2, DoubleShape, .opPutByValNotDouble
1724     contiguousPutByVal(
1725         macro (operand, scratch, base, index)
1726             const tag = scratch
1727             const payload = operand
1728             loadConstantOrVariable2Reg(operand, tag, payload)
1729             bineq tag, Int32Tag, .notInt
1730             ci2d payload, ft0
1731             jmp .ready
1732         .notInt:
1733             fii2d payload, tag, ft0
1734             bdnequn ft0, ft0, .opPutByValSlow
1735         .ready:
1736             stored ft0, [base, index, 8]
1737         end)
1738
1739 .opPutByValNotDouble:
1740     bineq t2, ContiguousShape, .opPutByValNotContiguous
1741     contiguousPutByVal(
1742         macro (operand, scratch, base, index)
1743             const tag = scratch
1744             const payload = operand
1745             loadConstantOrVariable2Reg(operand, tag, payload)
1746             storei tag, TagOffset[base, index, 8]
1747             storei payload, PayloadOffset[base, index, 8]
1748         end)
1749
1750 .opPutByValNotContiguous:
1751     bineq t2, ArrayStorageShape, .opPutByValSlow
1752     biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t0], .opPutByValOutOfBounds
1753     bieq ArrayStorage::m_vector + TagOffset[t0, t3, 8], EmptyValueTag, .opPutByValArrayStorageEmpty
1754 .opPutByValArrayStorageStoreResult:
1755     loadi 12[PC], t2
1756     loadConstantOrVariable2Reg(t2, t1, t2)
1757     storei t1, ArrayStorage::m_vector + TagOffset[t0, t3, 8]
1758     storei t2, ArrayStorage::m_vector + PayloadOffset[t0, t3, 8]
1759     dispatch(5)
1760
1761 .opPutByValArrayStorageEmpty:
1762     loadp 16[PC], t1
1763     storeb 1, ArrayProfile::m_mayStoreToHole[t1]
1764     addi 1, ArrayStorage::m_numValuesInVector[t0]
1765     bib t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .opPutByValArrayStorageStoreResult
1766     addi 1, t3, t1
1767     storei t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0]
1768     jmp .opPutByValArrayStorageStoreResult
1769
1770 .opPutByValOutOfBounds:
1771     loadpFromInstruction(4, t0)
1772     storeb 1, ArrayProfile::m_outOfBounds[t0]
1773 .opPutByValSlow:
1774     callSlowPath(slowPath)
1775     dispatch(5)
1776 end
1777
1778 _llint_op_put_by_val:
1779     putByVal(_llint_slow_path_put_by_val)
1780
1781 _llint_op_put_by_val_direct:
1782     putByVal(_llint_slow_path_put_by_val_direct)
1783
1784 _llint_op_jmp:
1785     traceExecution()
1786     dispatchBranch(4[PC])
1787
1788
1789 macro jumpTrueOrFalse(conditionOp, slow)
1790     loadi 4[PC], t1
1791     loadConstantOrVariablePayload(t1, BooleanTag, t0, .slow)
1792     conditionOp(t0, .target)
1793     dispatch(3)
1794
1795 .target:
1796     dispatchBranch(8[PC])
1797
1798 .slow:
1799     callSlowPath(slow)
1800     dispatch(0)
1801 end
1802
1803
1804 macro equalNull(cellHandler, immediateHandler)
1805     loadi 4[PC], t0
1806     assertNotConstant(t0)
1807     loadi TagOffset[cfr, t0, 8], t1
1808     loadi PayloadOffset[cfr, t0, 8], t0
1809     bineq t1, CellTag, .immediate
1810     loadp JSCell::m_structureID[t0], t2
1811     cellHandler(t2, JSCell::m_flags[t0], .target)
1812     dispatch(3)
1813
1814 .target:
1815     dispatchBranch(8[PC])
1816
1817 .immediate:
1818     ori 1, t1
1819     immediateHandler(t1, .target)
1820     dispatch(3)
1821 end
1822
1823 _llint_op_jeq_null:
1824     traceExecution()
1825     equalNull(
1826         macro (structure, value, target) 
1827             btbz value, MasqueradesAsUndefined, .opJeqNullNotMasqueradesAsUndefined
1828             loadp CodeBlock[cfr], t0
1829             loadp CodeBlock::m_globalObject[t0], t0
1830             bpeq Structure::m_globalObject[structure], t0, target
1831 .opJeqNullNotMasqueradesAsUndefined:
1832         end,
1833         macro (value, target) bieq value, NullTag, target end)
1834     
1835
1836 _llint_op_jneq_null:
1837     traceExecution()
1838     equalNull(
1839         macro (structure, value, target) 
1840             btbz value, MasqueradesAsUndefined, target 
1841             loadp CodeBlock[cfr], t0
1842             loadp CodeBlock::m_globalObject[t0], t0
1843             bpneq Structure::m_globalObject[structure], t0, target
1844         end,
1845         macro (value, target) bineq value, NullTag, target end)
1846
1847
1848 _llint_op_jneq_ptr:
1849     traceExecution()
1850     loadi 4[PC], t0
1851     loadi 8[PC], t1
1852     loadp CodeBlock[cfr], t2
1853     loadp CodeBlock::m_globalObject[t2], t2
1854     bineq TagOffset[cfr, t0, 8], CellTag, .opJneqPtrBranch
1855     loadp JSGlobalObject::m_specialPointers[t2, t1, 4], t1
1856     bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough
1857 .opJneqPtrBranch:
1858     storei 1, 16[PC]
1859     dispatchBranch(12[PC])
1860 .opJneqPtrFallThrough:
1861     dispatch(constexpr op_jneq_ptr_length)
1862
1863
1864 macro compareUnsignedJump(integerCompare)
1865     loadi 4[PC], t2
1866     loadi 8[PC], t3
1867     loadConstantOrVariable(t2, t0, t1)
1868     loadConstantOrVariable2Reg(t3, t2, t3)
1869     integerCompare(t1, t3, .jumpTarget)
1870     dispatch(4)
1871
1872 .jumpTarget:
1873     dispatchBranch(12[PC])
1874 end
1875
1876
1877 macro compareUnsigned(integerCompareAndSet)
1878     loadi 12[PC], t2
1879     loadi 8[PC], t0
1880     loadConstantOrVariable(t2, t3, t1)
1881     loadConstantOrVariable2Reg(t0, t2, t0)
1882     integerCompareAndSet(t0, t1, t0)
1883     loadi 4[PC], t2
1884     storei BooleanTag, TagOffset[cfr, t2, 8]
1885     storei t0, PayloadOffset[cfr, t2, 8]
1886     dispatch(4)
1887 end
1888
1889
1890 macro compareJump(integerCompare, doubleCompare, slowPath)
1891     loadi 4[PC], t2
1892     loadi 8[PC], t3
1893     loadConstantOrVariable(t2, t0, t1)
1894     loadConstantOrVariable2Reg(t3, t2, t3)
1895     bineq t0, Int32Tag, .op1NotInt
1896     bineq t2, Int32Tag, .op2NotInt
1897     integerCompare(t1, t3, .jumpTarget)
1898     dispatch(4)
1899
1900 .op1NotInt:
1901     bia t0, LowestTag, .slow
1902     bib t2, LowestTag, .op1NotIntOp2Double
1903     bineq t2, Int32Tag, .slow
1904     ci2d t3, ft1
1905     jmp .op1NotIntReady
1906 .op1NotIntOp2Double:
1907     fii2d t3, t2, ft1
1908 .op1NotIntReady:
1909     fii2d t1, t0, ft0
1910     doubleCompare(ft0, ft1, .jumpTarget)
1911     dispatch(4)
1912
1913 .op2NotInt:
1914     ci2d t1, ft0
1915     bia t2, LowestTag, .slow
1916     fii2d t3, t2, ft1
1917     doubleCompare(ft0, ft1, .jumpTarget)
1918     dispatch(4)
1919
1920 .jumpTarget:
1921     dispatchBranch(12[PC])
1922
1923 .slow:
1924     callSlowPath(slowPath)
1925     dispatch(0)
1926 end
1927
1928
1929 _llint_op_switch_imm:
1930     traceExecution()
1931     loadi 12[PC], t2
1932     loadi 4[PC], t3
1933     loadConstantOrVariable(t2, t1, t0)
1934     loadp CodeBlock[cfr], t2
1935     loadp CodeBlock::m_rareData[t2], t2
1936     muli sizeof SimpleJumpTable, t3   # FIXME: would be nice to peephole this!
1937     loadp CodeBlock::RareData::m_switchJumpTables + VectorBufferOffset[t2], t2
1938     addp t3, t2
1939     bineq t1, Int32Tag, .opSwitchImmNotInt
1940     subi SimpleJumpTable::min[t2], t0
1941     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchImmFallThrough
1942     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t3
1943     loadi [t3, t0, 4], t1
1944     btiz t1, .opSwitchImmFallThrough
1945     dispatchBranchWithOffset(t1)
1946
1947 .opSwitchImmNotInt:
1948     bib t1, LowestTag, .opSwitchImmSlow  # Go to slow path if it's a double.
1949 .opSwitchImmFallThrough:
1950     dispatchBranch(8[PC])
1951
1952 .opSwitchImmSlow:
1953     callSlowPath(_llint_slow_path_switch_imm)
1954     dispatch(0)
1955
1956
1957 _llint_op_switch_char:
1958     traceExecution()
1959     loadi 12[PC], t2
1960     loadi 4[PC], t3
1961     loadConstantOrVariable(t2, t1, t0)
1962     loadp CodeBlock[cfr], t2
1963     loadp CodeBlock::m_rareData[t2], t2
1964     muli sizeof SimpleJumpTable, t3
1965     loadp CodeBlock::RareData::m_switchJumpTables + VectorBufferOffset[t2], t2
1966     addp t3, t2
1967     bineq t1, CellTag, .opSwitchCharFallThrough
1968     bbneq JSCell::m_type[t0], StringType, .opSwitchCharFallThrough
1969     bineq JSString::m_length[t0], 1, .opSwitchCharFallThrough
1970     loadp JSString::m_value[t0], t0
1971     btpz  t0, .opSwitchOnRope
1972     loadp StringImpl::m_data8[t0], t1
1973     btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
1974     loadh [t1], t0
1975     jmp .opSwitchCharReady
1976 .opSwitchChar8Bit:
1977     loadb [t1], t0
1978 .opSwitchCharReady:
1979     subi SimpleJumpTable::min[t2], t0
1980     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchCharFallThrough
1981     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t2
1982     loadi [t2, t0, 4], t1
1983     btiz t1, .opSwitchCharFallThrough
1984     dispatchBranchWithOffset(t1)
1985
1986 .opSwitchCharFallThrough:
1987     dispatchBranch(8[PC])
1988
1989 .opSwitchOnRope:
1990     callSlowPath(_llint_slow_path_switch_char)
1991     dispatch(0)
1992
1993
1994 macro arrayProfileForCall()
1995     loadi 16[PC], t3
1996     negi t3
1997     bineq ThisArgumentOffset + TagOffset[cfr, t3, 8], CellTag, .done
1998     loadi ThisArgumentOffset + PayloadOffset[cfr, t3, 8], t0
1999     loadp JSCell::m_structureID[t0], t0
2000     loadpFromInstruction(CallOpCodeSize - 2, t1)
2001     storep t0, ArrayProfile::m_lastSeenStructureID[t1]
2002 .done:
2003 end
2004
2005 macro doCall(slowPath, prepareCall)
2006     loadi 8[PC], t0
2007     loadi 20[PC], t1
2008     loadp LLIntCallLinkInfo::callee[t1], t2
2009     loadConstantOrVariablePayload(t0, CellTag, t3, .opCallSlow)
2010     bineq t3, t2, .opCallSlow
2011     loadi 16[PC], t3
2012     lshifti 3, t3
2013     negi t3
2014     addp cfr, t3  # t3 contains the new value of cfr
2015     storei t2, Callee + PayloadOffset[t3]
2016     loadi 12[PC], t2
2017     storei PC, ArgumentCount + TagOffset[cfr]
2018     storei t2, ArgumentCount + PayloadOffset[t3]
2019     storei CellTag, Callee + TagOffset[t3]
2020     move t3, sp
2021     prepareCall(LLIntCallLinkInfo::machineCodeTarget[t1], t2, t3, t4, JSEntryPtrTag)
2022     callTargetFunction(LLIntCallLinkInfo::machineCodeTarget[t1], JSEntryPtrTag)
2023
2024 .opCallSlow:
2025     slowPathForCall(slowPath, prepareCall)
2026 end
2027
2028 _llint_op_ret:
2029     traceExecution()
2030     checkSwitchToJITForEpilogue()
2031     loadi 4[PC], t2
2032     loadConstantOrVariable(t2, t1, t0)
2033     doReturn()
2034
2035
2036 _llint_op_to_primitive:
2037     traceExecution()
2038     loadi 8[PC], t2
2039     loadi 4[PC], t3
2040     loadConstantOrVariable(t2, t1, t0)
2041     bineq t1, CellTag, .opToPrimitiveIsImm
2042     bbaeq JSCell::m_type[t0], ObjectType, .opToPrimitiveSlowCase
2043 .opToPrimitiveIsImm:
2044     storei t1, TagOffset[cfr, t3, 8]
2045     storei t0, PayloadOffset[cfr, t3, 8]
2046     dispatch(constexpr op_to_primitive_length)
2047
2048 .opToPrimitiveSlowCase:
2049     callSlowPath(_slow_path_to_primitive)
2050     dispatch(constexpr op_to_primitive_length)
2051
2052
2053 _llint_op_catch:
2054     # This is where we end up from the JIT's throw trampoline (because the
2055     # machine code return address will be set to _llint_op_catch), and from
2056     # the interpreter's throw trampoline (see _llint_throw_trampoline).
2057     # The throwing code must have known that we were throwing to the interpreter,
2058     # and have set VM::targetInterpreterPCForThrow.
2059     loadp Callee + PayloadOffset[cfr], t3
2060     andp MarkedBlockMask, t3
2061     loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t3], t3
2062     restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer(t3, t0)
2063     loadp VM::callFrameForCatch[t3], cfr
2064     storep 0, VM::callFrameForCatch[t3]
2065     restoreStackPointerAfterCall()
2066
2067     loadi VM::targetInterpreterPCForThrow[t3], PC
2068
2069     callSlowPath(_llint_slow_path_check_if_exception_is_uncatchable_and_notify_profiler)
2070     bpeq r1, 0, .isCatchableException
2071     jmp _llint_throw_from_slow_path_trampoline
2072
2073 .isCatchableException:
2074     loadp Callee + PayloadOffset[cfr], t3
2075     andp MarkedBlockMask, t3
2076     loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t3], t3
2077
2078     loadi VM::m_exception[t3], t0
2079     storei 0, VM::m_exception[t3]
2080     loadi 4[PC], t2
2081     storei t0, PayloadOffset[cfr, t2, 8]
2082     storei CellTag, TagOffset[cfr, t2, 8]
2083
2084     loadi Exception::m_value + TagOffset[t0], t1
2085     loadi Exception::m_value + PayloadOffset[t0], t0
2086     loadi 8[PC], t2
2087     storei t0, PayloadOffset[cfr, t2, 8]
2088     storei t1, TagOffset[cfr, t2, 8]
2089
2090     traceExecution()  # This needs to be here because we don't want to clobber t0, t1, t2, t3 above.
2091
2092     callSlowPath(_llint_slow_path_profile_catch)
2093
2094     dispatch(constexpr op_catch_length)
2095
2096 _llint_op_end:
2097     traceExecution()
2098     checkSwitchToJITForEpilogue()
2099     loadi 4[PC], t0
2100     assertNotConstant(t0)
2101     loadi TagOffset[cfr, t0, 8], t1
2102     loadi PayloadOffset[cfr, t0, 8], t0
2103     doReturn()
2104
2105
2106 _llint_throw_from_slow_path_trampoline:
2107     callSlowPath(_llint_slow_path_handle_exception)
2108
2109     # When throwing from the interpreter (i.e. throwing from LLIntSlowPaths), so
2110     # the throw target is not necessarily interpreted code, we come to here.
2111     # This essentially emulates the JIT's throwing protocol.
2112     loadp Callee[cfr], t1
2113     andp MarkedBlockMask, t1
2114     loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t1], t1
2115     copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(t1, t2)
2116     jmp VM::targetMachinePCForThrow[t1]
2117
2118
2119 _llint_throw_during_call_trampoline:
2120     preserveReturnAddressAfterCall(t2)
2121     jmp _llint_throw_from_slow_path_trampoline
2122
2123
2124 macro nativeCallTrampoline(executableOffsetToFunction)
2125
2126     functionPrologue()
2127     storep 0, CodeBlock[cfr]
2128     loadi Callee + PayloadOffset[cfr], t1
2129     // Callee is still in t1 for code below
2130     if X86 or X86_WIN
2131         subp 8, sp # align stack pointer
2132         andp MarkedBlockMask, t1
2133         loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t1], t3
2134         storep cfr, VM::topCallFrame[t3]
2135         move cfr, a0  # a0 = ecx
2136         storep a0, [sp]
2137         loadi Callee + PayloadOffset[cfr], t1
2138         loadp JSFunction::m_executable[t1], t1
2139         checkStackPointerAlignment(t3, 0xdead0001)
2140         call executableOffsetToFunction[t1]
2141         loadp Callee + PayloadOffset[cfr], t3
2142         andp MarkedBlockMask, t3
2143         loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t3], t3
2144         addp 8, sp
2145     elsif ARM or ARMv7 or ARMv7_TRADITIONAL or C_LOOP or MIPS
2146         if MIPS
2147         # calling convention says to save stack space for 4 first registers in
2148         # all cases. To match our 16-byte alignment, that means we need to
2149         # take 24 bytes
2150             subp 24, sp
2151         else
2152             subp 8, sp # align stack pointer
2153         end
2154         # t1 already contains the Callee.
2155         andp MarkedBlockMask, t1
2156         loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t1], t1
2157         storep cfr, VM::topCallFrame[t1]
2158         move cfr, a0
2159         loadi Callee + PayloadOffset[cfr], t1
2160         loadp JSFunction::m_executable[t1], t1
2161         checkStackPointerAlignment(t3, 0xdead0001)
2162         if C_LOOP
2163             cloopCallNative executableOffsetToFunction[t1]
2164         else
2165             call executableOffsetToFunction[t1]
2166         end
2167         loadp Callee + PayloadOffset[cfr], t3
2168         andp MarkedBlockMask, t3
2169         loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t3], t3
2170         if MIPS
2171             addp 24, sp
2172         else
2173             addp 8, sp
2174         end
2175     else
2176         error
2177     end
2178     
2179     btinz VM::m_exception[t3], .handleException
2180
2181     functionEpilogue()
2182     ret
2183
2184 .handleException:
2185 if X86 or X86_WIN
2186     subp 8, sp # align stack pointer
2187 end
2188     storep cfr, VM::topCallFrame[t3]
2189     jmp _llint_throw_from_slow_path_trampoline
2190 end
2191
2192
2193 macro internalFunctionCallTrampoline(offsetOfFunction)
2194     functionPrologue()
2195     storep 0, CodeBlock[cfr]
2196     loadi Callee + PayloadOffset[cfr], t1
2197     // Callee is still in t1 for code below
2198     if X86 or X86_WIN
2199         subp 8, sp # align stack pointer
2200         andp MarkedBlockMask, t1
2201         loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t1], t3
2202         storep cfr, VM::topCallFrame[t3]
2203         move cfr, a0  # a0 = ecx
2204         storep a0, [sp]
2205         loadi Callee + PayloadOffset[cfr], t1
2206         checkStackPointerAlignment(t3, 0xdead0001)
2207         call offsetOfFunction[t1]
2208         loadp Callee + PayloadOffset[cfr], t3
2209         andp MarkedBlockMask, t3
2210         loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t3], t3
2211         addp 8, sp
2212     elsif ARM or ARMv7 or ARMv7_TRADITIONAL or C_LOOP or MIPS
2213         subp 8, sp # align stack pointer
2214         # t1 already contains the Callee.
2215         andp MarkedBlockMask, t1
2216         loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t1], t1
2217         storep cfr, VM::topCallFrame[t1]
2218         move cfr, a0
2219         loadi Callee + PayloadOffset[cfr], t1
2220         checkStackPointerAlignment(t3, 0xdead0001)
2221         if C_LOOP
2222             cloopCallNative offsetOfFunction[t1]
2223         else
2224             call offsetOfFunction[t1]
2225         end
2226         loadp Callee + PayloadOffset[cfr], t3
2227         andp MarkedBlockMask, t3
2228         loadp MarkedBlockFooterOffset + MarkedBlock::Footer::m_vm[t3], t3
2229         addp 8, sp
2230     else
2231         error
2232     end
2233
2234     btinz VM::m_exception[t3], .handleException
2235
2236     functionEpilogue()
2237     ret
2238
2239 .handleException:
2240 if X86 or X86_WIN
2241     subp 8, sp # align stack pointer
2242 end
2243     storep cfr, VM::topCallFrame[t3]
2244     jmp _llint_throw_from_slow_path_trampoline
2245 end
2246
2247
2248 macro getConstantScope(dst)
2249     loadpFromInstruction(6, t0)
2250     loadisFromInstruction(dst, t1)
2251     storei CellTag, TagOffset[cfr, t1, 8]
2252     storei t0, PayloadOffset[cfr, t1, 8]
2253 end
2254
2255 macro varInjectionCheck(slowPath)
2256     loadp CodeBlock[cfr], t0
2257     loadp CodeBlock::m_globalObject[t0], t0
2258     loadp JSGlobalObject::m_varInjectionWatchpoint[t0], t0
2259     bbeq WatchpointSet::m_state[t0], IsInvalidated, slowPath
2260 end
2261
2262 macro resolveScope()
2263     loadp CodeBlock[cfr], t0
2264     loadisFromInstruction(5, t2)
2265
2266     loadisFromInstruction(2, t0)
2267     loadp PayloadOffset[cfr, t0, 8], t0
2268     btiz t2, .resolveScopeLoopEnd
2269
2270 .resolveScopeLoop:
2271     loadp JSScope::m_next[t0], t0
2272     subi 1, t2
2273     btinz t2, .resolveScopeLoop
2274
2275 .resolveScopeLoopEnd:
2276     loadisFromInstruction(1, t1)
2277     storei CellTag, TagOffset[cfr, t1, 8]
2278     storei t0, PayloadOffset[cfr, t1, 8]
2279 end
2280
2281
2282 _llint_op_resolve_scope:
2283     traceExecution()
2284     loadisFromInstruction(4, t0)
2285
2286 #rGlobalProperty:
2287     bineq t0, GlobalProperty, .rGlobalVar
2288     getConstantScope(1)
2289     dispatch(7)
2290
2291 .rGlobalVar:
2292     bineq t0, GlobalVar, .rGlobalLexicalVar
2293     getConstantScope(1)
2294     dispatch(7)
2295
2296 .rGlobalLexicalVar:
2297     bineq t0, GlobalLexicalVar, .rClosureVar
2298     getConstantScope(1)
2299     dispatch(7)
2300
2301 .rClosureVar:
2302     bineq t0, ClosureVar, .rModuleVar
2303     resolveScope()
2304     dispatch(7)
2305
2306 .rModuleVar:
2307     bineq t0, ModuleVar, .rGlobalPropertyWithVarInjectionChecks
2308     getConstantScope(1)
2309     dispatch(7)
2310
2311 .rGlobalPropertyWithVarInjectionChecks:
2312     bineq t0, GlobalPropertyWithVarInjectionChecks, .rGlobalVarWithVarInjectionChecks
2313     varInjectionCheck(.rDynamic)
2314     getConstantScope(1)
2315     dispatch(7)
2316
2317 .rGlobalVarWithVarInjectionChecks:
2318     bineq t0, GlobalVarWithVarInjectionChecks, .rGlobalLexicalVarWithVarInjectionChecks
2319     varInjectionCheck(.rDynamic)
2320     getConstantScope(1)
2321     dispatch(7)
2322
2323 .rGlobalLexicalVarWithVarInjectionChecks:
2324     bineq t0, GlobalLexicalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks
2325     varInjectionCheck(.rDynamic)
2326     getConstantScope(1)
2327     dispatch(7)
2328
2329 .rClosureVarWithVarInjectionChecks:
2330     bineq t0, ClosureVarWithVarInjectionChecks, .rDynamic
2331     varInjectionCheck(.rDynamic)
2332     resolveScope()
2333     dispatch(7)
2334
2335 .rDynamic:
2336     callSlowPath(_slow_path_resolve_scope)
2337     dispatch(7)
2338
2339
2340 macro loadWithStructureCheck(operand, slowPath)
2341     loadisFromInstruction(operand, t0)
2342     loadp PayloadOffset[cfr, t0, 8], t0
2343     loadpFromInstruction(5, t1)
2344     bpneq JSCell::m_structureID[t0], t1, slowPath
2345 end
2346
2347 macro getProperty()
2348     loadisFromInstruction(6, t3)
2349     loadPropertyAtVariableOffset(t3, t0, t1, t2)
2350     valueProfile(t1, t2, 28, t0)
2351     loadisFromInstruction(1, t0)
2352     storei t1, TagOffset[cfr, t0, 8]
2353     storei t2, PayloadOffset[cfr, t0, 8]
2354 end
2355
2356 macro getGlobalVar(tdzCheckIfNecessary)
2357     loadpFromInstruction(6, t0)
2358     loadp TagOffset[t0], t1
2359     loadp PayloadOffset[t0], t2
2360     tdzCheckIfNecessary(t1)
2361     valueProfile(t1, t2, 28, t0)
2362     loadisFromInstruction(1, t0)
2363     storei t1, TagOffset[cfr, t0, 8]
2364     storei t2, PayloadOffset[cfr, t0, 8]
2365 end
2366
2367 macro getClosureVar()
2368     loadisFromInstruction(6, t3)
2369     loadp JSLexicalEnvironment_variables + TagOffset[t0, t3, 8], t1
2370     loadp JSLexicalEnvironment_variables + PayloadOffset[t0, t3, 8], t2
2371     valueProfile(t1, t2, 28, t0)
2372     loadisFromInstruction(1, t0)
2373     storei t1, TagOffset[cfr, t0, 8]
2374     storei t2, PayloadOffset[cfr, t0, 8]
2375 end
2376
2377 _llint_op_get_from_scope:
2378     traceExecution()
2379     loadisFromInstruction(4, t0)
2380     andi ResolveTypeMask, t0
2381
2382 #gGlobalProperty:
2383     bineq t0, GlobalProperty, .gGlobalVar
2384     loadWithStructureCheck(2, .gDynamic)
2385     getProperty()
2386     dispatch(8)
2387
2388 .gGlobalVar:
2389     bineq t0, GlobalVar, .gGlobalLexicalVar
2390     getGlobalVar(macro(t) end)
2391     dispatch(8)
2392
2393 .gGlobalLexicalVar:
2394     bineq t0, GlobalLexicalVar, .gClosureVar
2395     getGlobalVar(
2396         macro(tag)
2397             bieq tag, EmptyValueTag, .gDynamic
2398         end)
2399     dispatch(8)
2400
2401 .gClosureVar:
2402     bineq t0, ClosureVar, .gGlobalPropertyWithVarInjectionChecks
2403     loadVariable(2, t2, t1, t0)
2404     getClosureVar()
2405     dispatch(8)
2406
2407 .gGlobalPropertyWithVarInjectionChecks:
2408     bineq t0, GlobalPropertyWithVarInjectionChecks, .gGlobalVarWithVarInjectionChecks
2409     loadWithStructureCheck(2, .gDynamic)
2410     getProperty()
2411     dispatch(8)
2412
2413 .gGlobalVarWithVarInjectionChecks:
2414     bineq t0, GlobalVarWithVarInjectionChecks, .gGlobalLexicalVarWithVarInjectionChecks
2415     varInjectionCheck(.gDynamic)
2416     getGlobalVar(macro(t) end)
2417     dispatch(8)
2418
2419 .gGlobalLexicalVarWithVarInjectionChecks:
2420     bineq t0, GlobalLexicalVarWithVarInjectionChecks, .gClosureVarWithVarInjectionChecks
2421     varInjectionCheck(.gDynamic)
2422     getGlobalVar(
2423         macro(tag)
2424             bieq tag, EmptyValueTag, .gDynamic
2425         end)
2426     dispatch(8)
2427
2428 .gClosureVarWithVarInjectionChecks:
2429     bineq t0, ClosureVarWithVarInjectionChecks, .gDynamic
2430     varInjectionCheck(.gDynamic)
2431     loadVariable(2, t2, t1, t0)
2432     getClosureVar()
2433     dispatch(8)
2434
2435 .gDynamic:
2436     callSlowPath(_llint_slow_path_get_from_scope)
2437     dispatch(8)
2438
2439
2440 macro putProperty()
2441     loadisFromInstruction(3, t1)
2442     loadConstantOrVariable(t1, t2, t3)
2443     loadisFromInstruction(6, t1)
2444     storePropertyAtVariableOffset(t1, t0, t2, t3)
2445 end
2446
2447 macro putGlobalVariable()
2448     loadisFromInstruction(3, t0)
2449     loadConstantOrVariable(t0, t1, t2)
2450     loadpFromInstruction(5, t3)
2451     notifyWrite(t3, .pDynamic)
2452     loadpFromInstruction(6, t0)
2453     storei t1, TagOffset[t0]
2454     storei t2, PayloadOffset[t0]
2455 end
2456
2457 macro putClosureVar()
2458     loadisFromInstruction(3, t1)
2459     loadConstantOrVariable(t1, t2, t3)
2460     loadisFromInstruction(6, t1)
2461     storei t2, JSLexicalEnvironment_variables + TagOffset[t0, t1, 8]
2462     storei t3, JSLexicalEnvironment_variables + PayloadOffset[t0, t1, 8]
2463 end
2464
2465 macro putLocalClosureVar()
2466     loadisFromInstruction(3, t1)
2467     loadConstantOrVariable(t1, t2, t3)
2468     loadpFromInstruction(5, t5)
2469     btpz t5, .noVariableWatchpointSet
2470     notifyWrite(t5, .pDynamic)
2471 .noVariableWatchpointSet:
2472     loadisFromInstruction(6, t1)
2473     storei t2, JSLexicalEnvironment_variables + TagOffset[t0, t1, 8]
2474     storei t3, JSLexicalEnvironment_variables + PayloadOffset[t0, t1, 8]
2475 end
2476
2477
2478 _llint_op_put_to_scope:
2479     traceExecution()
2480     loadisFromInstruction(4, t0)
2481     andi ResolveTypeMask, t0
2482
2483 #pLocalClosureVar:
2484     bineq t0, LocalClosureVar, .pGlobalProperty
2485     writeBarrierOnOperands(1, 3)
2486     loadVariable(1, t2, t1, t0)
2487     putLocalClosureVar()
2488     dispatch(7)
2489
2490 .pGlobalProperty:
2491     bineq t0, GlobalProperty, .pGlobalVar
2492     writeBarrierOnOperands(1, 3)
2493     loadWithStructureCheck(1, .pDynamic)
2494     putProperty()
2495     dispatch(7)
2496
2497 .pGlobalVar:
2498     bineq t0, GlobalVar, .pGlobalLexicalVar
2499     writeBarrierOnGlobalObject(3)
2500     putGlobalVariable()
2501     dispatch(7)
2502
2503 .pGlobalLexicalVar:
2504     bineq t0, GlobalLexicalVar, .pClosureVar
2505     writeBarrierOnGlobalLexicalEnvironment(3)
2506     putGlobalVariable()
2507     dispatch(7)
2508
2509 .pClosureVar:
2510     bineq t0, ClosureVar, .pGlobalPropertyWithVarInjectionChecks
2511     writeBarrierOnOperands(1, 3)
2512     loadVariable(1, t2, t1, t0)
2513     putClosureVar()
2514     dispatch(7)
2515
2516 .pGlobalPropertyWithVarInjectionChecks:
2517     bineq t0, GlobalPropertyWithVarInjectionChecks, .pGlobalVarWithVarInjectionChecks
2518     writeBarrierOnOperands(1, 3)
2519     loadWithStructureCheck(1, .pDynamic)
2520     putProperty()
2521     dispatch(7)
2522
2523 .pGlobalVarWithVarInjectionChecks:
2524     bineq t0, GlobalVarWithVarInjectionChecks, .pGlobalLexicalVarWithVarInjectionChecks
2525     writeBarrierOnGlobalObject(3)
2526     varInjectionCheck(.pDynamic)
2527     putGlobalVariable()
2528     dispatch(7)
2529
2530 .pGlobalLexicalVarWithVarInjectionChecks:
2531     bineq t0, GlobalLexicalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
2532     writeBarrierOnGlobalLexicalEnvironment(3)
2533     varInjectionCheck(.pDynamic)
2534     putGlobalVariable()
2535     dispatch(7)
2536
2537 .pClosureVarWithVarInjectionChecks:
2538     bineq t0, ClosureVarWithVarInjectionChecks, .pModuleVar
2539     writeBarrierOnOperands(1, 3)
2540     varInjectionCheck(.pDynamic)
2541     loadVariable(1, t2, t1, t0)
2542     putClosureVar()
2543     dispatch(7)
2544
2545 .pModuleVar:
2546     bineq t0, ModuleVar, .pDynamic
2547     callSlowPath(_slow_path_throw_strict_mode_readonly_property_write_error)
2548     dispatch(7)
2549
2550 .pDynamic:
2551     callSlowPath(_llint_slow_path_put_to_scope)
2552     dispatch(7)
2553
2554
2555 _llint_op_get_from_arguments:
2556     traceExecution()
2557     loadisFromInstruction(2, t0)
2558     loadi PayloadOffset[cfr, t0, 8], t0
2559     loadi 12[PC], t1
2560     loadi DirectArguments_storage + TagOffset[t0, t1, 8], t2
2561     loadi DirectArguments_storage + PayloadOffset[t0, t1, 8], t3
2562     loadisFromInstruction(1, t1)
2563     valueProfile(t2, t3, 16, t0)
2564     storei t2, TagOffset[cfr, t1, 8]
2565     storei t3, PayloadOffset[cfr, t1, 8]
2566     dispatch(5)
2567
2568
2569 _llint_op_put_to_arguments:
2570     traceExecution()
2571     writeBarrierOnOperands(1, 3)
2572     loadisFromInstruction(1, t0)
2573     loadi PayloadOffset[cfr, t0, 8], t0
2574     loadisFromInstruction(3, t1)
2575     loadConstantOrVariable(t1, t2, t3)
2576     loadi 8[PC], t1
2577     storei t2, DirectArguments_storage + TagOffset[t0, t1, 8]
2578     storei t3, DirectArguments_storage + PayloadOffset[t0, t1, 8]
2579     dispatch(4)
2580
2581
2582 _llint_op_get_parent_scope:
2583     traceExecution()
2584     loadisFromInstruction(2, t0)
2585     loadp PayloadOffset[cfr, t0, 8], t0
2586     loadp JSScope::m_next[t0], t0
2587     loadisFromInstruction(1, t1)
2588     storei CellTag, TagOffset[cfr, t1, 8]
2589     storei t0, PayloadOffset[cfr, t1, 8]
2590     dispatch(3)
2591
2592
2593 _llint_op_profile_type:
2594     traceExecution()
2595     loadp CodeBlock[cfr], t1
2596     loadp CodeBlock::m_poisonedVM[t1], t1
2597     unpoison(_g_CodeBlockPoison, t1, t2)
2598     # t1 is holding the pointer to the typeProfilerLog.
2599     loadp VM::m_typeProfilerLog[t1], t1
2600
2601     # t0 is holding the payload, t5 is holding the tag.
2602     loadisFromInstruction(1, t2)
2603     loadConstantOrVariable(t2, t5, t0)
2604
2605     bieq t5, EmptyValueTag, .opProfileTypeDone
2606
2607     # t2 is holding the pointer to the current log entry.
2608     loadp TypeProfilerLog::m_currentLogEntryPtr[t1], t2
2609
2610     # Store the JSValue onto the log entry.
2611     storei t5, TypeProfilerLog::LogEntry::value + TagOffset[t2]
2612     storei t0, TypeProfilerLog::LogEntry::value + PayloadOffset[t2]
2613
2614     # Store the TypeLocation onto the log entry.
2615     loadpFromInstruction(2, t3)
2616     storep t3, TypeProfilerLog::LogEntry::location[t2]
2617
2618     bieq t5, CellTag, .opProfileTypeIsCell
2619     storei 0, TypeProfilerLog::LogEntry::structureID[t2]
2620     jmp .opProfileTypeSkipIsCell
2621 .opProfileTypeIsCell:
2622     loadi JSCell::m_structureID[t0], t3
2623     storei t3, TypeProfilerLog::LogEntry::structureID[t2]
2624 .opProfileTypeSkipIsCell:
2625     
2626     # Increment the current log entry.
2627     addp sizeof TypeProfilerLog::LogEntry, t2
2628     storep t2, TypeProfilerLog::m_currentLogEntryPtr[t1]
2629
2630     loadp TypeProfilerLog::m_logEndPtr[t1], t1
2631     bpneq t2, t1, .opProfileTypeDone
2632     callSlowPath(_slow_path_profile_type_clear_log)
2633
2634 .opProfileTypeDone:
2635     dispatch(6)
2636
2637
2638 _llint_op_profile_control_flow:
2639     traceExecution()
2640     loadpFromInstruction(1, t0)
2641     loadi BasicBlockLocation::m_executionCount[t0], t1
2642     addi 1, t1
2643     bieq t1, 0, .done # We overflowed.
2644     storei t1, BasicBlockLocation::m_executionCount[t0]
2645 .done:
2646     dispatch(2)
2647
2648
2649 _llint_op_get_rest_length:
2650     traceExecution()
2651     loadi PayloadOffset + ArgumentCount[cfr], t0
2652     subi 1, t0
2653     loadisFromInstruction(2, t1)
2654     bilteq t0, t1, .storeZero
2655     subi t1, t0
2656     jmp .finish
2657 .storeZero:
2658     move 0, t0
2659 .finish:
2660     loadisFromInstruction(1, t1)
2661     storei t0, PayloadOffset[cfr, t1, 8]
2662     storei Int32Tag, TagOffset[cfr, t1, 8]
2663     dispatch(3)
2664
2665
2666 _llint_op_log_shadow_chicken_prologue:
2667     traceExecution()
2668     acquireShadowChickenPacket(.opLogShadowChickenPrologueSlow)
2669     storep cfr, ShadowChicken::Packet::frame[t0]
2670     loadp CallerFrame[cfr], t1
2671     storep t1, ShadowChicken::Packet::callerFrame[t0]
2672     loadp Callee + PayloadOffset[cfr], t1
2673     storep t1, ShadowChicken::Packet::callee[t0]
2674     loadisFromInstruction(1, t1)
2675     loadi PayloadOffset[cfr, t1, 8], t1
2676     storep t1, ShadowChicken::Packet::scope[t0]
2677     dispatch(2)
2678 .opLogShadowChickenPrologueSlow:
2679     callSlowPath(_llint_slow_path_log_shadow_chicken_prologue)
2680     dispatch(2)
2681
2682
2683 _llint_op_log_shadow_chicken_tail:
2684     traceExecution()
2685     acquireShadowChickenPacket(.opLogShadowChickenTailSlow)
2686     storep cfr, ShadowChicken::Packet::frame[t0]
2687     storep ShadowChickenTailMarker, ShadowChicken::Packet::callee[t0]
2688     loadVariable(1, t3, t2, t1)
2689     storei t2, TagOffset + ShadowChicken::Packet::thisValue[t0]
2690     storei t1, PayloadOffset + ShadowChicken::Packet::thisValue[t0]
2691     loadisFromInstruction(2, t1)
2692     loadi PayloadOffset[cfr, t1, 8], t1
2693     storep t1, ShadowChicken::Packet::scope[t0]
2694     loadp CodeBlock[cfr], t1
2695     storep t1, ShadowChicken::Packet::codeBlock[t0]
2696     storei PC, ShadowChicken::Packet::callSiteIndex[t0]
2697     dispatch(3)
2698 .opLogShadowChickenTailSlow:
2699     callSlowPath(_llint_slow_path_log_shadow_chicken_tail)
2700     dispatch(3)