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