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