jneq_ptr shouldn't have a pointer
[WebKit-https.git] / Source / JavaScriptCore / llint / LowLevelInterpreter32_64.asm
1 # Copyright (C) 2011, 2012 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
74 # Value representation constants.
75 const Int32Tag = -1
76 const BooleanTag = -2
77 const NullTag = -3
78 const UndefinedTag = -4
79 const CellTag = -5
80 const EmptyValueTag = -6
81 const DeletedValueTag = -7
82 const LowestTag = DeletedValueTag
83
84
85 # Utilities
86 macro dispatch(advance)
87     addp advance * 4, PC
88     jmp [PC]
89 end
90
91 macro dispatchBranchWithOffset(pcOffset)
92     lshifti 2, pcOffset
93     addp pcOffset, PC
94     jmp [PC]
95 end
96
97 macro dispatchBranch(pcOffset)
98     loadi pcOffset, t0
99     dispatchBranchWithOffset(t0)
100 end
101
102 macro dispatchAfterCall()
103     loadi ArgumentCount + TagOffset[cfr], PC
104     jmp [PC]
105 end
106
107 macro cCall2(function, arg1, arg2)
108     if ARMv7
109         move arg1, t0
110         move arg2, t1
111         call function
112     elsif X86
113         poke arg1, 0
114         poke arg2, 1
115         call function
116     elsif C_LOOP
117         cloopCallSlowPath function, arg1, arg2
118     else
119         error
120     end
121 end
122
123 # This barely works. arg3 and arg4 should probably be immediates.
124 macro cCall4(function, arg1, arg2, arg3, arg4)
125     if ARMv7
126         move arg1, t0
127         move arg2, t1
128         move arg3, t2
129         move arg4, t3
130         call function
131     elsif X86
132         poke arg1, 0
133         poke arg2, 1
134         poke arg3, 2
135         poke arg4, 3
136         call function
137     elsif C_LOOP
138         error
139     else
140         error
141     end
142 end
143
144 macro callSlowPath(slowPath)
145     cCall2(slowPath, cfr, PC)
146     move t0, PC
147     move t1, cfr
148 end
149
150 # Debugging operation if you'd like to print an operand in the instruction stream. fromWhere
151 # should be an immediate integer - any integer you like; use it to identify the place you're
152 # debugging from. operand should likewise be an immediate, and should identify the operand
153 # in the instruction stream you'd like to print out.
154 macro traceOperand(fromWhere, operand)
155     cCall4(_llint_trace_operand, cfr, PC, fromWhere, operand)
156     move t0, PC
157     move t1, cfr
158 end
159
160 # Debugging operation if you'd like to print the value of an operand in the instruction
161 # stream. Same as traceOperand(), but assumes that the operand is a register, and prints its
162 # value.
163 macro traceValue(fromWhere, operand)
164     cCall4(_llint_trace_value, cfr, PC, fromWhere, operand)
165     move t0, PC
166     move t1, cfr
167 end
168
169 # Call a slowPath for call opcodes.
170 macro callCallSlowPath(advance, slowPath, action)
171     addp advance * 4, PC, t0
172     storep t0, ArgumentCount + TagOffset[cfr]
173     cCall2(slowPath, cfr, PC)
174     move t1, cfr
175     action(t0)
176 end
177
178 macro checkSwitchToJITForLoop()
179     checkSwitchToJIT(
180         1,
181         macro ()
182             storei PC, ArgumentCount + TagOffset[cfr]
183             cCall2(_llint_loop_osr, cfr, PC)
184             move t1, cfr
185             btpz t0, .recover
186             jmp t0
187         .recover:
188             loadi ArgumentCount + TagOffset[cfr], PC
189         end)
190 end
191
192 # Index, tag, and payload must be different registers. Index is not
193 # changed.
194 macro loadConstantOrVariable(index, tag, payload)
195     bigteq index, FirstConstantRegisterIndex, .constant
196     loadi TagOffset[cfr, index, 8], tag
197     loadi PayloadOffset[cfr, index, 8], payload
198     jmp .done
199 .constant:
200     loadp CodeBlock[cfr], payload
201     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload
202     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
203     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
204     loadp TagOffset[payload, index, 8], tag
205     loadp PayloadOffset[payload, index, 8], payload
206 .done:
207 end
208
209 macro loadConstantOrVariableTag(index, tag)
210     bigteq index, FirstConstantRegisterIndex, .constant
211     loadi TagOffset[cfr, index, 8], tag
212     jmp .done
213 .constant:
214     loadp CodeBlock[cfr], tag
215     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[tag], tag
216     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
217     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
218     loadp TagOffset[tag, index, 8], tag
219 .done:
220 end
221
222 # Index and payload may be the same register. Index may be clobbered.
223 macro loadConstantOrVariable2Reg(index, tag, payload)
224     bigteq index, FirstConstantRegisterIndex, .constant
225     loadi TagOffset[cfr, index, 8], tag
226     loadi PayloadOffset[cfr, index, 8], payload
227     jmp .done
228 .constant:
229     loadp CodeBlock[cfr], tag
230     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[tag], tag
231     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
232     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
233     lshifti 3, index
234     addp index, tag
235     loadp PayloadOffset[tag], payload
236     loadp TagOffset[tag], tag
237 .done:
238 end
239
240 macro loadConstantOrVariablePayloadTagCustom(index, tagCheck, payload)
241     bigteq index, FirstConstantRegisterIndex, .constant
242     tagCheck(TagOffset[cfr, index, 8])
243     loadi PayloadOffset[cfr, index, 8], payload
244     jmp .done
245 .constant:
246     loadp CodeBlock[cfr], payload
247     loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload
248     # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
249     # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
250     tagCheck(TagOffset[payload, index, 8])
251     loadp PayloadOffset[payload, index, 8], payload
252 .done:
253 end
254
255 # Index and payload must be different registers. Index is not mutated. Use
256 # this if you know what the tag of the variable should be. Doing the tag
257 # test as part of loading the variable reduces register use, but may not
258 # be faster than doing loadConstantOrVariable followed by a branch on the
259 # tag.
260 macro loadConstantOrVariablePayload(index, expectedTag, payload, slow)
261     loadConstantOrVariablePayloadTagCustom(
262         index,
263         macro (actualTag) bineq actualTag, expectedTag, slow end,
264         payload)
265 end
266
267 macro loadConstantOrVariablePayloadUnchecked(index, payload)
268     loadConstantOrVariablePayloadTagCustom(
269         index,
270         macro (actualTag) end,
271         payload)
272 end
273
274 macro writeBarrier(tag, payload)
275     # Nothing to do, since we don't have a generational or incremental collector.
276 end
277
278 macro valueProfile(tag, payload, profile)
279     if VALUE_PROFILER
280         storei tag, ValueProfile::m_buckets + TagOffset[profile]
281         storei payload, ValueProfile::m_buckets + PayloadOffset[profile]
282     end
283 end
284
285
286 # Entrypoints into the interpreter
287
288 # Expects that CodeBlock is in t1, which is what prologue() leaves behind.
289 macro functionArityCheck(doneLabel, slow_path)
290     loadi PayloadOffset + ArgumentCount[cfr], t0
291     biaeq t0, CodeBlock::m_numParameters[t1], doneLabel
292     cCall2(slow_path, cfr, PC)   # This slow_path has a simple protocol: t0 = 0 => no error, t0 != 0 => error
293     move t1, cfr
294     btiz t0, .continue
295     loadp JITStackFrame::globalData[sp], t1
296     loadp JSGlobalData::callFrameForThrow[t1], t0
297     jmp JSGlobalData::targetMachinePCForThrow[t1]
298 .continue:
299     # Reload CodeBlock and PC, since the slow_path clobbered it.
300     loadp CodeBlock[cfr], t1
301     loadp CodeBlock::m_instructions[t1], PC
302     jmp doneLabel
303 end
304
305
306 # Instruction implementations
307
308 _llint_op_enter:
309     traceExecution()
310     loadp CodeBlock[cfr], t2                // t2<CodeBlock> = cfr.CodeBlock
311     loadi CodeBlock::m_numVars[t2], t2      // t2<size_t> = t2<CodeBlock>.m_numVars
312     btiz t2, .opEnterDone
313     move UndefinedTag, t0
314     move 0, t1
315 .opEnterLoop:
316     subi 1, t2
317     storei t0, TagOffset[cfr, t2, 8]
318     storei t1, PayloadOffset[cfr, t2, 8]
319     btinz t2, .opEnterLoop
320 .opEnterDone:
321     dispatch(1)
322
323
324 _llint_op_create_activation:
325     traceExecution()
326     loadi 4[PC], t0
327     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateActivationDone
328     callSlowPath(_llint_slow_path_create_activation)
329 .opCreateActivationDone:
330     dispatch(2)
331
332
333 _llint_op_init_lazy_reg:
334     traceExecution()
335     loadi 4[PC], t0
336     storei EmptyValueTag, TagOffset[cfr, t0, 8]
337     storei 0, PayloadOffset[cfr, t0, 8]
338     dispatch(2)
339
340
341 _llint_op_create_arguments:
342     traceExecution()
343     loadi 4[PC], t0
344     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateArgumentsDone
345     callSlowPath(_llint_slow_path_create_arguments)
346 .opCreateArgumentsDone:
347     dispatch(2)
348
349
350 _llint_op_create_this:
351     traceExecution()
352     loadp Callee[cfr], t0
353     loadp JSFunction::m_cachedInheritorID[t0], t2
354     btpz t2, .opCreateThisSlow
355     allocateBasicJSObject(JSFinalObjectSizeClassIndex, t2, t0, t1, t3, .opCreateThisSlow)
356     loadi 4[PC], t1
357     storei CellTag, TagOffset[cfr, t1, 8]
358     storei t0, PayloadOffset[cfr, t1, 8]
359     dispatch(2)
360
361 .opCreateThisSlow:
362     callSlowPath(_llint_slow_path_create_this)
363     dispatch(2)
364
365
366 _llint_op_convert_this:
367     traceExecution()
368     loadi 4[PC], t0
369     bineq TagOffset[cfr, t0, 8], CellTag, .opConvertThisSlow
370     loadi PayloadOffset[cfr, t0, 8], t0
371     loadp JSCell::m_structure[t0], t0
372     bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow
373     loadi 8[PC], t1
374     valueProfile(CellTag, t0, t1)
375     dispatch(3)
376
377 .opConvertThisSlow:
378     callSlowPath(_llint_slow_path_convert_this)
379     dispatch(3)
380
381
382 _llint_op_new_object:
383     traceExecution()
384     loadp CodeBlock[cfr], t0
385     loadp CodeBlock::m_globalObject[t0], t0
386     loadp JSGlobalObject::m_emptyObjectStructure[t0], t1
387     allocateBasicJSObject(JSFinalObjectSizeClassIndex, t1, t0, t2, t3, .opNewObjectSlow)
388     loadi 4[PC], t1
389     storei CellTag, TagOffset[cfr, t1, 8]
390     storei t0, PayloadOffset[cfr, t1, 8]
391     dispatch(2)
392
393 .opNewObjectSlow:
394     callSlowPath(_llint_slow_path_new_object)
395     dispatch(2)
396
397
398 _llint_op_mov:
399     traceExecution()
400     loadi 8[PC], t1
401     loadi 4[PC], t0
402     loadConstantOrVariable(t1, t2, t3)
403     storei t2, TagOffset[cfr, t0, 8]
404     storei t3, PayloadOffset[cfr, t0, 8]
405     dispatch(3)
406
407
408 _llint_op_not:
409     traceExecution()
410     loadi 8[PC], t0
411     loadi 4[PC], t1
412     loadConstantOrVariable(t0, t2, t3)
413     bineq t2, BooleanTag, .opNotSlow
414     xori 1, t3
415     storei t2, TagOffset[cfr, t1, 8]
416     storei t3, PayloadOffset[cfr, t1, 8]
417     dispatch(3)
418
419 .opNotSlow:
420     callSlowPath(_llint_slow_path_not)
421     dispatch(3)
422
423
424 _llint_op_eq:
425     traceExecution()
426     loadi 12[PC], t2
427     loadi 8[PC], t0
428     loadConstantOrVariable(t2, t3, t1)
429     loadConstantOrVariable2Reg(t0, t2, t0)
430     bineq t2, t3, .opEqSlow
431     bieq t2, CellTag, .opEqSlow
432     bib t2, LowestTag, .opEqSlow
433     loadi 4[PC], t2
434     cieq t0, t1, t0
435     storei BooleanTag, TagOffset[cfr, t2, 8]
436     storei t0, PayloadOffset[cfr, t2, 8]
437     dispatch(4)
438
439 .opEqSlow:
440     callSlowPath(_llint_slow_path_eq)
441     dispatch(4)
442
443
444 _llint_op_eq_null:
445     traceExecution()
446     loadi 8[PC], t0
447     loadi 4[PC], t3
448     assertNotConstant(t0)
449     loadi TagOffset[cfr, t0, 8], t1
450     loadi PayloadOffset[cfr, t0, 8], t0
451     bineq t1, CellTag, .opEqNullImmediate
452     loadp JSCell::m_structure[t0], t1
453     btbnz Structure::m_typeInfo + TypeInfo::m_flags[t1], MasqueradesAsUndefined, .opEqNullMasqueradesAsUndefined
454     move 0, t1
455     jmp .opEqNullNotImmediate
456 .opEqNullMasqueradesAsUndefined:
457     loadp CodeBlock[cfr], t0
458     loadp CodeBlock::m_globalObject[t0], t0
459     cpeq Structure::m_globalObject[t1], t0, t1
460     jmp .opEqNullNotImmediate
461 .opEqNullImmediate:
462     cieq t1, NullTag, t2
463     cieq t1, UndefinedTag, t1
464     ori t2, t1
465 .opEqNullNotImmediate:
466     storei BooleanTag, TagOffset[cfr, t3, 8]
467     storei t1, PayloadOffset[cfr, t3, 8]
468     dispatch(3)
469
470
471 _llint_op_neq:
472     traceExecution()
473     loadi 12[PC], t2
474     loadi 8[PC], t0
475     loadConstantOrVariable(t2, t3, t1)
476     loadConstantOrVariable2Reg(t0, t2, t0)
477     bineq t2, t3, .opNeqSlow
478     bieq t2, CellTag, .opNeqSlow
479     bib t2, LowestTag, .opNeqSlow
480     loadi 4[PC], t2
481     cineq t0, t1, t0
482     storei BooleanTag, TagOffset[cfr, t2, 8]
483     storei t0, PayloadOffset[cfr, t2, 8]
484     dispatch(4)
485
486 .opNeqSlow:
487     callSlowPath(_llint_slow_path_neq)
488     dispatch(4)
489     
490
491 _llint_op_neq_null:
492     traceExecution()
493     loadi 8[PC], t0
494     loadi 4[PC], t3
495     assertNotConstant(t0)
496     loadi TagOffset[cfr, t0, 8], t1
497     loadi PayloadOffset[cfr, t0, 8], t0
498     bineq t1, CellTag, .opNeqNullImmediate
499     loadp JSCell::m_structure[t0], t1
500     btbnz Structure::m_typeInfo + TypeInfo::m_flags[t1], MasqueradesAsUndefined, .opNeqNullMasqueradesAsUndefined
501     move 1, t1
502     jmp .opNeqNullNotImmediate
503 .opNeqNullMasqueradesAsUndefined:
504     loadp CodeBlock[cfr], t0
505     loadp CodeBlock::m_globalObject[t0], t0
506     cpneq Structure::m_globalObject[t1], t0, t1
507     jmp .opNeqNullNotImmediate
508 .opNeqNullImmediate:
509     cineq t1, NullTag, t2
510     cineq t1, UndefinedTag, t1
511     andi t2, t1
512 .opNeqNullNotImmediate:
513     storei BooleanTag, TagOffset[cfr, t3, 8]
514     storei t1, PayloadOffset[cfr, t3, 8]
515     dispatch(3)
516
517
518 macro strictEq(equalityOperation, slowPath)
519     loadi 12[PC], t2
520     loadi 8[PC], t0
521     loadConstantOrVariable(t2, t3, t1)
522     loadConstantOrVariable2Reg(t0, t2, t0)
523     bineq t2, t3, .slow
524     bib t2, LowestTag, .slow
525     bineq t2, CellTag, .notString
526     loadp JSCell::m_structure[t0], t2
527     loadp JSCell::m_structure[t1], t3
528     bbneq Structure::m_typeInfo + TypeInfo::m_type[t2], StringType, .notString
529     bbeq Structure::m_typeInfo + TypeInfo::m_type[t3], StringType, .slow
530 .notString:
531     loadi 4[PC], t2
532     equalityOperation(t0, t1, t0)
533     storei BooleanTag, TagOffset[cfr, t2, 8]
534     storei t0, PayloadOffset[cfr, t2, 8]
535     dispatch(4)
536
537 .slow:
538     callSlowPath(slowPath)
539     dispatch(4)
540 end
541
542 _llint_op_stricteq:
543     traceExecution()
544     strictEq(macro (left, right, result) cieq left, right, result end, _llint_slow_path_stricteq)
545
546
547 _llint_op_nstricteq:
548     traceExecution()
549     strictEq(macro (left, right, result) cineq left, right, result end, _llint_slow_path_nstricteq)
550
551
552 _llint_op_pre_inc:
553     traceExecution()
554     loadi 4[PC], t0
555     bineq TagOffset[cfr, t0, 8], Int32Tag, .opPreIncSlow
556     loadi PayloadOffset[cfr, t0, 8], t1
557     baddio 1, t1, .opPreIncSlow
558     storei t1, PayloadOffset[cfr, t0, 8]
559     dispatch(2)
560
561 .opPreIncSlow:
562     callSlowPath(_llint_slow_path_pre_inc)
563     dispatch(2)
564
565
566 _llint_op_pre_dec:
567     traceExecution()
568     loadi 4[PC], t0
569     bineq TagOffset[cfr, t0, 8], Int32Tag, .opPreDecSlow
570     loadi PayloadOffset[cfr, t0, 8], t1
571     bsubio 1, t1, .opPreDecSlow
572     storei t1, PayloadOffset[cfr, t0, 8]
573     dispatch(2)
574
575 .opPreDecSlow:
576     callSlowPath(_llint_slow_path_pre_dec)
577     dispatch(2)
578
579
580 _llint_op_post_inc:
581     traceExecution()
582     loadi 8[PC], t0
583     loadi 4[PC], t1
584     bineq TagOffset[cfr, t0, 8], Int32Tag, .opPostIncSlow
585     bieq t0, t1, .opPostIncDone
586     loadi PayloadOffset[cfr, t0, 8], t2
587     move t2, t3
588     baddio 1, t3, .opPostIncSlow
589     storei Int32Tag, TagOffset[cfr, t1, 8]
590     storei t2, PayloadOffset[cfr, t1, 8]
591     storei t3, PayloadOffset[cfr, t0, 8]
592 .opPostIncDone:
593     dispatch(3)
594
595 .opPostIncSlow:
596     callSlowPath(_llint_slow_path_post_inc)
597     dispatch(3)
598
599
600 _llint_op_post_dec:
601     traceExecution()
602     loadi 8[PC], t0
603     loadi 4[PC], t1
604     bineq TagOffset[cfr, t0, 8], Int32Tag, .opPostDecSlow
605     bieq t0, t1, .opPostDecDone
606     loadi PayloadOffset[cfr, t0, 8], t2
607     move t2, t3
608     bsubio 1, t3, .opPostDecSlow
609     storei Int32Tag, TagOffset[cfr, t1, 8]
610     storei t2, PayloadOffset[cfr, t1, 8]
611     storei t3, PayloadOffset[cfr, t0, 8]
612 .opPostDecDone:
613     dispatch(3)
614
615 .opPostDecSlow:
616     callSlowPath(_llint_slow_path_post_dec)
617     dispatch(3)
618
619
620 _llint_op_to_jsnumber:
621     traceExecution()
622     loadi 8[PC], t0
623     loadi 4[PC], t1
624     loadConstantOrVariable(t0, t2, t3)
625     bieq t2, Int32Tag, .opToJsnumberIsInt
626     biaeq t2, EmptyValueTag, .opToJsnumberSlow
627 .opToJsnumberIsInt:
628     storei t2, TagOffset[cfr, t1, 8]
629     storei t3, PayloadOffset[cfr, t1, 8]
630     dispatch(3)
631
632 .opToJsnumberSlow:
633     callSlowPath(_llint_slow_path_to_jsnumber)
634     dispatch(3)
635
636
637 _llint_op_negate:
638     traceExecution()
639     loadi 8[PC], t0
640     loadi 4[PC], t3
641     loadConstantOrVariable(t0, t1, t2)
642     bineq t1, Int32Tag, .opNegateSrcNotInt
643     btiz t2, 0x7fffffff, .opNegateSlow
644     negi t2
645     storei Int32Tag, TagOffset[cfr, t3, 8]
646     storei t2, PayloadOffset[cfr, t3, 8]
647     dispatch(3)
648 .opNegateSrcNotInt:
649     bia t1, LowestTag, .opNegateSlow
650     xori 0x80000000, t1
651     storei t1, TagOffset[cfr, t3, 8]
652     storei t2, PayloadOffset[cfr, t3, 8]
653     dispatch(3)
654
655 .opNegateSlow:
656     callSlowPath(_llint_slow_path_negate)
657     dispatch(3)
658
659
660 macro binaryOpCustomStore(integerOperationAndStore, doubleOperation, slowPath)
661     loadi 12[PC], t2
662     loadi 8[PC], t0
663     loadConstantOrVariable(t2, t3, t1)
664     loadConstantOrVariable2Reg(t0, t2, t0)
665     bineq t2, Int32Tag, .op1NotInt
666     bineq t3, Int32Tag, .op2NotInt
667     loadi 4[PC], t2
668     integerOperationAndStore(t3, t1, t0, .slow, t2)
669     dispatch(5)
670
671 .op1NotInt:
672     # First operand is definitely not an int, the second operand could be anything.
673     bia t2, LowestTag, .slow
674     bib t3, LowestTag, .op1NotIntOp2Double
675     bineq t3, Int32Tag, .slow
676     ci2d t1, ft1
677     jmp .op1NotIntReady
678 .op1NotIntOp2Double:
679     fii2d t1, t3, ft1
680 .op1NotIntReady:
681     loadi 4[PC], t1
682     fii2d t0, t2, ft0
683     doubleOperation(ft1, ft0)
684     stored ft0, [cfr, t1, 8]
685     dispatch(5)
686
687 .op2NotInt:
688     # First operand is definitely an int, the second operand is definitely not.
689     loadi 4[PC], t2
690     bia t3, LowestTag, .slow
691     ci2d t0, ft0
692     fii2d t1, t3, ft1
693     doubleOperation(ft1, ft0)
694     stored ft0, [cfr, t2, 8]
695     dispatch(5)
696
697 .slow:
698     callSlowPath(slowPath)
699     dispatch(5)
700 end
701
702 macro binaryOp(integerOperation, doubleOperation, slowPath)
703     binaryOpCustomStore(
704         macro (int32Tag, left, right, slow, index)
705             integerOperation(left, right, slow)
706             storei int32Tag, TagOffset[cfr, index, 8]
707             storei right, PayloadOffset[cfr, index, 8]
708         end,
709         doubleOperation, slowPath)
710 end
711
712 _llint_op_add:
713     traceExecution()
714     binaryOp(
715         macro (left, right, slow) baddio left, right, slow end,
716         macro (left, right) addd left, right end,
717         _llint_slow_path_add)
718
719
720 _llint_op_mul:
721     traceExecution()
722     binaryOpCustomStore(
723         macro (int32Tag, left, right, slow, index)
724             const scratch = int32Tag   # We know that we can reuse the int32Tag register since it has a constant.
725             move right, scratch
726             bmulio left, scratch, slow
727             btinz scratch, .done
728             bilt left, 0, slow
729             bilt right, 0, slow
730         .done:
731             storei Int32Tag, TagOffset[cfr, index, 8]
732             storei scratch, PayloadOffset[cfr, index, 8]
733         end,
734         macro (left, right) muld left, right end,
735         _llint_slow_path_mul)
736
737
738 _llint_op_sub:
739     traceExecution()
740     binaryOp(
741         macro (left, right, slow) bsubio left, right, slow end,
742         macro (left, right) subd left, right end,
743         _llint_slow_path_sub)
744
745
746 _llint_op_div:
747     traceExecution()
748     binaryOpCustomStore(
749         macro (int32Tag, left, right, slow, index)
750             ci2d left, ft0
751             ci2d right, ft1
752             divd ft0, ft1
753             bcd2i ft1, right, .notInt
754             storei int32Tag, TagOffset[cfr, index, 8]
755             storei right, PayloadOffset[cfr, index, 8]
756             jmp .done
757         .notInt:
758             stored ft1, [cfr, index, 8]
759         .done:
760         end,
761         macro (left, right) divd left, right end,
762         _llint_slow_path_div)
763
764
765 macro bitOp(operation, slowPath, advance)
766     loadi 12[PC], t2
767     loadi 8[PC], t0
768     loadConstantOrVariable(t2, t3, t1)
769     loadConstantOrVariable2Reg(t0, t2, t0)
770     bineq t3, Int32Tag, .slow
771     bineq t2, Int32Tag, .slow
772     loadi 4[PC], t2
773     operation(t1, t0, .slow)
774     storei t3, TagOffset[cfr, t2, 8]
775     storei t0, PayloadOffset[cfr, t2, 8]
776     dispatch(advance)
777
778 .slow:
779     callSlowPath(slowPath)
780     dispatch(advance)
781 end
782
783 _llint_op_lshift:
784     traceExecution()
785     bitOp(
786         macro (left, right, slow) lshifti left, right end,
787         _llint_slow_path_lshift,
788         4)
789
790
791 _llint_op_rshift:
792     traceExecution()
793     bitOp(
794         macro (left, right, slow) rshifti left, right end,
795         _llint_slow_path_rshift,
796         4)
797
798
799 _llint_op_urshift:
800     traceExecution()
801     bitOp(
802         macro (left, right, slow)
803             urshifti left, right
804             bilt right, 0, slow
805         end,
806         _llint_slow_path_urshift,
807         4)
808
809
810 _llint_op_bitand:
811     traceExecution()
812     bitOp(
813         macro (left, right, slow) andi left, right end,
814         _llint_slow_path_bitand,
815         5)
816
817
818 _llint_op_bitxor:
819     traceExecution()
820     bitOp(
821         macro (left, right, slow) xori left, right end,
822         _llint_slow_path_bitxor,
823         5)
824
825
826 _llint_op_bitor:
827     traceExecution()
828     bitOp(
829         macro (left, right, slow) ori left, right end,
830         _llint_slow_path_bitor,
831         5)
832
833
834 _llint_op_check_has_instance:
835     traceExecution()
836     loadi 12[PC], t1
837     loadConstantOrVariablePayload(t1, CellTag, t0, .opCheckHasInstanceSlow)
838     loadp JSCell::m_structure[t0], t0
839     btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opCheckHasInstanceSlow
840     dispatch(5)
841
842 .opCheckHasInstanceSlow:
843     callSlowPath(_llint_slow_path_check_has_instance)
844     dispatch(0)
845
846
847 _llint_op_instanceof:
848     traceExecution()
849     # Actually do the work.
850     loadi 12[PC], t0
851     loadi 4[PC], t3
852     loadConstantOrVariablePayload(t0, CellTag, t1, .opInstanceofSlow)
853     loadp JSCell::m_structure[t1], t2
854     bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opInstanceofSlow
855     loadi 8[PC], t0
856     loadConstantOrVariablePayload(t0, CellTag, t2, .opInstanceofSlow)
857     
858     # Register state: t1 = prototype, t2 = value
859     move 1, t0
860 .opInstanceofLoop:
861     loadp JSCell::m_structure[t2], t2
862     loadi Structure::m_prototype + PayloadOffset[t2], t2
863     bpeq t2, t1, .opInstanceofDone
864     btinz t2, .opInstanceofLoop
865
866     move 0, t0
867 .opInstanceofDone:
868     storei BooleanTag, TagOffset[cfr, t3, 8]
869     storei t0, PayloadOffset[cfr, t3, 8]
870     dispatch(4)
871
872 .opInstanceofSlow:
873     callSlowPath(_llint_slow_path_instanceof)
874     dispatch(4)
875
876
877 _llint_op_is_undefined:
878     traceExecution()
879     loadi 8[PC], t1
880     loadi 4[PC], t0
881     loadConstantOrVariable(t1, t2, t3)
882     storei BooleanTag, TagOffset[cfr, t0, 8]
883     bieq t2, CellTag, .opIsUndefinedCell
884     cieq t2, UndefinedTag, t3
885     storei t3, PayloadOffset[cfr, t0, 8]
886     dispatch(3)
887 .opIsUndefinedCell:
888     loadp JSCell::m_structure[t3], t1
889     btbnz Structure::m_typeInfo + TypeInfo::m_flags[t1], MasqueradesAsUndefined, .opIsUndefinedMasqueradesAsUndefined
890     move 0, t1
891     storei t1, PayloadOffset[cfr, t0, 8]
892     dispatch(3)
893 .opIsUndefinedMasqueradesAsUndefined:
894     loadp CodeBlock[cfr], t3
895     loadp CodeBlock::m_globalObject[t3], t3
896     cpeq Structure::m_globalObject[t1], t3, t1
897     storei t1, PayloadOffset[cfr, t0, 8]
898     dispatch(3)
899
900
901 _llint_op_is_boolean:
902     traceExecution()
903     loadi 8[PC], t1
904     loadi 4[PC], t2
905     loadConstantOrVariableTag(t1, t0)
906     cieq t0, BooleanTag, t0
907     storei BooleanTag, TagOffset[cfr, t2, 8]
908     storei t0, PayloadOffset[cfr, t2, 8]
909     dispatch(3)
910
911
912 _llint_op_is_number:
913     traceExecution()
914     loadi 8[PC], t1
915     loadi 4[PC], t2
916     loadConstantOrVariableTag(t1, t0)
917     storei BooleanTag, TagOffset[cfr, t2, 8]
918     addi 1, t0
919     cib t0, LowestTag + 1, t1
920     storei t1, PayloadOffset[cfr, t2, 8]
921     dispatch(3)
922
923
924 _llint_op_is_string:
925     traceExecution()
926     loadi 8[PC], t1
927     loadi 4[PC], t2
928     loadConstantOrVariable(t1, t0, t3)
929     storei BooleanTag, TagOffset[cfr, t2, 8]
930     bineq t0, CellTag, .opIsStringNotCell
931     loadp JSCell::m_structure[t3], t0
932     cbeq Structure::m_typeInfo + TypeInfo::m_type[t0], StringType, t1
933     storei t1, PayloadOffset[cfr, t2, 8]
934     dispatch(3)
935 .opIsStringNotCell:
936     storep 0, PayloadOffset[cfr, t2, 8]
937     dispatch(3)
938
939
940 macro loadPropertyAtVariableOffsetKnownNotFinal(propertyOffset, objectAndStorage, tag, payload)
941     assert(macro (ok) bigteq propertyOffset, InlineStorageCapacity, ok end)
942     negi propertyOffset
943     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
944     loadi TagOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], tag
945     loadi PayloadOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], payload
946 end
947
948 macro loadPropertyAtVariableOffset(propertyOffset, objectAndStorage, tag, payload)
949     bilt propertyOffset, InlineStorageCapacity, .isInline
950     loadp JSObject::m_butterfly[objectAndStorage], objectAndStorage
951     negi propertyOffset
952     jmp .ready
953 .isInline:
954     addp JSFinalObject::m_inlineStorage - (InlineStorageCapacity - 1) * 8 + sizeof IndexingHeader, objectAndStorage
955 .ready:
956     loadi TagOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], tag
957     loadi PayloadOffset + (InlineStorageCapacity - 1) * 8 - sizeof IndexingHeader[objectAndStorage, propertyOffset, 8], payload
958 end
959
960 macro resolveGlobal(size, slow)
961     # Operands are as follows:
962     # 4[PC]   Destination for the load.
963     # 8[PC]   Property identifier index in the code block.
964     # 12[PC]  Structure pointer, initialized to 0 by bytecode generator.
965     # 16[PC]  Offset in global object, initialized to 0 by bytecode generator.
966     loadp CodeBlock[cfr], t0
967     loadp CodeBlock::m_globalObject[t0], t0
968     loadp JSCell::m_structure[t0], t1
969     bpneq t1, 12[PC], slow
970     loadi 16[PC], t1
971     loadPropertyAtVariableOffsetKnownNotFinal(t1, t0, t2, t3)
972     loadi 4[PC], t0
973     storei t2, TagOffset[cfr, t0, 8]
974     storei t3, PayloadOffset[cfr, t0, 8]
975     loadi (size - 1) * 4[PC], t0
976     valueProfile(t2, t3, t0)
977 end
978
979 _llint_op_resolve_global:
980     traceExecution()
981     resolveGlobal(6, .opResolveGlobalSlow)
982     dispatch(6)
983
984 .opResolveGlobalSlow:
985     callSlowPath(_llint_slow_path_resolve_global)
986     dispatch(6)
987
988
989 # Gives you the scope in t0, while allowing you to optionally perform additional checks on the
990 # scopes as they are traversed. scopeCheck() is called with two arguments: the register
991 # holding the scope, and a register that can be used for scratch. Note that this does not
992 # use t3, so you can hold stuff in t3 if need be.
993 macro getScope(deBruijinIndexOperand, scopeCheck)
994     loadp ScopeChain + PayloadOffset[cfr], t0
995     loadi deBruijinIndexOperand, t2
996     
997     btiz t2, .done
998     
999     loadp CodeBlock[cfr], t1
1000     bineq CodeBlock::m_codeType[t1], FunctionCode, .loop
1001     btbz CodeBlock::m_needsFullScopeChain[t1], .loop
1002     
1003     loadi CodeBlock::m_activationRegister[t1], t1
1004
1005     # Need to conditionally skip over one scope.
1006     bieq TagOffset[cfr, t1, 8], EmptyValueTag, .noActivation
1007     scopeCheck(t0, t1)
1008     loadp JSScope::m_next[t0], t0
1009 .noActivation:
1010     subi 1, t2
1011     
1012     btiz t2, .done
1013 .loop:
1014     scopeCheck(t0, t1)
1015     loadp JSScope::m_next[t0], t0
1016     subi 1, t2
1017     btinz t2, .loop
1018
1019 .done:
1020 end
1021
1022 _llint_op_resolve_global_dynamic:
1023     traceExecution()
1024     loadp CodeBlock[cfr], t3
1025     loadp CodeBlock::m_globalObject[t3], t3
1026     loadp JSGlobalObject::m_activationStructure[t3], t3
1027     getScope(
1028         20[PC],
1029         macro (scope, scratch)
1030             bpneq JSCell::m_structure[scope], t3, .opResolveGlobalDynamicSuperSlow
1031         end)
1032     resolveGlobal(7, .opResolveGlobalDynamicSlow)
1033     dispatch(7)
1034
1035 .opResolveGlobalDynamicSuperSlow:
1036     callSlowPath(_llint_slow_path_resolve_for_resolve_global_dynamic)
1037     dispatch(7)
1038
1039 .opResolveGlobalDynamicSlow:
1040     callSlowPath(_llint_slow_path_resolve_global_dynamic)
1041     dispatch(7)
1042
1043
1044 _llint_op_get_scoped_var:
1045     traceExecution()
1046     # Operands are as follows:
1047     # 4[PC]   Destination for the load.
1048     # 8[PC]   Index of register in the scope.
1049     # 12[PC]  De Bruijin index.
1050     getScope(12[PC], macro (scope, scratch) end)
1051     loadi 4[PC], t1
1052     loadi 8[PC], t2
1053     loadp JSVariableObject::m_registers[t0], t0
1054     loadi TagOffset[t0, t2, 8], t3
1055     loadi PayloadOffset[t0, t2, 8], t0
1056     storei t3, TagOffset[cfr, t1, 8]
1057     storei t0, PayloadOffset[cfr, t1, 8]
1058     loadi 16[PC], t1
1059     valueProfile(t3, t0, t1)
1060     dispatch(5)
1061
1062
1063 _llint_op_put_scoped_var:
1064     traceExecution()
1065     getScope(8[PC], macro (scope, scratch) end)
1066     loadi 12[PC], t1
1067     loadConstantOrVariable(t1, t3, t2)
1068     loadi 4[PC], t1
1069     writeBarrier(t3, t2)
1070     loadp JSVariableObject::m_registers[t0], t0
1071     storei t3, TagOffset[t0, t1, 8]
1072     storei t2, PayloadOffset[t0, t1, 8]
1073     dispatch(4)
1074
1075
1076 macro getGlobalVar(size)
1077     traceExecution()
1078     loadp 8[PC], t0
1079     loadi 4[PC], t3
1080     loadi TagOffset[t0], t2
1081     loadi PayloadOffset[t0], t1
1082     storei t2, TagOffset[cfr, t3, 8]
1083     storei t1, PayloadOffset[cfr, t3, 8]
1084     loadi (size - 1) * 4[PC], t3
1085     valueProfile(t2, t1, t3)
1086     dispatch(size)
1087 end
1088
1089 _llint_op_get_global_var:
1090     getGlobalVar(4)
1091
1092
1093 _llint_op_get_global_var_watchable:
1094     getGlobalVar(5)
1095
1096
1097 _llint_op_init_global_const:
1098 _llint_op_put_global_var:
1099     traceExecution()
1100     loadi 8[PC], t1
1101     loadi 4[PC], t0
1102     loadConstantOrVariable(t1, t2, t3)
1103     writeBarrier(t2, t3)
1104     storei t2, TagOffset[t0]
1105     storei t3, PayloadOffset[t0]
1106     dispatch(3)
1107
1108
1109 _llint_op_init_global_const_check:
1110 _llint_op_put_global_var_check:
1111     traceExecution()
1112     loadp 12[PC], t2
1113     loadi 8[PC], t1
1114     loadi 4[PC], t0
1115     btbnz [t2], .opPutGlobalVarCheckSlow
1116     loadConstantOrVariable(t1, t2, t3)
1117     writeBarrier(t2, t3)
1118     storei t2, TagOffset[t0]
1119     storei t3, PayloadOffset[t0]
1120     dispatch(5)
1121 .opPutGlobalVarCheckSlow:
1122     callSlowPath(_llint_slow_path_put_global_var_check)
1123     dispatch(5)
1124
1125
1126 # We only do monomorphic get_by_id caching for now, and we do not modify the
1127 # opcode. We do, however, allow for the cache to change anytime if fails, since
1128 # ping-ponging is free. At best we get lucky and the get_by_id will continue
1129 # to take fast path on the new cache. At worst we take slow path, which is what
1130 # we would have been doing anyway.
1131
1132 macro getById(getPropertyStorage)
1133     traceExecution()
1134     loadi 8[PC], t0
1135     loadi 16[PC], t1
1136     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow)
1137     loadi 20[PC], t2
1138     getPropertyStorage(
1139         t3,
1140         t0,
1141         macro (propertyStorage, scratch)
1142             bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
1143             loadi 4[PC], t1
1144             loadi TagOffset[propertyStorage, t2], scratch
1145             loadi PayloadOffset[propertyStorage, t2], t2
1146             storei scratch, TagOffset[cfr, t1, 8]
1147             storei t2, PayloadOffset[cfr, t1, 8]
1148             loadi 32[PC], t1
1149             valueProfile(scratch, t2, t1)
1150             dispatch(9)
1151         end)
1152
1153     .opGetByIdSlow:
1154         callSlowPath(_llint_slow_path_get_by_id)
1155         dispatch(9)
1156 end
1157
1158 _llint_op_get_by_id:
1159     getById(withInlineStorage)
1160
1161
1162 _llint_op_get_by_id_out_of_line:
1163     getById(withOutOfLineStorage)
1164
1165
1166 _llint_op_get_array_length:
1167     traceExecution()
1168     loadi 8[PC], t0
1169     loadp 16[PC], t1
1170     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetArrayLengthSlow)
1171     loadp JSCell::m_structure[t3], t2
1172     arrayProfile(t2, t1, t0)
1173     btiz t2, IsArray, .opGetArrayLengthSlow
1174     btiz t2, HasArrayStorage, .opGetArrayLengthSlow
1175     loadi 4[PC], t1
1176     loadp 32[PC], t2
1177     loadp JSObject::m_butterfly[t3], t0
1178     loadi -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], t0
1179     bilt t0, 0, .opGetArrayLengthSlow
1180     valueProfile(Int32Tag, t0, t2)
1181     storep t0, PayloadOffset[cfr, t1, 8]
1182     storep Int32Tag, TagOffset[cfr, t1, 8]
1183     dispatch(9)
1184
1185 .opGetArrayLengthSlow:
1186     callSlowPath(_llint_slow_path_get_by_id)
1187     dispatch(9)
1188
1189
1190 _llint_op_get_arguments_length:
1191     traceExecution()
1192     loadi 8[PC], t0
1193     loadi 4[PC], t1
1194     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentsLengthSlow
1195     loadi ArgumentCount + PayloadOffset[cfr], t2
1196     subi 1, t2
1197     storei Int32Tag, TagOffset[cfr, t1, 8]
1198     storei t2, PayloadOffset[cfr, t1, 8]
1199     dispatch(4)
1200
1201 .opGetArgumentsLengthSlow:
1202     callSlowPath(_llint_slow_path_get_arguments_length)
1203     dispatch(4)
1204
1205
1206 macro putById(getPropertyStorage)
1207     traceExecution()
1208     loadi 4[PC], t3
1209     loadi 16[PC], t1
1210     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1211     loadi 12[PC], t2
1212     getPropertyStorage(
1213         t0,
1214         t3,
1215         macro (propertyStorage, scratch)
1216             bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1217             loadi 20[PC], t1
1218             loadConstantOrVariable2Reg(t2, scratch, t2)
1219             writeBarrier(scratch, t2)
1220             storei scratch, TagOffset[propertyStorage, t1]
1221             storei t2, PayloadOffset[propertyStorage, t1]
1222             dispatch(9)
1223         end)
1224 end
1225
1226 _llint_op_put_by_id:
1227     putById(withInlineStorage)
1228
1229 .opPutByIdSlow:
1230     callSlowPath(_llint_slow_path_put_by_id)
1231     dispatch(9)
1232
1233
1234 _llint_op_put_by_id_out_of_line:
1235     putById(withOutOfLineStorage)
1236
1237
1238 macro putByIdTransition(additionalChecks, getPropertyStorage)
1239     traceExecution()
1240     loadi 4[PC], t3
1241     loadi 16[PC], t1
1242     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1243     loadi 12[PC], t2
1244     bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1245     additionalChecks(t1, t3)
1246     loadi 20[PC], t1
1247     getPropertyStorage(
1248         t0,
1249         t3,
1250         macro (propertyStorage, scratch)
1251             addp t1, propertyStorage, t3
1252             loadConstantOrVariable2Reg(t2, t1, t2)
1253             writeBarrier(t1, t2)
1254             storei t1, TagOffset[t3]
1255             loadi 24[PC], t1
1256             storei t2, PayloadOffset[t3]
1257             storep t1, JSCell::m_structure[t0]
1258             dispatch(9)
1259         end)
1260 end
1261
1262 macro noAdditionalChecks(oldStructure, scratch)
1263 end
1264
1265 macro structureChainChecks(oldStructure, scratch)
1266     const protoCell = oldStructure   # Reusing the oldStructure register for the proto
1267
1268     loadp 28[PC], scratch
1269     assert(macro (ok) btpnz scratch, ok end)
1270     loadp StructureChain::m_vector[scratch], scratch
1271     assert(macro (ok) btpnz scratch, ok end)
1272     bieq Structure::m_prototype + TagOffset[oldStructure], NullTag, .done
1273 .loop:
1274     loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell
1275     loadp JSCell::m_structure[protoCell], oldStructure
1276     bpneq oldStructure, [scratch], .opPutByIdSlow
1277     addp 4, scratch
1278     bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop
1279 .done:
1280 end
1281
1282 _llint_op_put_by_id_transition_direct:
1283     putByIdTransition(noAdditionalChecks, withInlineStorage)
1284
1285
1286 _llint_op_put_by_id_transition_direct_out_of_line:
1287     putByIdTransition(noAdditionalChecks, withOutOfLineStorage)
1288
1289
1290 _llint_op_put_by_id_transition_normal:
1291     putByIdTransition(structureChainChecks, withInlineStorage)
1292
1293
1294 _llint_op_put_by_id_transition_normal_out_of_line:
1295     putByIdTransition(structureChainChecks, withOutOfLineStorage)
1296
1297
1298 _llint_op_get_by_val:
1299     traceExecution()
1300     loadi 8[PC], t2
1301     loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow)
1302     loadp JSCell::m_structure[t0], t2
1303     loadp 16[PC], t3
1304     arrayProfile(t2, t3, t1)
1305     btiz t2, HasArrayStorage, .opGetByValSlow
1306     loadi 12[PC], t3
1307     loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
1308     loadp JSObject::m_butterfly[t0], t3
1309     biaeq t1, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t3], .opGetByValSlow
1310     loadi 4[PC], t0
1311     loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2
1312     loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1
1313     bieq t2, EmptyValueTag, .opGetByValSlow
1314     storei t2, TagOffset[cfr, t0, 8]
1315     storei t1, PayloadOffset[cfr, t0, 8]
1316     loadi 20[PC], t0
1317     valueProfile(t2, t1, t0)
1318     dispatch(6)
1319
1320 .opGetByValSlow:
1321     callSlowPath(_llint_slow_path_get_by_val)
1322     dispatch(6)
1323
1324
1325 _llint_op_get_argument_by_val:
1326     # FIXME: At some point we should array profile this. Right now it isn't necessary
1327     # since the DFG will never turn a get_argument_by_val into a GetByVal.
1328     traceExecution()
1329     loadi 8[PC], t0
1330     loadi 12[PC], t1
1331     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentByValSlow
1332     loadConstantOrVariablePayload(t1, Int32Tag, t2, .opGetArgumentByValSlow)
1333     addi 1, t2
1334     loadi ArgumentCount + PayloadOffset[cfr], t1
1335     biaeq t2, t1, .opGetArgumentByValSlow
1336     negi t2
1337     loadi 4[PC], t3
1338     loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0
1339     loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t1
1340     loadi 20[PC], t2
1341     storei t0, TagOffset[cfr, t3, 8]
1342     storei t1, PayloadOffset[cfr, t3, 8]
1343     valueProfile(t0, t1, t2)
1344     dispatch(6)
1345
1346 .opGetArgumentByValSlow:
1347     callSlowPath(_llint_slow_path_get_argument_by_val)
1348     dispatch(6)
1349
1350
1351 _llint_op_get_by_pname:
1352     traceExecution()
1353     loadi 12[PC], t0
1354     loadConstantOrVariablePayload(t0, CellTag, t1, .opGetByPnameSlow)
1355     loadi 16[PC], t0
1356     bpneq t1, PayloadOffset[cfr, t0, 8], .opGetByPnameSlow
1357     loadi 8[PC], t0
1358     loadConstantOrVariablePayload(t0, CellTag, t2, .opGetByPnameSlow)
1359     loadi 20[PC], t0
1360     loadi PayloadOffset[cfr, t0, 8], t3
1361     loadp JSCell::m_structure[t2], t0
1362     bpneq t0, JSPropertyNameIterator::m_cachedStructure[t3], .opGetByPnameSlow
1363     loadi 24[PC], t0
1364     loadi [cfr, t0, 8], t0
1365     subi 1, t0
1366     biaeq t0, JSPropertyNameIterator::m_numCacheableSlots[t3], .opGetByPnameSlow
1367     addi JSPropertyNameIterator::m_offsetBase[t3], t0
1368     loadPropertyAtVariableOffset(t0, t2, t1, t3)
1369     loadi 4[PC], t0
1370     storei t1, TagOffset[cfr, t0, 8]
1371     storei t3, PayloadOffset[cfr, t0, 8]
1372     dispatch(7)
1373
1374 .opGetByPnameSlow:
1375     callSlowPath(_llint_slow_path_get_by_pname)
1376     dispatch(7)
1377
1378
1379 _llint_op_put_by_val:
1380     traceExecution()
1381     loadi 4[PC], t0
1382     loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
1383     loadp JSCell::m_structure[t1], t2
1384     loadp 16[PC], t3
1385     arrayProfile(t2, t3, t0)
1386     btiz t2, HasArrayStorage, .opPutByValSlow
1387     loadi 8[PC], t0
1388     loadConstantOrVariablePayload(t0, Int32Tag, t2, .opPutByValSlow)
1389     loadp JSObject::m_butterfly[t1], t0
1390     biaeq t2, -sizeof IndexingHeader + IndexingHeader::m_vectorLength[t0], .opPutByValSlow
1391     bieq ArrayStorage::m_vector + TagOffset[t0, t2, 8], EmptyValueTag, .opPutByValEmpty
1392 .opPutByValStoreResult:
1393     loadi 12[PC], t3
1394     loadConstantOrVariable2Reg(t3, t1, t3)
1395     writeBarrier(t1, t3)
1396     storei t1, ArrayStorage::m_vector + TagOffset[t0, t2, 8]
1397     storei t3, ArrayStorage::m_vector + PayloadOffset[t0, t2, 8]
1398     dispatch(5)
1399
1400 .opPutByValEmpty:
1401     if VALUE_PROFILER
1402         storeb 1, ArrayProfile::m_mayStoreToHole[t3]
1403     end
1404     addi 1, ArrayStorage::m_numValuesInVector[t0]
1405     bib t2, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0], .opPutByValStoreResult
1406     addi 1, t2, t1
1407     storei t1, -sizeof IndexingHeader + IndexingHeader::m_publicLength[t0]
1408     jmp .opPutByValStoreResult
1409
1410 .opPutByValSlow:
1411     callSlowPath(_llint_slow_path_put_by_val)
1412     dispatch(5)
1413
1414
1415 _llint_op_loop:
1416     traceExecution()
1417     dispatchBranch(4[PC])
1418
1419
1420 _llint_op_jmp:
1421     traceExecution()
1422     dispatchBranch(4[PC])
1423
1424
1425 macro jumpTrueOrFalse(conditionOp, slow)
1426     loadi 4[PC], t1
1427     loadConstantOrVariablePayload(t1, BooleanTag, t0, .slow)
1428     conditionOp(t0, .target)
1429     dispatch(3)
1430
1431 .target:
1432     dispatchBranch(8[PC])
1433
1434 .slow:
1435     callSlowPath(slow)
1436     dispatch(0)
1437 end
1438
1439
1440 macro equalNull(cellHandler, immediateHandler)
1441     loadi 4[PC], t0
1442     assertNotConstant(t0)
1443     loadi TagOffset[cfr, t0, 8], t1
1444     loadi PayloadOffset[cfr, t0, 8], t0
1445     bineq t1, CellTag, .immediate
1446     loadp JSCell::m_structure[t0], t2
1447     cellHandler(t2, Structure::m_typeInfo + TypeInfo::m_flags[t2], .target)
1448     dispatch(3)
1449
1450 .target:
1451     dispatchBranch(8[PC])
1452
1453 .immediate:
1454     ori 1, t1
1455     immediateHandler(t1, .target)
1456     dispatch(3)
1457 end
1458
1459 _llint_op_jeq_null:
1460     traceExecution()
1461     equalNull(
1462         macro (structure, value, target) 
1463             btbz value, MasqueradesAsUndefined, .opJeqNullNotMasqueradesAsUndefined
1464             loadp CodeBlock[cfr], t0
1465             loadp CodeBlock::m_globalObject[t0], t0
1466             bpeq Structure::m_globalObject[structure], t0, target
1467 .opJeqNullNotMasqueradesAsUndefined:
1468         end,
1469         macro (value, target) bieq value, NullTag, target end)
1470     
1471
1472 _llint_op_jneq_null:
1473     traceExecution()
1474     equalNull(
1475         macro (structure, value, target) 
1476             btbz value, MasqueradesAsUndefined, target 
1477             loadp CodeBlock[cfr], t0
1478             loadp CodeBlock::m_globalObject[t0], t0
1479             bpneq Structure::m_globalObject[structure], t0, target
1480         end,
1481         macro (value, target) bineq value, NullTag, target end)
1482
1483
1484 _llint_op_jneq_ptr:
1485     traceExecution()
1486     loadi 4[PC], t0
1487     loadi 8[PC], t1
1488     loadp CodeBLock[cfr], t2
1489     loadp CodeBlock::m_globalObject[t2], t2
1490     bineq TagOffset[cfr, t0, 8], CellTag, .opJneqPtrBranch
1491     loadp JSGlobalObject::m_specialPointers[t2, t1, 8], t1
1492     bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough
1493 .opJneqPtrBranch:
1494     dispatchBranch(12[PC])
1495 .opJneqPtrFallThrough:
1496     dispatch(4)
1497
1498
1499 macro compare(integerCompare, doubleCompare, slowPath)
1500     loadi 4[PC], t2
1501     loadi 8[PC], t3
1502     loadConstantOrVariable(t2, t0, t1)
1503     loadConstantOrVariable2Reg(t3, t2, t3)
1504     bineq t0, Int32Tag, .op1NotInt
1505     bineq t2, Int32Tag, .op2NotInt
1506     integerCompare(t1, t3, .jumpTarget)
1507     dispatch(4)
1508
1509 .op1NotInt:
1510     bia t0, LowestTag, .slow
1511     bib t2, LowestTag, .op1NotIntOp2Double
1512     bineq t2, Int32Tag, .slow
1513     ci2d t3, ft1
1514     jmp .op1NotIntReady
1515 .op1NotIntOp2Double:
1516     fii2d t3, t2, ft1
1517 .op1NotIntReady:
1518     fii2d t1, t0, ft0
1519     doubleCompare(ft0, ft1, .jumpTarget)
1520     dispatch(4)
1521
1522 .op2NotInt:
1523     ci2d t1, ft0
1524     bia t2, LowestTag, .slow
1525     fii2d t3, t2, ft1
1526     doubleCompare(ft0, ft1, .jumpTarget)
1527     dispatch(4)
1528
1529 .jumpTarget:
1530     dispatchBranch(12[PC])
1531
1532 .slow:
1533     callSlowPath(slowPath)
1534     dispatch(0)
1535 end
1536
1537
1538 _llint_op_switch_imm:
1539     traceExecution()
1540     loadi 12[PC], t2
1541     loadi 4[PC], t3
1542     loadConstantOrVariable(t2, t1, t0)
1543     loadp CodeBlock[cfr], t2
1544     loadp CodeBlock::m_rareData[t2], t2
1545     muli sizeof SimpleJumpTable, t3   # FIXME: would be nice to peephole this!
1546     loadp CodeBlock::RareData::m_immediateSwitchJumpTables + VectorBufferOffset[t2], t2
1547     addp t3, t2
1548     bineq t1, Int32Tag, .opSwitchImmNotInt
1549     subi SimpleJumpTable::min[t2], t0
1550     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchImmFallThrough
1551     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t3
1552     loadi [t3, t0, 4], t1
1553     btiz t1, .opSwitchImmFallThrough
1554     dispatchBranchWithOffset(t1)
1555
1556 .opSwitchImmNotInt:
1557     bib t1, LowestTag, .opSwitchImmSlow  # Go to slow path if it's a double.
1558 .opSwitchImmFallThrough:
1559     dispatchBranch(8[PC])
1560
1561 .opSwitchImmSlow:
1562     callSlowPath(_llint_slow_path_switch_imm)
1563     dispatch(0)
1564
1565
1566 _llint_op_switch_char:
1567     traceExecution()
1568     loadi 12[PC], t2
1569     loadi 4[PC], t3
1570     loadConstantOrVariable(t2, t1, t0)
1571     loadp CodeBlock[cfr], t2
1572     loadp CodeBlock::m_rareData[t2], t2
1573     muli sizeof SimpleJumpTable, t3
1574     loadp CodeBlock::RareData::m_characterSwitchJumpTables + VectorBufferOffset[t2], t2
1575     addp t3, t2
1576     bineq t1, CellTag, .opSwitchCharFallThrough
1577     loadp JSCell::m_structure[t0], t1
1578     bbneq Structure::m_typeInfo + TypeInfo::m_type[t1], StringType, .opSwitchCharFallThrough
1579     bineq JSString::m_length[t0], 1, .opSwitchCharFallThrough
1580     loadp JSString::m_value[t0], t0
1581     btpz  t0, .opSwitchOnRope
1582     loadp StringImpl::m_data8[t0], t1
1583     btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
1584     loadh [t1], t0
1585     jmp .opSwitchCharReady
1586 .opSwitchChar8Bit:
1587     loadb [t1], t0
1588 .opSwitchCharReady:
1589     subi SimpleJumpTable::min[t2], t0
1590     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchCharFallThrough
1591     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t2
1592     loadi [t2, t0, 4], t1
1593     btiz t1, .opSwitchCharFallThrough
1594     dispatchBranchWithOffset(t1)
1595
1596 .opSwitchCharFallThrough:
1597     dispatchBranch(8[PC])
1598
1599 .opSwitchOnRope:
1600     callSlowPath(_llint_slow_path_switch_char)
1601     dispatch(0)
1602
1603
1604 _llint_op_new_func:
1605     traceExecution()
1606     btiz 12[PC], .opNewFuncUnchecked
1607     loadi 4[PC], t1
1608     bineq TagOffset[cfr, t1, 8], EmptyValueTag, .opNewFuncDone
1609 .opNewFuncUnchecked:
1610     callSlowPath(_llint_slow_path_new_func)
1611 .opNewFuncDone:
1612     dispatch(4)
1613
1614
1615 macro arrayProfileForCall()
1616     if VALUE_PROFILER
1617         loadi 12[PC], t3
1618         bineq ThisArgumentOffset + TagOffset[cfr, t3, 8], CellTag, .done
1619         loadi ThisArgumentOffset + PayloadOffset[cfr, t3, 8], t0
1620         loadp JSCell::m_structure[t0], t0
1621         loadp 20[PC], t1
1622         storep t0, ArrayProfile::m_lastSeenStructure[t1]
1623     .done:
1624     end
1625 end
1626
1627 macro doCall(slowPath)
1628     loadi 4[PC], t0
1629     loadi 16[PC], t1
1630     loadp LLIntCallLinkInfo::callee[t1], t2
1631     loadConstantOrVariablePayload(t0, CellTag, t3, .opCallSlow)
1632     bineq t3, t2, .opCallSlow
1633     loadi 12[PC], t3
1634     addp 24, PC
1635     lshifti 3, t3
1636     addp cfr, t3  # t3 contains the new value of cfr
1637     loadp JSFunction::m_scope[t2], t0
1638     storei t2, Callee + PayloadOffset[t3]
1639     storei t0, ScopeChain + PayloadOffset[t3]
1640     loadi 8 - 24[PC], t2
1641     storei PC, ArgumentCount + TagOffset[cfr]
1642     storep cfr, CallerFrame[t3]
1643     storei t2, ArgumentCount + PayloadOffset[t3]
1644     storei CellTag, Callee + TagOffset[t3]
1645     storei CellTag, ScopeChain + TagOffset[t3]
1646     move t3, cfr
1647     callTargetFunction(t1)
1648
1649 .opCallSlow:
1650     slowPathForCall(6, slowPath)
1651 end
1652
1653
1654 _llint_op_tear_off_activation:
1655     traceExecution()
1656     loadi 4[PC], t0
1657     bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffActivationNotCreated
1658     callSlowPath(_llint_slow_path_tear_off_activation)
1659 .opTearOffActivationNotCreated:
1660     dispatch(2)
1661
1662
1663 _llint_op_tear_off_arguments:
1664     traceExecution()
1665     loadi 4[PC], t0
1666     subi 1, t0   # Get the unmodifiedArgumentsRegister
1667     bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffArgumentsNotCreated
1668     callSlowPath(_llint_slow_path_tear_off_arguments)
1669 .opTearOffArgumentsNotCreated:
1670     dispatch(3)
1671
1672
1673 _llint_op_ret:
1674     traceExecution()
1675     checkSwitchToJITForEpilogue()
1676     loadi 4[PC], t2
1677     loadConstantOrVariable(t2, t1, t0)
1678     doReturn()
1679
1680
1681 _llint_op_call_put_result:
1682     loadi 4[PC], t2
1683     loadi 8[PC], t3
1684     storei t1, TagOffset[cfr, t2, 8]
1685     storei t0, PayloadOffset[cfr, t2, 8]
1686     valueProfile(t1, t0, t3)
1687     traceExecution() # Needs to be here because it would clobber t1, t0
1688     dispatch(3)
1689
1690
1691 _llint_op_ret_object_or_this:
1692     traceExecution()
1693     checkSwitchToJITForEpilogue()
1694     loadi 4[PC], t2
1695     loadConstantOrVariable(t2, t1, t0)
1696     bineq t1, CellTag, .opRetObjectOrThisNotObject
1697     loadp JSCell::m_structure[t0], t2
1698     bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opRetObjectOrThisNotObject
1699     doReturn()
1700
1701 .opRetObjectOrThisNotObject:
1702     loadi 8[PC], t2
1703     loadConstantOrVariable(t2, t1, t0)
1704     doReturn()
1705
1706
1707 _llint_op_to_primitive:
1708     traceExecution()
1709     loadi 8[PC], t2
1710     loadi 4[PC], t3
1711     loadConstantOrVariable(t2, t1, t0)
1712     bineq t1, CellTag, .opToPrimitiveIsImm
1713     loadp JSCell::m_structure[t0], t2
1714     bbneq Structure::m_typeInfo + TypeInfo::m_type[t2], StringType, .opToPrimitiveSlowCase
1715 .opToPrimitiveIsImm:
1716     storei t1, TagOffset[cfr, t3, 8]
1717     storei t0, PayloadOffset[cfr, t3, 8]
1718     dispatch(3)
1719
1720 .opToPrimitiveSlowCase:
1721     callSlowPath(_llint_slow_path_to_primitive)
1722     dispatch(3)
1723
1724
1725 _llint_op_next_pname:
1726     traceExecution()
1727     loadi 12[PC], t1
1728     loadi 16[PC], t2
1729     loadi PayloadOffset[cfr, t1, 8], t0
1730     bieq t0, PayloadOffset[cfr, t2, 8], .opNextPnameEnd
1731     loadi 20[PC], t2
1732     loadi PayloadOffset[cfr, t2, 8], t2
1733     loadp JSPropertyNameIterator::m_jsStrings[t2], t3
1734     loadi [t3, t0, 8], t3
1735     addi 1, t0
1736     storei t0, PayloadOffset[cfr, t1, 8]
1737     loadi 4[PC], t1
1738     storei CellTag, TagOffset[cfr, t1, 8]
1739     storei t3, PayloadOffset[cfr, t1, 8]
1740     loadi 8[PC], t3
1741     loadi PayloadOffset[cfr, t3, 8], t3
1742     loadp JSCell::m_structure[t3], t1
1743     bpneq t1, JSPropertyNameIterator::m_cachedStructure[t2], .opNextPnameSlow
1744     loadp JSPropertyNameIterator::m_cachedPrototypeChain[t2], t0
1745     loadp StructureChain::m_vector[t0], t0
1746     btpz [t0], .opNextPnameTarget
1747 .opNextPnameCheckPrototypeLoop:
1748     bieq Structure::m_prototype + TagOffset[t1], NullTag, .opNextPnameSlow
1749     loadp Structure::m_prototype + PayloadOffset[t1], t2
1750     loadp JSCell::m_structure[t2], t1
1751     bpneq t1, [t0], .opNextPnameSlow
1752     addp 4, t0
1753     btpnz [t0], .opNextPnameCheckPrototypeLoop
1754 .opNextPnameTarget:
1755     dispatchBranch(24[PC])
1756
1757 .opNextPnameEnd:
1758     dispatch(7)
1759
1760 .opNextPnameSlow:
1761     callSlowPath(_llint_slow_path_next_pname) # This either keeps the PC where it was (causing us to loop) or sets it to target.
1762     dispatch(0)
1763
1764
1765 _llint_op_catch:
1766     # This is where we end up from the JIT's throw trampoline (because the
1767     # machine code return address will be set to _llint_op_catch), and from
1768     # the interpreter's throw trampoline (see _llint_throw_trampoline).
1769     # The JIT throwing protocol calls for the cfr to be in t0. The throwing
1770     # code must have known that we were throwing to the interpreter, and have
1771     # set JSGlobalData::targetInterpreterPCForThrow.
1772     move t0, cfr
1773     loadp JITStackFrame::globalData[sp], t3
1774     loadi JSGlobalData::targetInterpreterPCForThrow[t3], PC
1775     loadi JSGlobalData::exception + PayloadOffset[t3], t0
1776     loadi JSGlobalData::exception + TagOffset[t3], t1
1777     storei 0, JSGlobalData::exception + PayloadOffset[t3]
1778     storei EmptyValueTag, JSGlobalData::exception + TagOffset[t3]       
1779     loadi 4[PC], t2
1780     storei t0, PayloadOffset[cfr, t2, 8]
1781     storei t1, TagOffset[cfr, t2, 8]
1782     traceExecution()  # This needs to be here because we don't want to clobber t0, t1, t2, t3 above.
1783     dispatch(2)
1784
1785
1786 _llint_op_end:
1787     traceExecution()
1788     checkSwitchToJITForEpilogue()
1789     loadi 4[PC], t0
1790     assertNotConstant(t0)
1791     loadi TagOffset[cfr, t0, 8], t1
1792     loadi PayloadOffset[cfr, t0, 8], t0
1793     doReturn()
1794
1795
1796 _llint_throw_from_slow_path_trampoline:
1797     # When throwing from the interpreter (i.e. throwing from LLIntSlowPaths), so
1798     # the throw target is not necessarily interpreted code, we come to here.
1799     # This essentially emulates the JIT's throwing protocol.
1800     loadp JITStackFrame::globalData[sp], t1
1801     loadp JSGlobalData::callFrameForThrow[t1], t0
1802     jmp JSGlobalData::targetMachinePCForThrow[t1]
1803
1804
1805 _llint_throw_during_call_trampoline:
1806     preserveReturnAddressAfterCall(t2)
1807     loadp JITStackFrame::globalData[sp], t1
1808     loadp JSGlobalData::callFrameForThrow[t1], t0
1809     jmp JSGlobalData::targetMachinePCForThrow[t1]
1810
1811
1812 macro nativeCallTrampoline(executableOffsetToFunction)
1813     storep 0, CodeBlock[cfr]
1814     loadp CallerFrame[cfr], t0
1815     loadi ScopeChain + PayloadOffset[t0], t1
1816     storei CellTag, ScopeChain + TagOffset[cfr]
1817     storei t1, ScopeChain + PayloadOffset[cfr]
1818     if X86
1819         loadp JITStackFrame::globalData + 4[sp], t3 # Additional offset for return address
1820         storep cfr, JSGlobalData::topCallFrame[t3]
1821         peek 0, t1
1822         storep t1, ReturnPC[cfr]
1823         move cfr, t2  # t2 = ecx
1824         subp 16 - 4, sp
1825         loadi Callee + PayloadOffset[cfr], t1
1826         loadp JSFunction::m_executable[t1], t1
1827         move t0, cfr
1828         call executableOffsetToFunction[t1]
1829         addp 16 - 4, sp
1830         loadp JITStackFrame::globalData + 4[sp], t3
1831     elsif ARMv7
1832         loadp JITStackFrame::globalData[sp], t3
1833         storep cfr, JSGlobalData::topCallFrame[t3]
1834         move t0, t2
1835         preserveReturnAddressAfterCall(t3)
1836         storep t3, ReturnPC[cfr]
1837         move cfr, t0
1838         loadi Callee + PayloadOffset[cfr], t1
1839         loadp JSFunction::m_executable[t1], t1
1840         move t2, cfr
1841         call executableOffsetToFunction[t1]
1842         restoreReturnAddressBeforeReturn(t3)
1843         loadp JITStackFrame::globalData[sp], t3
1844     elsif C_LOOP
1845         loadp JITStackFrame::globalData[sp], t3
1846         storep cfr, JSGlobalData::topCallFrame[t3]
1847         move t0, t2
1848         preserveReturnAddressAfterCall(t3)
1849         storep t3, ReturnPC[cfr]
1850         move cfr, t0
1851         loadi Callee + PayloadOffset[cfr], t1
1852         loadp JSFunction::m_executable[t1], t1
1853         move t2, cfr
1854         cloopCallNative executableOffsetToFunction[t1]
1855         restoreReturnAddressBeforeReturn(t3)
1856         loadp JITStackFrame::globalData[sp], t3
1857     else  
1858         error
1859     end
1860     bineq JSGlobalData::exception + TagOffset[t3], EmptyValueTag, .exception
1861     ret
1862 .exception:
1863     preserveReturnAddressAfterCall(t1) # This is really only needed on X86
1864     loadi ArgumentCount + TagOffset[cfr], PC
1865     callSlowPath(_llint_throw_from_native_call)
1866     jmp _llint_throw_from_slow_path_trampoline
1867 end
1868