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