c878c6b524c61f770e85201e18958f486c8d90b9
[WebKit-https.git] / Source / JavaScriptCore / llint / LowLevelInterpreter32_64.asm
1 # Copyright (C) 2011, 2012, 2013, 2014 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     bieq VM::m_exception + TagOffset[t3], EmptyValueTag, .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_create_lexical_environment:
724     traceExecution()
725     loadi 4[PC], t0
726     callSlowPath(_llint_slow_path_create_lexical_environment)
727     dispatch(3)
728
729
730 _llint_op_get_scope:
731     traceExecution()
732     loadi Callee + PayloadOffset[cfr], t0
733     loadi JSCallee::m_scope[t0], t0
734     loadisFromInstruction(1, t1)
735     storei CellTag, TagOffset[cfr, t1, 8]
736     storei t0, PayloadOffset[cfr, t1, 8]
737     dispatch(2)
738
739
740 _llint_op_init_lazy_reg:
741     traceExecution()
742     loadi 4[PC], t0
743     storei EmptyValueTag, TagOffset[cfr, t0, 8]
744     storei 0, PayloadOffset[cfr, t0, 8]
745     dispatch(2)
746
747
748 _llint_op_create_arguments:
749     traceExecution()
750     loadi 4[PC], t0
751     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateArgumentsDone
752     callSlowPath(_slow_path_create_arguments)
753 .opCreateArgumentsDone:
754     dispatch(3)
755
756
757 _llint_op_create_this:
758     traceExecution()
759     loadi 8[PC], t0
760     loadp PayloadOffset[cfr, t0, 8], t0
761     loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_allocator[t0], t1
762     loadp JSFunction::m_allocationProfile + ObjectAllocationProfile::m_structure[t0], t2
763     btpz t1, .opCreateThisSlow
764     allocateJSObject(t1, t2, t0, t3, .opCreateThisSlow)
765     loadi 4[PC], t1
766     storei CellTag, TagOffset[cfr, t1, 8]
767     storei t0, PayloadOffset[cfr, t1, 8]
768     dispatch(4)
769
770 .opCreateThisSlow:
771     callSlowPath(_slow_path_create_this)
772     dispatch(4)
773
774
775 _llint_op_get_callee:
776     traceExecution()
777     loadi 4[PC], t0
778     loadp PayloadOffset + Callee[cfr], t1
779     loadpFromInstruction(2, t2)
780     bpneq t1, t2, .opGetCalleeSlow
781     storei CellTag, TagOffset[cfr, t0, 8]
782     storei t1, PayloadOffset[cfr, t0, 8]
783     dispatch(3)
784
785 .opGetCalleeSlow:
786     callSlowPath(_slow_path_get_callee)
787     dispatch(3)
788
789 _llint_op_to_this:
790     traceExecution()
791     loadi 4[PC], t0
792     bineq TagOffset[cfr, t0, 8], CellTag, .opToThisSlow
793     loadi PayloadOffset[cfr, t0, 8], t0
794     bbneq JSCell::m_type[t0], FinalObjectType, .opToThisSlow
795     loadpFromInstruction(2, t2)
796     bpneq JSCell::m_structureID[t0], t2, .opToThisSlow
797     dispatch(4)
798
799 .opToThisSlow:
800     callSlowPath(_slow_path_to_this)
801     dispatch(4)
802
803
804 _llint_op_new_object:
805     traceExecution()
806     loadpFromInstruction(3, t0)
807     loadp ObjectAllocationProfile::m_allocator[t0], t1
808     loadp ObjectAllocationProfile::m_structure[t0], t2
809     allocateJSObject(t1, t2, t0, t3, .opNewObjectSlow)
810     loadi 4[PC], t1
811     storei CellTag, TagOffset[cfr, t1, 8]
812     storei t0, PayloadOffset[cfr, t1, 8]
813     dispatch(4)
814
815 .opNewObjectSlow:
816     callSlowPath(_llint_slow_path_new_object)
817     dispatch(4)
818
819
820 _llint_op_mov:
821     traceExecution()
822     loadi 8[PC], t1
823     loadi 4[PC], t0
824     loadConstantOrVariable(t1, t2, t3)
825     storei t2, TagOffset[cfr, t0, 8]
826     storei t3, PayloadOffset[cfr, t0, 8]
827     dispatch(3)
828
829
830 macro notifyWrite(set, valueTag, valuePayload, scratch, slow)
831     loadb VariableWatchpointSet::m_state[set], scratch
832     bieq scratch, IsInvalidated, .done
833     bineq valuePayload, VariableWatchpointSet::m_inferredValue + PayloadOffset[set], slow
834     bineq valueTag, VariableWatchpointSet::m_inferredValue + TagOffset[set], slow
835 .done:
836 end
837
838 _llint_op_not:
839     traceExecution()
840     loadi 8[PC], t0
841     loadi 4[PC], t1
842     loadConstantOrVariable(t0, t2, t3)
843     bineq t2, BooleanTag, .opNotSlow
844     xori 1, t3
845     storei t2, TagOffset[cfr, t1, 8]
846     storei t3, PayloadOffset[cfr, t1, 8]
847     dispatch(3)
848
849 .opNotSlow:
850     callSlowPath(_slow_path_not)
851     dispatch(3)
852
853
854 _llint_op_eq:
855     traceExecution()
856     loadi 12[PC], t2
857     loadi 8[PC], t0
858     loadConstantOrVariable(t2, t3, t1)
859     loadConstantOrVariable2Reg(t0, t2, t0)
860     bineq t2, t3, .opEqSlow
861     bieq t2, CellTag, .opEqSlow
862     bib t2, LowestTag, .opEqSlow
863     loadi 4[PC], t2
864     cieq t0, t1, t0
865     storei BooleanTag, TagOffset[cfr, t2, 8]
866     storei t0, PayloadOffset[cfr, t2, 8]
867     dispatch(4)
868
869 .opEqSlow:
870     callSlowPath(_slow_path_eq)
871     dispatch(4)
872
873
874 _llint_op_eq_null:
875     traceExecution()
876     loadi 8[PC], t0
877     loadi 4[PC], t3
878     assertNotConstant(t0)
879     loadi TagOffset[cfr, t0, 8], t1
880     loadi PayloadOffset[cfr, t0, 8], t0
881     bineq t1, CellTag, .opEqNullImmediate
882     btbnz JSCell::m_flags[t0], MasqueradesAsUndefined, .opEqNullMasqueradesAsUndefined
883     move 0, t1
884     jmp .opEqNullNotImmediate
885 .opEqNullMasqueradesAsUndefined:
886     loadp JSCell::m_structureID[t0], t1
887     loadp CodeBlock[cfr], t0
888     loadp CodeBlock::m_globalObject[t0], t0
889     cpeq Structure::m_globalObject[t1], t0, t1
890     jmp .opEqNullNotImmediate
891 .opEqNullImmediate:
892     cieq t1, NullTag, t2
893     cieq t1, UndefinedTag, t1
894     ori t2, t1
895 .opEqNullNotImmediate:
896     storei BooleanTag, TagOffset[cfr, t3, 8]
897     storei t1, PayloadOffset[cfr, t3, 8]
898     dispatch(3)
899
900
901 _llint_op_neq:
902     traceExecution()
903     loadi 12[PC], t2
904     loadi 8[PC], t0
905     loadConstantOrVariable(t2, t3, t1)
906     loadConstantOrVariable2Reg(t0, t2, t0)
907     bineq t2, t3, .opNeqSlow
908     bieq t2, CellTag, .opNeqSlow
909     bib t2, LowestTag, .opNeqSlow
910     loadi 4[PC], t2
911     cineq t0, t1, t0
912     storei BooleanTag, TagOffset[cfr, t2, 8]
913     storei t0, PayloadOffset[cfr, t2, 8]
914     dispatch(4)
915
916 .opNeqSlow:
917     callSlowPath(_slow_path_neq)
918     dispatch(4)
919     
920
921 _llint_op_neq_null:
922     traceExecution()
923     loadi 8[PC], t0
924     loadi 4[PC], t3
925     assertNotConstant(t0)
926     loadi TagOffset[cfr, t0, 8], t1
927     loadi PayloadOffset[cfr, t0, 8], t0
928     bineq t1, CellTag, .opNeqNullImmediate
929     btbnz JSCell::m_flags[t0], MasqueradesAsUndefined, .opNeqNullMasqueradesAsUndefined
930     move 1, t1
931     jmp .opNeqNullNotImmediate
932 .opNeqNullMasqueradesAsUndefined:
933     loadp JSCell::m_structureID[t0], t1
934     loadp CodeBlock[cfr], t0
935     loadp CodeBlock::m_globalObject[t0], t0
936     cpneq Structure::m_globalObject[t1], t0, t1
937     jmp .opNeqNullNotImmediate
938 .opNeqNullImmediate:
939     cineq t1, NullTag, t2
940     cineq t1, UndefinedTag, t1
941     andi t2, t1
942 .opNeqNullNotImmediate:
943     storei BooleanTag, TagOffset[cfr, t3, 8]
944     storei t1, PayloadOffset[cfr, t3, 8]
945     dispatch(3)
946
947
948 macro strictEq(equalityOperation, slowPath)
949     loadi 12[PC], t2
950     loadi 8[PC], t0
951     loadConstantOrVariable(t2, t3, t1)
952     loadConstantOrVariable2Reg(t0, t2, t0)
953     bineq t2, t3, .slow
954     bib t2, LowestTag, .slow
955     bineq t2, CellTag, .notString
956     bbneq JSCell::m_type[t0], StringType, .notString
957     bbeq JSCell::m_type[t1], StringType, .slow
958 .notString:
959     loadi 4[PC], t2
960     equalityOperation(t0, t1, t0)
961     storei BooleanTag, TagOffset[cfr, t2, 8]
962     storei t0, PayloadOffset[cfr, t2, 8]
963     dispatch(4)
964
965 .slow:
966     callSlowPath(slowPath)
967     dispatch(4)
968 end
969
970 _llint_op_stricteq:
971     traceExecution()
972     strictEq(macro (left, right, result) cieq left, right, result end, _slow_path_stricteq)
973
974
975 _llint_op_nstricteq:
976     traceExecution()
977     strictEq(macro (left, right, result) cineq left, right, result end, _slow_path_nstricteq)
978
979
980 _llint_op_inc:
981     traceExecution()
982     loadi 4[PC], t0
983     bineq TagOffset[cfr, t0, 8], Int32Tag, .opIncSlow
984     loadi PayloadOffset[cfr, t0, 8], t1
985     baddio 1, t1, .opIncSlow
986     storei t1, PayloadOffset[cfr, t0, 8]
987     dispatch(2)
988
989 .opIncSlow:
990     callSlowPath(_slow_path_inc)
991     dispatch(2)
992
993
994 _llint_op_dec:
995     traceExecution()
996     loadi 4[PC], t0
997     bineq TagOffset[cfr, t0, 8], Int32Tag, .opDecSlow
998     loadi PayloadOffset[cfr, t0, 8], t1
999     bsubio 1, t1, .opDecSlow
1000     storei t1, PayloadOffset[cfr, t0, 8]
1001     dispatch(2)
1002
1003 .opDecSlow:
1004     callSlowPath(_slow_path_dec)
1005     dispatch(2)
1006
1007
1008 _llint_op_to_number:
1009     traceExecution()
1010     loadi 8[PC], t0
1011     loadi 4[PC], t1
1012     loadConstantOrVariable(t0, t2, t3)
1013     bieq t2, Int32Tag, .opToNumberIsInt
1014     biaeq t2, LowestTag, .opToNumberSlow
1015 .opToNumberIsInt:
1016     storei t2, TagOffset[cfr, t1, 8]
1017     storei t3, PayloadOffset[cfr, t1, 8]
1018     dispatch(3)
1019
1020 .opToNumberSlow:
1021     callSlowPath(_slow_path_to_number)
1022     dispatch(3)
1023
1024
1025 _llint_op_negate:
1026     traceExecution()
1027     loadi 8[PC], t0
1028     loadi 4[PC], t3
1029     loadConstantOrVariable(t0, t1, t2)
1030     bineq t1, Int32Tag, .opNegateSrcNotInt
1031     btiz t2, 0x7fffffff, .opNegateSlow
1032     negi t2
1033     storei Int32Tag, TagOffset[cfr, t3, 8]
1034     storei t2, PayloadOffset[cfr, t3, 8]
1035     dispatch(3)
1036 .opNegateSrcNotInt:
1037     bia t1, LowestTag, .opNegateSlow
1038     xori 0x80000000, t1
1039     storei t1, TagOffset[cfr, t3, 8]
1040     storei t2, PayloadOffset[cfr, t3, 8]
1041     dispatch(3)
1042
1043 .opNegateSlow:
1044     callSlowPath(_slow_path_negate)
1045     dispatch(3)
1046
1047
1048 macro binaryOpCustomStore(integerOperationAndStore, doubleOperation, slowPath)
1049     loadi 12[PC], t2
1050     loadi 8[PC], t0
1051     loadConstantOrVariable(t2, t3, t1)
1052     loadConstantOrVariable2Reg(t0, t2, t0)
1053     bineq t2, Int32Tag, .op1NotInt
1054     bineq t3, Int32Tag, .op2NotInt
1055     loadi 4[PC], t2
1056     integerOperationAndStore(t3, t1, t0, .slow, t2)
1057     dispatch(5)
1058
1059 .op1NotInt:
1060     # First operand is definitely not an int, the second operand could be anything.
1061     bia t2, LowestTag, .slow
1062     bib t3, LowestTag, .op1NotIntOp2Double
1063     bineq t3, Int32Tag, .slow
1064     ci2d t1, ft1
1065     jmp .op1NotIntReady
1066 .op1NotIntOp2Double:
1067     fii2d t1, t3, ft1
1068 .op1NotIntReady:
1069     loadi 4[PC], t1
1070     fii2d t0, t2, ft0
1071     doubleOperation(ft1, ft0)
1072     stored ft0, [cfr, t1, 8]
1073     dispatch(5)
1074
1075 .op2NotInt:
1076     # First operand is definitely an int, the second operand is definitely not.
1077     loadi 4[PC], t2
1078     bia t3, LowestTag, .slow
1079     ci2d t0, ft0
1080     fii2d t1, t3, ft1
1081     doubleOperation(ft1, ft0)
1082     stored ft0, [cfr, t2, 8]
1083     dispatch(5)
1084
1085 .slow:
1086     callSlowPath(slowPath)
1087     dispatch(5)
1088 end
1089
1090 macro binaryOp(integerOperation, doubleOperation, slowPath)
1091     binaryOpCustomStore(
1092         macro (int32Tag, left, right, slow, index)
1093             integerOperation(left, right, slow)
1094             storei int32Tag, TagOffset[cfr, index, 8]
1095             storei right, PayloadOffset[cfr, index, 8]
1096         end,
1097         doubleOperation, slowPath)
1098 end
1099
1100 _llint_op_add:
1101     traceExecution()
1102     binaryOp(
1103         macro (left, right, slow) baddio left, right, slow end,
1104         macro (left, right) addd left, right end,
1105         _slow_path_add)
1106
1107
1108 _llint_op_mul:
1109     traceExecution()
1110     binaryOpCustomStore(
1111         macro (int32Tag, left, right, slow, index)
1112             const scratch = int32Tag   # We know that we can reuse the int32Tag register since it has a constant.
1113             move right, scratch
1114             bmulio left, scratch, slow
1115             btinz scratch, .done
1116             bilt left, 0, slow
1117             bilt right, 0, slow
1118         .done:
1119             storei Int32Tag, TagOffset[cfr, index, 8]
1120             storei scratch, PayloadOffset[cfr, index, 8]
1121         end,
1122         macro (left, right) muld left, right end,
1123         _slow_path_mul)
1124
1125
1126 _llint_op_sub:
1127     traceExecution()
1128     binaryOp(
1129         macro (left, right, slow) bsubio left, right, slow end,
1130         macro (left, right) subd left, right end,
1131         _slow_path_sub)
1132
1133
1134 _llint_op_div:
1135     traceExecution()
1136     binaryOpCustomStore(
1137         macro (int32Tag, left, right, slow, index)
1138             ci2d left, ft0
1139             ci2d right, ft1
1140             divd ft0, ft1
1141             bcd2i ft1, right, .notInt
1142             storei int32Tag, TagOffset[cfr, index, 8]
1143             storei right, PayloadOffset[cfr, index, 8]
1144             jmp .done
1145         .notInt:
1146             stored ft1, [cfr, index, 8]
1147         .done:
1148         end,
1149         macro (left, right) divd left, right end,
1150         _slow_path_div)
1151
1152
1153 macro bitOp(operation, slowPath, advance)
1154     loadi 12[PC], t2
1155     loadi 8[PC], t0
1156     loadConstantOrVariable(t2, t3, t1)
1157     loadConstantOrVariable2Reg(t0, t2, t0)
1158     bineq t3, Int32Tag, .slow
1159     bineq t2, Int32Tag, .slow
1160     loadi 4[PC], t2
1161     operation(t1, t0)
1162     storei t3, TagOffset[cfr, t2, 8]
1163     storei t0, PayloadOffset[cfr, t2, 8]
1164     dispatch(advance)
1165
1166 .slow:
1167     callSlowPath(slowPath)
1168     dispatch(advance)
1169 end
1170
1171 _llint_op_lshift:
1172     traceExecution()
1173     bitOp(
1174         macro (left, right) lshifti left, right end,
1175         _slow_path_lshift,
1176         4)
1177
1178
1179 _llint_op_rshift:
1180     traceExecution()
1181     bitOp(
1182         macro (left, right) rshifti left, right end,
1183         _slow_path_rshift,
1184         4)
1185
1186
1187 _llint_op_urshift:
1188     traceExecution()
1189     bitOp(
1190         macro (left, right) urshifti left, right end,
1191         _slow_path_urshift,
1192         4)
1193
1194
1195 _llint_op_unsigned:
1196     traceExecution()
1197     loadi 4[PC], t0
1198     loadi 8[PC], t1
1199     loadConstantOrVariablePayload(t1, Int32Tag, t2, .opUnsignedSlow)
1200     bilt t2, 0, .opUnsignedSlow
1201     storei t2, PayloadOffset[cfr, t0, 8]
1202     storei Int32Tag, TagOffset[cfr, t0, 8]
1203     dispatch(3)
1204 .opUnsignedSlow:
1205     callSlowPath(_slow_path_unsigned)
1206     dispatch(3)
1207
1208
1209 _llint_op_bitand:
1210     traceExecution()
1211     bitOp(
1212         macro (left, right) andi left, right end,
1213         _slow_path_bitand,
1214         5)
1215
1216
1217 _llint_op_bitxor:
1218     traceExecution()
1219     bitOp(
1220         macro (left, right) xori left, right end,
1221         _slow_path_bitxor,
1222         5)
1223
1224
1225 _llint_op_bitor:
1226     traceExecution()
1227     bitOp(
1228         macro (left, right) ori left, right end,
1229         _slow_path_bitor,
1230         5)
1231
1232
1233 _llint_op_check_has_instance:
1234     traceExecution()
1235     loadi 12[PC], t1
1236     loadConstantOrVariablePayload(t1, CellTag, t0, .opCheckHasInstanceSlow)
1237     btbz JSCell::m_flags[t0], ImplementsDefaultHasInstance, .opCheckHasInstanceSlow
1238     dispatch(5)
1239
1240 .opCheckHasInstanceSlow:
1241     callSlowPath(_llint_slow_path_check_has_instance)
1242     dispatch(0)
1243
1244
1245 _llint_op_instanceof:
1246     traceExecution()
1247     # Actually do the work.
1248     loadi 12[PC], t0
1249     loadi 4[PC], t3
1250     loadConstantOrVariablePayload(t0, CellTag, t1, .opInstanceofSlow)
1251     bbb JSCell::m_type[t1], ObjectType, .opInstanceofSlow
1252     loadi 8[PC], t0
1253     loadConstantOrVariablePayload(t0, CellTag, t2, .opInstanceofSlow)
1254     
1255     # Register state: t1 = prototype, t2 = value
1256     move 1, t0
1257 .opInstanceofLoop:
1258     loadp JSCell::m_structureID[t2], t2
1259     loadi Structure::m_prototype + PayloadOffset[t2], t2
1260     bpeq t2, t1, .opInstanceofDone
1261     btinz t2, .opInstanceofLoop
1262
1263     move 0, t0
1264 .opInstanceofDone:
1265     storei BooleanTag, TagOffset[cfr, t3, 8]
1266     storei t0, PayloadOffset[cfr, t3, 8]
1267     dispatch(4)
1268
1269 .opInstanceofSlow:
1270     callSlowPath(_llint_slow_path_instanceof)
1271     dispatch(4)
1272
1273
1274 _llint_op_is_undefined:
1275     traceExecution()
1276     loadi 8[PC], t1
1277     loadi 4[PC], t0
1278     loadConstantOrVariable(t1, t2, t3)
1279     storei BooleanTag, TagOffset[cfr, t0, 8]
1280     bieq t2, CellTag, .opIsUndefinedCell
1281     cieq t2, UndefinedTag, t3
1282     storei t3, PayloadOffset[cfr, t0, 8]
1283     dispatch(3)
1284 .opIsUndefinedCell:
1285     btbnz JSCell::m_flags[t3], MasqueradesAsUndefined, .opIsUndefinedMasqueradesAsUndefined
1286     move 0, t1
1287     storei t1, PayloadOffset[cfr, t0, 8]
1288     dispatch(3)
1289 .opIsUndefinedMasqueradesAsUndefined:
1290     loadp JSCell::m_structureID[t3], t1
1291     loadp CodeBlock[cfr], t3
1292     loadp CodeBlock::m_globalObject[t3], t3
1293     cpeq Structure::m_globalObject[t1], t3, t1
1294     storei t1, PayloadOffset[cfr, t0, 8]
1295     dispatch(3)
1296
1297
1298 _llint_op_is_boolean:
1299     traceExecution()
1300     loadi 8[PC], t1
1301     loadi 4[PC], t2
1302     loadConstantOrVariableTag(t1, t0)
1303     cieq t0, BooleanTag, t0
1304     storei BooleanTag, TagOffset[cfr, t2, 8]
1305     storei t0, PayloadOffset[cfr, t2, 8]
1306     dispatch(3)
1307
1308
1309 _llint_op_is_number:
1310     traceExecution()
1311     loadi 8[PC], t1
1312     loadi 4[PC], t2
1313     loadConstantOrVariableTag(t1, t0)
1314     storei BooleanTag, TagOffset[cfr, t2, 8]
1315     addi 1, t0
1316     cib t0, LowestTag + 1, t1
1317     storei t1, PayloadOffset[cfr, t2, 8]
1318     dispatch(3)
1319
1320
1321 _llint_op_is_string:
1322     traceExecution()
1323     loadi 8[PC], t1
1324     loadi 4[PC], t2
1325     loadConstantOrVariable(t1, t0, t3)
1326     storei BooleanTag, TagOffset[cfr, t2, 8]
1327     bineq t0, CellTag, .opIsStringNotCell
1328     cbeq JSCell::m_type[t3], StringType, t1
1329     storei t1, PayloadOffset[cfr, t2, 8]
1330     dispatch(3)
1331 .opIsStringNotCell:
1332     storep 0, PayloadOffset[cfr, t2, 8]
1333     dispatch(3)
1334
1335
1336 macro loadPropertyAtVariableOffsetKnownNotInline(propertyOffset, objectAndStorage, tag, payload)
1337     assert(macro (ok) bigteq propertyOffset, firstOutOfLineOffset, ok end)
1338     negi propertyOffset
1339     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
1340     loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag
1341     loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload
1342 end
1343
1344 macro loadPropertyAtVariableOffset(propertyOffset, objectAndStorage, tag, payload)
1345     bilt propertyOffset, firstOutOfLineOffset, .isInline
1346     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
1347     negi propertyOffset
1348     jmp .ready
1349 .isInline:
1350     addp sizeof JSObject - (firstOutOfLineOffset - 2) * 8, objectAndStorage
1351 .ready:
1352     loadi TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], tag
1353     loadi PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffset, 8], payload
1354 end
1355
1356 macro storePropertyAtVariableOffset(propertyOffsetAsInt, objectAndStorage, tag, payload)
1357     bilt propertyOffsetAsInt, firstOutOfLineOffset, .isInline
1358     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
1359     negi propertyOffsetAsInt
1360     jmp .ready
1361 .isInline:
1362     addp sizeof JSObject - (firstOutOfLineOffset - 2) * 8, objectAndStorage
1363 .ready:
1364     storei tag, TagOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8]
1365     storei payload, PayloadOffset + (firstOutOfLineOffset - 2) * 8[objectAndStorage, propertyOffsetAsInt, 8]
1366 end
1367
1368
1369 _llint_op_init_global_const:
1370     traceExecution()
1371     writeBarrierOnGlobalObject(2)
1372     loadi 8[PC], t1
1373     loadi 4[PC], t0
1374     loadConstantOrVariable(t1, t2, t3)
1375     storei t2, TagOffset[t0]
1376     storei t3, PayloadOffset[t0]
1377     dispatch(5)
1378
1379
1380 # We only do monomorphic get_by_id caching for now, and we do not modify the
1381 # opcode. We do, however, allow for the cache to change anytime if fails, since
1382 # ping-ponging is free. At best we get lucky and the get_by_id will continue
1383 # to take fast path on the new cache. At worst we take slow path, which is what
1384 # we would have been doing anyway.
1385
1386 macro getById(getPropertyStorage)
1387     traceExecution()
1388     loadi 8[PC], t0
1389     loadi 16[PC], t1
1390     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow)
1391     loadi 20[PC], t2
1392     getPropertyStorage(
1393         t3,
1394         t0,
1395         macro (propertyStorage, scratch)
1396             bpneq JSCell::m_structureID[t3], t1, .opGetByIdSlow
1397             loadi 4[PC], t1
1398             loadi TagOffset[propertyStorage, t2], scratch
1399             loadi PayloadOffset[propertyStorage, t2], t2
1400             storei scratch, TagOffset[cfr, t1, 8]
1401             storei t2, PayloadOffset[cfr, t1, 8]
1402             valueProfile(scratch, t2, 32, t1)
1403             dispatch(9)
1404         end)
1405
1406     .opGetByIdSlow:
1407         callSlowPath(_llint_slow_path_get_by_id)
1408         dispatch(9)
1409 end
1410
1411 _llint_op_get_by_id:
1412     getById(withInlineStorage)
1413
1414
1415 _llint_op_get_by_id_out_of_line:
1416     getById(withOutOfLineStorage)
1417
1418
1419 _llint_op_get_array_length:
1420     traceExecution()
1421     loadi 8[PC], t0
1422     loadp 16[PC], t1
1423     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetArrayLengthSlow)
1424     move t3, t2
1425     arrayProfile(t2, t1, t0)
1426     btiz t2, IsArray, .opGetArrayLengthSlow
1427     btiz t2, IndexingShapeMask, .opGetArrayLengthSlow
1428     loadi 4[PC], t1
1429     loadp JSObject::m_butterfly[t3], t0
1430     loadi -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], t0
1431     bilt t0, 0, .opGetArrayLengthSlow
1432     valueProfile(Int32Tag, t0, 32, t2)
1433     storep t0, PayloadOffset[cfr, t1, 8]
1434     storep Int32Tag, TagOffset[cfr, t1, 8]
1435     dispatch(9)
1436
1437 .opGetArrayLengthSlow:
1438     callSlowPath(_llint_slow_path_get_by_id)
1439     dispatch(9)
1440
1441
1442 _llint_op_get_arguments_length:
1443     traceExecution()
1444     loadi 8[PC], t0
1445     loadi 4[PC], t1
1446     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentsLengthSlow
1447     loadi ArgumentCount + PayloadOffset[cfr], t2
1448     subi 1, t2
1449     storei Int32Tag, TagOffset[cfr, t1, 8]
1450     storei t2, PayloadOffset[cfr, t1, 8]
1451     dispatch(4)
1452
1453 .opGetArgumentsLengthSlow:
1454     callSlowPath(_llint_slow_path_get_arguments_length)
1455     dispatch(4)
1456
1457
1458 macro putById(getPropertyStorage)
1459     traceExecution()
1460     writeBarrierOnOperands(1, 3)
1461     loadi 4[PC], t3
1462     loadi 16[PC], t1
1463     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1464     loadi 12[PC], t2
1465     getPropertyStorage(
1466         t0,
1467         t3,
1468         macro (propertyStorage, scratch)
1469             bpneq JSCell::m_structureID[t0], t1, .opPutByIdSlow
1470             loadi 20[PC], t1
1471             loadConstantOrVariable2Reg(t2, scratch, t2)
1472             storei scratch, TagOffset[propertyStorage, t1]
1473             storei t2, PayloadOffset[propertyStorage, t1]
1474             dispatch(9)
1475         end)
1476
1477     .opPutByIdSlow:
1478         callSlowPath(_llint_slow_path_put_by_id)
1479         dispatch(9)
1480 end
1481
1482 _llint_op_put_by_id:
1483     putById(withInlineStorage)
1484
1485
1486 _llint_op_put_by_id_out_of_line:
1487     putById(withOutOfLineStorage)
1488
1489
1490 macro putByIdTransition(additionalChecks, getPropertyStorage)
1491     traceExecution()
1492     writeBarrierOnOperand(1)
1493     loadi 4[PC], t3
1494     loadi 16[PC], t1
1495     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1496     loadi 12[PC], t2
1497     bpneq JSCell::m_structureID[t0], t1, .opPutByIdSlow
1498     additionalChecks(t1, t3, .opPutByIdSlow)
1499     loadi 20[PC], t1
1500     getPropertyStorage(
1501         t0,
1502         t3,
1503         macro (propertyStorage, scratch)
1504             addp t1, propertyStorage, t3
1505             loadConstantOrVariable2Reg(t2, t1, t2)
1506             storei t1, TagOffset[t3]
1507             loadi 24[PC], t1
1508             storei t2, PayloadOffset[t3]
1509             storep t1, JSCell::m_structureID[t0]
1510             dispatch(9)
1511         end)
1512
1513     .opPutByIdSlow:
1514         callSlowPath(_llint_slow_path_put_by_id)
1515         dispatch(9)
1516 end
1517
1518 macro noAdditionalChecks(oldStructure, scratch, slowPath)
1519 end
1520
1521 macro structureChainChecks(oldStructure, scratch, slowPath)
1522     const protoCell = oldStructure   # Reusing the oldStructure register for the proto
1523
1524     loadp 28[PC], scratch
1525     assert(macro (ok) btpnz scratch, ok end)
1526     loadp StructureChain::m_vector[scratch], scratch
1527     assert(macro (ok) btpnz scratch, ok end)
1528     bieq Structure::m_prototype + TagOffset[oldStructure], NullTag, .done
1529 .loop:
1530     loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell
1531     loadp JSCell::m_structureID[protoCell], oldStructure
1532     bpneq oldStructure, [scratch], slowPath
1533     addp 4, scratch
1534     bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop
1535 .done:
1536 end
1537
1538 _llint_op_put_by_id_transition_direct:
1539     putByIdTransition(noAdditionalChecks, withInlineStorage)
1540
1541
1542 _llint_op_put_by_id_transition_direct_out_of_line:
1543     putByIdTransition(noAdditionalChecks, withOutOfLineStorage)
1544
1545
1546 _llint_op_put_by_id_transition_normal:
1547     putByIdTransition(structureChainChecks, withInlineStorage)
1548
1549
1550 _llint_op_put_by_id_transition_normal_out_of_line:
1551     putByIdTransition(structureChainChecks, withOutOfLineStorage)
1552
1553
1554 _llint_op_get_by_val:
1555     traceExecution()
1556     loadi 8[PC], t2
1557     loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow)
1558     move t0, t2
1559     loadp 16[PC], t3
1560     arrayProfile(t2, t3, t1)
1561     loadi 12[PC], t3
1562     loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
1563     loadp JSObject::m_butterfly[t0], t3
1564     andi IndexingShapeMask, t2
1565     bieq t2, Int32Shape, .opGetByValIsContiguous
1566     bineq t2, ContiguousShape, .opGetByValNotContiguous
1567 .opGetByValIsContiguous:
1568     
1569     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds
1570     loadi TagOffset[t3, t1, 8], t2
1571     loadi PayloadOffset[t3, t1, 8], t1
1572     jmp .opGetByValDone
1573
1574 .opGetByValNotContiguous:
1575     bineq t2, DoubleShape, .opGetByValNotDouble
1576     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t3], .opGetByValOutOfBounds
1577     loadd [t3, t1, 8], ft0
1578     bdnequn ft0, ft0, .opGetByValSlow
1579     # FIXME: This could be massively optimized.
1580     fd2ii ft0, t1, t2
1581     loadi 4[PC], t0
1582     jmp .opGetByValNotEmpty
1583
1584 .opGetByValNotDouble:
1585     subi ArrayStorageShape, t2
1586     bia t2, SlowPutArrayStorageShape - ArrayStorageShape, .opGetByValSlow
1587     biaeq t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t3], .opGetByValOutOfBounds
1588     loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2
1589     loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1
1590
1591 .opGetByValDone:
1592     loadi 4[PC], t0
1593     bieq t2, EmptyValueTag, .opGetByValOutOfBounds
1594 .opGetByValNotEmpty:
1595     storei t2, TagOffset[cfr, t0, 8]
1596     storei t1, PayloadOffset[cfr, t0, 8]
1597     valueProfile(t2, t1, 20, t0)
1598     dispatch(6)
1599
1600 .opGetByValOutOfBounds:
1601     loadpFromInstruction(4, t0)
1602     storeb 1, ArrayProfile::m_outOfBounds[t0]
1603 .opGetByValSlow:
1604     callSlowPath(_llint_slow_path_get_by_val)
1605     dispatch(6)
1606
1607
1608 _llint_op_get_argument_by_val:
1609     # FIXME: At some point we should array profile this. Right now it isn't necessary
1610     # since the DFG will never turn a get_argument_by_val into a GetByVal.
1611     traceExecution()
1612     loadi 8[PC], t0
1613     loadi 12[PC], t1
1614     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentByValSlow
1615     loadConstantOrVariablePayload(t1, Int32Tag, t2, .opGetArgumentByValSlow)
1616     addi 1, t2
1617     loadi ArgumentCount + PayloadOffset[cfr], t1
1618     biaeq t2, t1, .opGetArgumentByValSlow
1619     loadi 4[PC], t3
1620     loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0
1621     loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t1
1622     storei t0, TagOffset[cfr, t3, 8]
1623     storei t1, PayloadOffset[cfr, t3, 8]
1624     valueProfile(t0, t1, 24, t2)
1625     dispatch(7)
1626
1627 .opGetArgumentByValSlow:
1628     callSlowPath(_llint_slow_path_get_argument_by_val)
1629     dispatch(7)
1630
1631
1632 macro contiguousPutByVal(storeCallback)
1633     biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .outOfBounds
1634 .storeResult:
1635     loadi 12[PC], t2
1636     storeCallback(t2, t1, t0, t3)
1637     dispatch(5)
1638
1639 .outOfBounds:
1640     biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t0], .opPutByValOutOfBounds
1641     loadp 16[PC], t2
1642     storeb 1, ArrayProfile::m_mayStoreToHole[t2]
1643     addi 1, t3, t2
1644     storei t2, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0]
1645     jmp .storeResult
1646 end
1647
1648 macro putByVal(slowPath)
1649     traceExecution()
1650     writeBarrierOnOperands(1, 3)
1651     loadi 4[PC], t0
1652     loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
1653     move t1, t2
1654     loadp 16[PC], t3
1655     arrayProfile(t2, t3, t0)
1656     loadi 8[PC], t0
1657     loadConstantOrVariablePayload(t0, Int32Tag, t3, .opPutByValSlow)
1658     loadp JSObject::m_butterfly[t1], t0
1659     andi IndexingShapeMask, t2
1660     bineq t2, Int32Shape, .opPutByValNotInt32
1661     contiguousPutByVal(
1662         macro (operand, scratch, base, index)
1663             loadConstantOrVariablePayload(operand, Int32Tag, scratch, .opPutByValSlow)
1664             storei Int32Tag, TagOffset[base, index, 8]
1665             storei scratch, PayloadOffset[base, index, 8]
1666         end)
1667
1668 .opPutByValNotInt32:
1669     bineq t2, DoubleShape, .opPutByValNotDouble
1670     contiguousPutByVal(
1671         macro (operand, scratch, base, index)
1672             const tag = scratch
1673             const payload = operand
1674             loadConstantOrVariable2Reg(operand, tag, payload)
1675             bineq tag, Int32Tag, .notInt
1676             ci2d payload, ft0
1677             jmp .ready
1678         .notInt:
1679             fii2d payload, tag, ft0
1680             bdnequn ft0, ft0, .opPutByValSlow
1681         .ready:
1682             stored ft0, [base, index, 8]
1683         end)
1684
1685 .opPutByValNotDouble:
1686     bineq t2, ContiguousShape, .opPutByValNotContiguous
1687     contiguousPutByVal(
1688         macro (operand, scratch, base, index)
1689             const tag = scratch
1690             const payload = operand
1691             loadConstantOrVariable2Reg(operand, tag, payload)
1692             storei tag, TagOffset[base, index, 8]
1693             storei payload, PayloadOffset[base, index, 8]
1694         end)
1695
1696 .opPutByValNotContiguous:
1697     bineq t2, ArrayStorageShape, .opPutByValSlow
1698     biaeq t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.vectorLength[t0], .opPutByValOutOfBounds
1699     bieq ArrayStorage::m_vector + TagOffset[t0, t3, 8], EmptyValueTag, .opPutByValArrayStorageEmpty
1700 .opPutByValArrayStorageStoreResult:
1701     loadi 12[PC], t2
1702     loadConstantOrVariable2Reg(t2, t1, t2)
1703     storei t1, ArrayStorage::m_vector + TagOffset[t0, t3, 8]
1704     storei t2, ArrayStorage::m_vector + PayloadOffset[t0, t3, 8]
1705     dispatch(5)
1706
1707 .opPutByValArrayStorageEmpty:
1708     loadp 16[PC], t1
1709     storeb 1, ArrayProfile::m_mayStoreToHole[t1]
1710     addi 1, ArrayStorage::m_numValuesInVector[t0]
1711     bib t3, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0], .opPutByValArrayStorageStoreResult
1712     addi 1, t3, t1
1713     storei t1, -sizeof IndexingHeader + IndexingHeader::u.lengths.publicLength[t0]
1714     jmp .opPutByValArrayStorageStoreResult
1715
1716 .opPutByValOutOfBounds:
1717     loadpFromInstruction(4, t0)
1718     storeb 1, ArrayProfile::m_outOfBounds[t0]
1719 .opPutByValSlow:
1720     callSlowPath(slowPath)
1721     dispatch(5)
1722 end
1723
1724 _llint_op_put_by_val:
1725     putByVal(_llint_slow_path_put_by_val)
1726
1727 _llint_op_put_by_val_direct:
1728     putByVal(_llint_slow_path_put_by_val_direct)
1729
1730 _llint_op_jmp:
1731     traceExecution()
1732     dispatchBranch(4[PC])
1733
1734
1735 macro jumpTrueOrFalse(conditionOp, slow)
1736     loadi 4[PC], t1
1737     loadConstantOrVariablePayload(t1, BooleanTag, t0, .slow)
1738     conditionOp(t0, .target)
1739     dispatch(3)
1740
1741 .target:
1742     dispatchBranch(8[PC])
1743
1744 .slow:
1745     callSlowPath(slow)
1746     dispatch(0)
1747 end
1748
1749
1750 macro equalNull(cellHandler, immediateHandler)
1751     loadi 4[PC], t0
1752     assertNotConstant(t0)
1753     loadi TagOffset[cfr, t0, 8], t1
1754     loadi PayloadOffset[cfr, t0, 8], t0
1755     bineq t1, CellTag, .immediate
1756     loadp JSCell::m_structureID[t0], t2
1757     cellHandler(t2, JSCell::m_flags[t0], .target)
1758     dispatch(3)
1759
1760 .target:
1761     dispatchBranch(8[PC])
1762
1763 .immediate:
1764     ori 1, t1
1765     immediateHandler(t1, .target)
1766     dispatch(3)
1767 end
1768
1769 _llint_op_jeq_null:
1770     traceExecution()
1771     equalNull(
1772         macro (structure, value, target) 
1773             btbz value, MasqueradesAsUndefined, .opJeqNullNotMasqueradesAsUndefined
1774             loadp CodeBlock[cfr], t0
1775             loadp CodeBlock::m_globalObject[t0], t0
1776             bpeq Structure::m_globalObject[structure], t0, target
1777 .opJeqNullNotMasqueradesAsUndefined:
1778         end,
1779         macro (value, target) bieq value, NullTag, target end)
1780     
1781
1782 _llint_op_jneq_null:
1783     traceExecution()
1784     equalNull(
1785         macro (structure, value, target) 
1786             btbz value, MasqueradesAsUndefined, target 
1787             loadp CodeBlock[cfr], t0
1788             loadp CodeBlock::m_globalObject[t0], t0
1789             bpneq Structure::m_globalObject[structure], t0, target
1790         end,
1791         macro (value, target) bineq value, NullTag, target end)
1792
1793
1794 _llint_op_jneq_ptr:
1795     traceExecution()
1796     loadi 4[PC], t0
1797     loadi 8[PC], t1
1798     loadp CodeBlock[cfr], t2
1799     loadp CodeBlock::m_globalObject[t2], t2
1800     bineq TagOffset[cfr, t0, 8], CellTag, .opJneqPtrBranch
1801     loadp JSGlobalObject::m_specialPointers[t2, t1, 4], t1
1802     bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough
1803 .opJneqPtrBranch:
1804     dispatchBranch(12[PC])
1805 .opJneqPtrFallThrough:
1806     dispatch(4)
1807
1808
1809 macro compare(integerCompare, doubleCompare, slowPath)
1810     loadi 4[PC], t2
1811     loadi 8[PC], t3
1812     loadConstantOrVariable(t2, t0, t1)
1813     loadConstantOrVariable2Reg(t3, t2, t3)
1814     bineq t0, Int32Tag, .op1NotInt
1815     bineq t2, Int32Tag, .op2NotInt
1816     integerCompare(t1, t3, .jumpTarget)
1817     dispatch(4)
1818
1819 .op1NotInt:
1820     bia t0, LowestTag, .slow
1821     bib t2, LowestTag, .op1NotIntOp2Double
1822     bineq t2, Int32Tag, .slow
1823     ci2d t3, ft1
1824     jmp .op1NotIntReady
1825 .op1NotIntOp2Double:
1826     fii2d t3, t2, ft1
1827 .op1NotIntReady:
1828     fii2d t1, t0, ft0
1829     doubleCompare(ft0, ft1, .jumpTarget)
1830     dispatch(4)
1831
1832 .op2NotInt:
1833     ci2d t1, ft0
1834     bia t2, LowestTag, .slow
1835     fii2d t3, t2, ft1
1836     doubleCompare(ft0, ft1, .jumpTarget)
1837     dispatch(4)
1838
1839 .jumpTarget:
1840     dispatchBranch(12[PC])
1841
1842 .slow:
1843     callSlowPath(slowPath)
1844     dispatch(0)
1845 end
1846
1847
1848 _llint_op_switch_imm:
1849     traceExecution()
1850     loadi 12[PC], t2
1851     loadi 4[PC], t3
1852     loadConstantOrVariable(t2, t1, t0)
1853     loadp CodeBlock[cfr], t2
1854     loadp CodeBlock::m_rareData[t2], t2
1855     muli sizeof SimpleJumpTable, t3   # FIXME: would be nice to peephole this!
1856     loadp CodeBlock::RareData::m_switchJumpTables + VectorBufferOffset[t2], t2
1857     addp t3, t2
1858     bineq t1, Int32Tag, .opSwitchImmNotInt
1859     subi SimpleJumpTable::min[t2], t0
1860     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchImmFallThrough
1861     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t3
1862     loadi [t3, t0, 4], t1
1863     btiz t1, .opSwitchImmFallThrough
1864     dispatchBranchWithOffset(t1)
1865
1866 .opSwitchImmNotInt:
1867     bib t1, LowestTag, .opSwitchImmSlow  # Go to slow path if it's a double.
1868 .opSwitchImmFallThrough:
1869     dispatchBranch(8[PC])
1870
1871 .opSwitchImmSlow:
1872     callSlowPath(_llint_slow_path_switch_imm)
1873     dispatch(0)
1874
1875
1876 _llint_op_switch_char:
1877     traceExecution()
1878     loadi 12[PC], t2
1879     loadi 4[PC], t3
1880     loadConstantOrVariable(t2, t1, t0)
1881     loadp CodeBlock[cfr], t2
1882     loadp CodeBlock::m_rareData[t2], t2
1883     muli sizeof SimpleJumpTable, t3
1884     loadp CodeBlock::RareData::m_switchJumpTables + VectorBufferOffset[t2], t2
1885     addp t3, t2
1886     bineq t1, CellTag, .opSwitchCharFallThrough
1887     bbneq JSCell::m_type[t0], StringType, .opSwitchCharFallThrough
1888     bineq JSString::m_length[t0], 1, .opSwitchCharFallThrough
1889     loadp JSString::m_value[t0], t0
1890     btpz  t0, .opSwitchOnRope
1891     loadp StringImpl::m_data8[t0], t1
1892     btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
1893     loadh [t1], t0
1894     jmp .opSwitchCharReady
1895 .opSwitchChar8Bit:
1896     loadb [t1], t0
1897 .opSwitchCharReady:
1898     subi SimpleJumpTable::min[t2], t0
1899     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchCharFallThrough
1900     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t2
1901     loadi [t2, t0, 4], t1
1902     btiz t1, .opSwitchCharFallThrough
1903     dispatchBranchWithOffset(t1)
1904
1905 .opSwitchCharFallThrough:
1906     dispatchBranch(8[PC])
1907
1908 .opSwitchOnRope:
1909     callSlowPath(_llint_slow_path_switch_char)
1910     dispatch(0)
1911
1912
1913 _llint_op_new_func:
1914     traceExecution()
1915     btiz 16[PC], .opNewFuncUnchecked
1916     loadi 4[PC], t1
1917     bineq TagOffset[cfr, t1, 8], EmptyValueTag, .opNewFuncDone
1918 .opNewFuncUnchecked:
1919     callSlowPath(_llint_slow_path_new_func)
1920 .opNewFuncDone:
1921     dispatch(5)
1922
1923 macro arrayProfileForCall()
1924     loadi 16[PC], t3
1925     negi t3
1926     bineq ThisArgumentOffset + TagOffset[cfr, t3, 8], CellTag, .done
1927     loadi ThisArgumentOffset + PayloadOffset[cfr, t3, 8], t0
1928     loadp JSCell::m_structureID[t0], t0
1929     loadpFromInstruction(CallOpCodeSize - 2, t1)
1930     storep t0, ArrayProfile::m_lastSeenStructureID[t1]
1931 .done:
1932 end
1933
1934 macro doCall(slowPath)
1935     loadi 8[PC], t0
1936     loadi 20[PC], t1
1937     loadp LLIntCallLinkInfo::callee[t1], t2
1938     loadConstantOrVariablePayload(t0, CellTag, t3, .opCallSlow)
1939     bineq t3, t2, .opCallSlow
1940     loadi 16[PC], t3
1941     lshifti 3, t3
1942     negi t3
1943     addp cfr, t3  # t3 contains the new value of cfr
1944     storei t2, Callee + PayloadOffset[t3]
1945     loadi 12[PC], t2
1946     storei PC, ArgumentCount + TagOffset[cfr]
1947     storei t2, ArgumentCount + PayloadOffset[t3]
1948     storei CellTag, Callee + TagOffset[t3]
1949     addp CallerFrameAndPCSize, t3
1950     callTargetFunction(t1, t3)
1951
1952 .opCallSlow:
1953     slowPathForCall(slowPath)
1954 end
1955
1956 _llint_op_tear_off_arguments:
1957     traceExecution()
1958     loadi 4[PC], t0
1959     bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffArgumentsNotCreated
1960     callSlowPath(_llint_slow_path_tear_off_arguments)
1961 .opTearOffArgumentsNotCreated:
1962     dispatch(3)
1963
1964
1965 _llint_op_ret:
1966     traceExecution()
1967     checkSwitchToJITForEpilogue()
1968     loadi 4[PC], t2
1969     loadConstantOrVariable(t2, t1, t0)
1970     doReturn()
1971
1972
1973 _llint_op_to_primitive:
1974     traceExecution()
1975     loadi 8[PC], t2
1976     loadi 4[PC], t3
1977     loadConstantOrVariable(t2, t1, t0)
1978     bineq t1, CellTag, .opToPrimitiveIsImm
1979     bbneq JSCell::m_type[t0], StringType, .opToPrimitiveSlowCase
1980 .opToPrimitiveIsImm:
1981     storei t1, TagOffset[cfr, t3, 8]
1982     storei t0, PayloadOffset[cfr, t3, 8]
1983     dispatch(3)
1984
1985 .opToPrimitiveSlowCase:
1986     callSlowPath(_slow_path_to_primitive)
1987     dispatch(3)
1988
1989
1990 _llint_op_catch:
1991     # This is where we end up from the JIT's throw trampoline (because the
1992     # machine code return address will be set to _llint_op_catch), and from
1993     # the interpreter's throw trampoline (see _llint_throw_trampoline).
1994     # The throwing code must have known that we were throwing to the interpreter,
1995     # and have set VM::targetInterpreterPCForThrow.
1996     loadp Callee + PayloadOffset[cfr], t3
1997     andp MarkedBlockMask, t3
1998     loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
1999     loadp VM::callFrameForThrow[t3], cfr
2000     loadp VM::vmEntryFrameForThrow[t3], t0
2001     storep t0, VM::topVMEntryFrame[t3]
2002     restoreStackPointerAfterCall()
2003
2004     loadi VM::targetInterpreterPCForThrow[t3], PC
2005     loadi VM::m_exception + PayloadOffset[t3], t0
2006     loadi VM::m_exception + TagOffset[t3], t1
2007     storei 0, VM::m_exception + PayloadOffset[t3]
2008     storei EmptyValueTag, VM::m_exception + TagOffset[t3]
2009     loadi 4[PC], t2
2010     storei t0, PayloadOffset[cfr, t2, 8]
2011     storei t1, TagOffset[cfr, t2, 8]
2012     traceExecution()  # This needs to be here because we don't want to clobber t0, t1, t2, t3 above.
2013     dispatch(2)
2014
2015 _llint_op_end:
2016     traceExecution()
2017     checkSwitchToJITForEpilogue()
2018     loadi 4[PC], t0
2019     assertNotConstant(t0)
2020     loadi TagOffset[cfr, t0, 8], t1
2021     loadi PayloadOffset[cfr, t0, 8], t0
2022     doReturn()
2023
2024
2025 _llint_throw_from_slow_path_trampoline:
2026     callSlowPath(_llint_slow_path_handle_exception)
2027
2028     # When throwing from the interpreter (i.e. throwing from LLIntSlowPaths), so
2029     # the throw target is not necessarily interpreted code, we come to here.
2030     # This essentially emulates the JIT's throwing protocol.
2031     loadp CodeBlock[cfr], t1
2032     loadp CodeBlock::m_vm[t1], t1
2033     jmp VM::targetMachinePCForThrow[t1]
2034
2035
2036 _llint_throw_during_call_trampoline:
2037     preserveReturnAddressAfterCall(t2)
2038     jmp _llint_throw_from_slow_path_trampoline
2039
2040
2041 macro nativeCallTrampoline(executableOffsetToFunction)
2042
2043     functionPrologue()
2044     storep 0, CodeBlock[cfr]
2045     loadi Callee + PayloadOffset[cfr], t1
2046     // Callee is still in t1 for code below
2047     if X86 or X86_WIN
2048         subp 8, sp # align stack pointer
2049         andp MarkedBlockMask, t1
2050         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t3
2051         storep cfr, VM::topCallFrame[t3]
2052         move cfr, t2  # t2 = ecx
2053         storep t2, [sp]
2054         loadi Callee + PayloadOffset[cfr], t1
2055         loadp JSFunction::m_executable[t1], t1
2056         checkStackPointerAlignment(t3, 0xdead0001)
2057         call executableOffsetToFunction[t1]
2058         loadp Callee + PayloadOffset[cfr], t3
2059         andp MarkedBlockMask, t3
2060         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
2061         addp 8, sp
2062     elsif ARM or ARMv7 or ARMv7_TRADITIONAL or C_LOOP or MIPS or SH4
2063         subp 8, sp # align stack pointer
2064         # t1 already contains the Callee.
2065         andp MarkedBlockMask, t1
2066         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t1], t1
2067         storep cfr, VM::topCallFrame[t1]
2068         if MIPS or SH4
2069             move cfr, a0
2070         else
2071             move cfr, t0
2072         end
2073         loadi Callee + PayloadOffset[cfr], t1
2074         loadp JSFunction::m_executable[t1], t1
2075         checkStackPointerAlignment(t3, 0xdead0001)
2076         if C_LOOP
2077             cloopCallNative executableOffsetToFunction[t1]
2078         else
2079             call executableOffsetToFunction[t1]
2080         end
2081         loadp Callee + PayloadOffset[cfr], t3
2082         andp MarkedBlockMask, t3
2083         loadp MarkedBlock::m_weakSet + WeakSet::m_vm[t3], t3
2084         addp 8, sp
2085     else
2086         error
2087     end
2088     
2089     functionEpilogue()
2090     bineq VM::m_exception + TagOffset[t3], EmptyValueTag, .handleException
2091     ret
2092
2093 .handleException:
2094     storep cfr, VM::topCallFrame[t3]
2095     restoreStackPointerAfterCall()
2096     jmp _llint_throw_from_slow_path_trampoline
2097 end
2098
2099
2100 macro getGlobalObject(dst)
2101     loadp CodeBlock[cfr], t0
2102     loadp CodeBlock::m_globalObject[t0], t0
2103     loadisFromInstruction(dst, t1)
2104     storei CellTag, TagOffset[cfr, t1, 8]
2105     storei t0, PayloadOffset[cfr, t1, 8]
2106 end
2107
2108 macro varInjectionCheck(slowPath)
2109     loadp CodeBlock[cfr], t0
2110     loadp CodeBlock::m_globalObject[t0], t0
2111     loadp JSGlobalObject::m_varInjectionWatchpoint[t0], t0
2112     bbeq WatchpointSet::m_state[t0], IsInvalidated, slowPath
2113 end
2114
2115 macro resolveScope()
2116     loadp CodeBlock[cfr], t0
2117     loadisFromInstruction(5, t2)
2118
2119     loadisFromInstruction(2, t0)
2120     loadp PayloadOffset[cfr, t0, 8], t0
2121     btiz t2, .resolveScopeLoopEnd
2122
2123 .resolveScopeLoop:
2124     loadp JSScope::m_next[t0], t0
2125     subi 1, t2
2126     btinz t2, .resolveScopeLoop
2127
2128 .resolveScopeLoopEnd:
2129     loadisFromInstruction(1, t1)
2130     storei CellTag, TagOffset[cfr, t1, 8]
2131     storei t0, PayloadOffset[cfr, t1, 8]
2132 end
2133
2134
2135 _llint_op_resolve_scope:
2136     traceExecution()
2137     loadisFromInstruction(4, t0)
2138
2139 #rGlobalProperty:
2140     bineq t0, GlobalProperty, .rGlobalVar
2141     getGlobalObject(1)
2142     dispatch(7)
2143
2144 .rGlobalVar:
2145     bineq t0, GlobalVar, .rClosureVar
2146     getGlobalObject(1)
2147     dispatch(7)
2148
2149 .rClosureVar:
2150     bineq t0, ClosureVar, .rGlobalPropertyWithVarInjectionChecks
2151     resolveScope()
2152     dispatch(7)
2153
2154 .rGlobalPropertyWithVarInjectionChecks:
2155     bineq t0, GlobalPropertyWithVarInjectionChecks, .rGlobalVarWithVarInjectionChecks
2156     varInjectionCheck(.rDynamic)
2157     getGlobalObject(1)
2158     dispatch(7)
2159
2160 .rGlobalVarWithVarInjectionChecks:
2161     bineq t0, GlobalVarWithVarInjectionChecks, .rClosureVarWithVarInjectionChecks
2162     varInjectionCheck(.rDynamic)
2163     getGlobalObject(1)
2164     dispatch(7)
2165
2166 .rClosureVarWithVarInjectionChecks:
2167     bineq t0, ClosureVarWithVarInjectionChecks, .rDynamic
2168     varInjectionCheck(.rDynamic)
2169     resolveScope()
2170     dispatch(7)
2171
2172 .rDynamic:
2173     callSlowPath(_llint_slow_path_resolve_scope)
2174     dispatch(7)
2175
2176
2177 macro loadWithStructureCheck(operand, slowPath)
2178     loadisFromInstruction(operand, t0)
2179     loadp PayloadOffset[cfr, t0, 8], t0
2180     loadpFromInstruction(5, t1)
2181     bpneq JSCell::m_structureID[t0], t1, slowPath
2182 end
2183
2184 macro getProperty()
2185     loadisFromInstruction(6, t3)
2186     loadPropertyAtVariableOffset(t3, t0, t1, t2)
2187     valueProfile(t1, t2, 28, t0)
2188     loadisFromInstruction(1, t0)
2189     storei t1, TagOffset[cfr, t0, 8]
2190     storei t2, PayloadOffset[cfr, t0, 8]
2191 end
2192
2193 macro getGlobalVar()
2194     loadpFromInstruction(6, t0)
2195     loadp TagOffset[t0], t1
2196     loadp PayloadOffset[t0], t2
2197     valueProfile(t1, t2, 28, t0)
2198     loadisFromInstruction(1, t0)
2199     storei t1, TagOffset[cfr, t0, 8]
2200     storei t2, PayloadOffset[cfr, t0, 8]
2201 end
2202
2203 macro getClosureVar()
2204     loadp JSEnvironmentRecord::m_registers[t0], t0
2205     loadisFromInstruction(6, t3)
2206     loadp TagOffset[t0, t3, 8], t1
2207     loadp PayloadOffset[t0, t3, 8], t2
2208     valueProfile(t1, t2, 28, t0)
2209     loadisFromInstruction(1, t0)
2210     storei t1, TagOffset[cfr, t0, 8]
2211     storei t2, PayloadOffset[cfr, t0, 8]
2212 end
2213
2214 _llint_op_get_from_scope:
2215     traceExecution()
2216     loadisFromInstruction(4, t0)
2217     andi ResolveModeMask, t0
2218
2219 #gGlobalProperty:
2220     bineq t0, GlobalProperty, .gGlobalVar
2221     loadWithStructureCheck(2, .gDynamic)
2222     getProperty()
2223     dispatch(8)
2224
2225 .gGlobalVar:
2226     bineq t0, GlobalVar, .gClosureVar
2227     getGlobalVar()
2228     dispatch(8)
2229
2230 .gClosureVar:
2231     bineq t0, ClosureVar, .gGlobalPropertyWithVarInjectionChecks
2232     loadVariable(2, t2, t1, t0)
2233     getClosureVar()
2234     dispatch(8)
2235
2236 .gGlobalPropertyWithVarInjectionChecks:
2237     bineq t0, GlobalPropertyWithVarInjectionChecks, .gGlobalVarWithVarInjectionChecks
2238     loadWithStructureCheck(2, .gDynamic)
2239     getProperty()
2240     dispatch(8)
2241
2242 .gGlobalVarWithVarInjectionChecks:
2243     bineq t0, GlobalVarWithVarInjectionChecks, .gClosureVarWithVarInjectionChecks
2244     varInjectionCheck(.gDynamic)
2245     loadVariable(2, t2, t1, t0)
2246     getGlobalVar()
2247     dispatch(8)
2248
2249 .gClosureVarWithVarInjectionChecks:
2250     bineq t0, ClosureVarWithVarInjectionChecks, .gDynamic
2251     varInjectionCheck(.gDynamic)
2252     loadVariable(2, t2, t1, t0)
2253     getClosureVar()
2254     dispatch(8)
2255
2256 .gDynamic:
2257     callSlowPath(_llint_slow_path_get_from_scope)
2258     dispatch(8)
2259
2260
2261 macro putProperty()
2262     loadisFromInstruction(3, t1)
2263     loadConstantOrVariable(t1, t2, t3)
2264     loadisFromInstruction(6, t1)
2265     storePropertyAtVariableOffset(t1, t0, t2, t3)
2266 end
2267
2268 macro putGlobalVar()
2269     loadisFromInstruction(3, t0)
2270     loadConstantOrVariable(t0, t1, t2)
2271     loadpFromInstruction(5, t3)
2272     notifyWrite(t3, t1, t2, t0, .pDynamic)
2273     loadpFromInstruction(6, t0)
2274     storei t1, TagOffset[t0]
2275     storei t2, PayloadOffset[t0]
2276 end
2277
2278 macro putClosureVar()
2279     loadisFromInstruction(3, t1)
2280     loadConstantOrVariable(t1, t2, t3)
2281     loadp JSEnvironmentRecord::m_registers[t0], t0
2282     loadisFromInstruction(6, t1)
2283     storei t2, TagOffset[t0, t1, 8]
2284     storei t3, PayloadOffset[t0, t1, 8]
2285 end
2286
2287 macro putLocalClosureVar()
2288     loadisFromInstruction(3, t1)
2289     loadConstantOrVariable(t1, t2, t3)
2290     loadpFromInstruction(5, t4)
2291     btpz t4, .noVariableWatchpointSet
2292     notifyWrite(t4, t2, t3, t1, .pDynamic)
2293 .noVariableWatchpointSet:
2294     loadp JSEnvironmentRecord::m_registers[t0], t0
2295     loadisFromInstruction(6, t1)
2296     storei t2, TagOffset[t0, t1, 8]
2297     storei t3, PayloadOffset[t0, t1, 8]
2298 end
2299
2300
2301 _llint_op_put_to_scope:
2302     traceExecution()
2303     loadisFromInstruction(4, t0)
2304     andi ResolveModeMask, t0
2305
2306 #pLocalClosureVar:
2307     bineq t0, LocalClosureVar, .pGlobalProperty
2308     writeBarrierOnOperands(1, 3)
2309     loadVariable(1, t2, t1, t0)
2310     putLocalClosureVar()
2311     dispatch(7)
2312
2313 .pGlobalProperty:
2314     bineq t0, GlobalProperty, .pGlobalVar
2315     writeBarrierOnOperands(1, 3)
2316     loadWithStructureCheck(1, .pDynamic)
2317     putProperty()
2318     dispatch(7)
2319
2320 .pGlobalVar:
2321     bineq t0, GlobalVar, .pClosureVar
2322     writeBarrierOnGlobalObject(3)
2323     putGlobalVar()
2324     dispatch(7)
2325
2326 .pClosureVar:
2327     bineq t0, ClosureVar, .pGlobalPropertyWithVarInjectionChecks
2328     writeBarrierOnOperands(1, 3)
2329     loadVariable(1, t2, t1, t0)
2330     putClosureVar()
2331     dispatch(7)
2332
2333 .pGlobalPropertyWithVarInjectionChecks:
2334     bineq t0, GlobalPropertyWithVarInjectionChecks, .pGlobalVarWithVarInjectionChecks
2335     writeBarrierOnOperands(1, 3)
2336     loadWithStructureCheck(1, .pDynamic)
2337     putProperty()
2338     dispatch(7)
2339
2340 .pGlobalVarWithVarInjectionChecks:
2341     bineq t0, GlobalVarWithVarInjectionChecks, .pClosureVarWithVarInjectionChecks
2342     writeBarrierOnGlobalObject(3)
2343     varInjectionCheck(.pDynamic)
2344     putGlobalVar()
2345     dispatch(7)
2346
2347 .pClosureVarWithVarInjectionChecks:
2348     bineq t0, ClosureVarWithVarInjectionChecks, .pDynamic
2349     writeBarrierOnOperands(1, 3)
2350     varInjectionCheck(.pDynamic)
2351     loadVariable(1, t2, t1, t0)
2352     putClosureVar()
2353     dispatch(7)
2354
2355 .pDynamic:
2356     callSlowPath(_llint_slow_path_put_to_scope)
2357     dispatch(7)
2358
2359 _llint_op_profile_type:
2360     traceExecution()
2361     loadp CodeBlock[cfr], t1
2362     loadp CodeBlock::m_vm[t1], t1
2363     # t1 is holding the pointer to the typeProfilerLog.
2364     loadp VM::m_typeProfilerLog[t1], t1
2365
2366     # t0 is holding the payload, t4 is holding the tag.
2367     loadisFromInstruction(1, t2)
2368     loadConstantOrVariable(t2, t4, t0)
2369
2370     # t2 is holding the pointer to the current log entry.
2371     loadp TypeProfilerLog::m_currentLogEntryPtr[t1], t2
2372
2373     # Store the JSValue onto the log entry.
2374     storei t4, TypeProfilerLog::LogEntry::value + TagOffset[t2]
2375     storei t0, TypeProfilerLog::LogEntry::value + PayloadOffset[t2]
2376
2377     # Store the TypeLocation onto the log entry.
2378     loadpFromInstruction(2, t3)
2379     storep t3, TypeProfilerLog::LogEntry::location[t2]
2380
2381     bieq t4, CellTag, .opProfileTypeIsCell
2382     storei 0, TypeProfilerLog::LogEntry::structureID[t2]
2383     jmp .opProfileTypeSkipIsCell
2384 .opProfileTypeIsCell:
2385     loadi JSCell::m_structureID[t0], t3
2386     storei t3, TypeProfilerLog::LogEntry::structureID[t2]
2387 .opProfileTypeSkipIsCell:
2388     
2389     # Increment the current log entry.
2390     addp sizeof TypeProfilerLog::LogEntry, t2
2391     storep t2, TypeProfilerLog::m_currentLogEntryPtr[t1]
2392
2393     loadp TypeProfilerLog::m_logEndPtr[t1], t1
2394     bpneq t2, t1, .opProfileTypeDone
2395     callSlowPath(_slow_path_profile_type_clear_log)
2396
2397 .opProfileTypeDone:
2398     dispatch(6)