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