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