DFG should be able to set watchpoints on global variables
[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 macro getGlobalVar(size)
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 (size - 1) * 4[PC], t3
1051     valueProfile(t2, t1, t3)
1052     dispatch(size)
1053 end
1054
1055 _llint_op_get_global_var:
1056     getGlobalVar(4)
1057
1058
1059 _llint_op_get_global_var_watchable:
1060     getGlobalVar(5)
1061
1062
1063 _llint_op_put_global_var:
1064     traceExecution()
1065     loadi 8[PC], t1
1066     loadi 4[PC], t0
1067     loadConstantOrVariable(t1, t2, t3)
1068     writeBarrier(t2, t3)
1069     storei t2, TagOffset[t0]
1070     storei t3, PayloadOffset[t0]
1071     dispatch(3)
1072
1073
1074 _llint_op_put_global_var_check:
1075     traceExecution()
1076     loadp 12[PC], t2
1077     loadi 8[PC], t1
1078     loadi 4[PC], t0
1079     btbnz [t2], .opPutGlobalVarCheckSlow
1080     loadConstantOrVariable(t1, t2, t3)
1081     writeBarrier(t2, t3)
1082     storei t2, TagOffset[t0]
1083     storei t3, PayloadOffset[t0]
1084     dispatch(5)
1085 .opPutGlobalVarCheckSlow:
1086     callSlowPath(_llint_slow_path_put_global_var_check)
1087     dispatch(5)
1088
1089
1090 _llint_op_get_by_id:
1091     traceExecution()
1092     # We only do monomorphic get_by_id caching for now, and we do not modify the
1093     # opcode. We do, however, allow for the cache to change anytime if fails, since
1094     # ping-ponging is free. At best we get lucky and the get_by_id will continue
1095     # to take fast path on the new cache. At worst we take slow path, which is what
1096     # we would have been doing anyway.
1097     loadi 8[PC], t0
1098     loadi 16[PC], t1
1099     loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow)
1100     loadi 20[PC], t2
1101     loadp JSObject::m_propertyStorage[t3], t0
1102     bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
1103     loadi 4[PC], t1
1104     loadi TagOffset[t0, t2], t3
1105     loadi PayloadOffset[t0, t2], t2
1106     storei t3, TagOffset[cfr, t1, 8]
1107     storei t2, PayloadOffset[cfr, t1, 8]
1108     loadi 32[PC], t1
1109     valueProfile(t3, t2, t1)
1110     dispatch(9)
1111
1112 .opGetByIdSlow:
1113     callSlowPath(_llint_slow_path_get_by_id)
1114     dispatch(9)
1115
1116
1117 _llint_op_get_arguments_length:
1118     traceExecution()
1119     loadi 8[PC], t0
1120     loadi 4[PC], t1
1121     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentsLengthSlow
1122     loadi ArgumentCount + PayloadOffset[cfr], t2
1123     subi 1, t2
1124     storei Int32Tag, TagOffset[cfr, t1, 8]
1125     storei t2, PayloadOffset[cfr, t1, 8]
1126     dispatch(4)
1127
1128 .opGetArgumentsLengthSlow:
1129     callSlowPath(_llint_slow_path_get_arguments_length)
1130     dispatch(4)
1131
1132
1133 _llint_op_put_by_id:
1134     traceExecution()
1135     loadi 4[PC], t3
1136     loadi 16[PC], t1
1137     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1138     loadi 12[PC], t2
1139     loadp JSObject::m_propertyStorage[t0], t3
1140     bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1141     loadi 20[PC], t1
1142     loadConstantOrVariable2Reg(t2, t0, t2)
1143     writeBarrier(t0, t2)
1144     storei t0, TagOffset[t3, t1]
1145     storei t2, PayloadOffset[t3, t1]
1146     dispatch(9)
1147
1148 .opPutByIdSlow:
1149     callSlowPath(_llint_slow_path_put_by_id)
1150     dispatch(9)
1151
1152
1153 macro putByIdTransition(additionalChecks)
1154     traceExecution()
1155     loadi 4[PC], t3
1156     loadi 16[PC], t1
1157     loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1158     loadi 12[PC], t2
1159     bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1160     additionalChecks(t1, t3, .opPutByIdSlow)
1161     loadi 20[PC], t1
1162     loadp JSObject::m_propertyStorage[t0], t3
1163     addp t1, t3
1164     loadConstantOrVariable2Reg(t2, t1, t2)
1165     writeBarrier(t1, t2)
1166     storei t1, TagOffset[t3]
1167     loadi 24[PC], t1
1168     storei t2, PayloadOffset[t3]
1169     storep t1, JSCell::m_structure[t0]
1170     dispatch(9)
1171 end
1172
1173 _llint_op_put_by_id_transition_direct:
1174     putByIdTransition(macro (oldStructure, scratch, slow) end)
1175
1176
1177 _llint_op_put_by_id_transition_normal:
1178     putByIdTransition(
1179         macro (oldStructure, scratch, slow)
1180             const protoCell = oldStructure   # Reusing the oldStructure register for the proto
1181         
1182             loadp 28[PC], scratch
1183             assert(macro (ok) btpnz scratch, ok end)
1184             loadp StructureChain::m_vector[scratch], scratch
1185             assert(macro (ok) btpnz scratch, ok end)
1186             bieq Structure::m_prototype + TagOffset[oldStructure], NullTag, .done
1187         .loop:
1188             loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell
1189             loadp JSCell::m_structure[protoCell], oldStructure
1190             bpneq oldStructure, [scratch], slow
1191             addp 4, scratch
1192             bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop
1193         .done:
1194         end)
1195
1196
1197 _llint_op_get_by_val:
1198     traceExecution()
1199     loadp CodeBlock[cfr], t1
1200     loadi 8[PC], t2
1201     loadi 12[PC], t3
1202     loadp CodeBlock::m_globalData[t1], t1
1203     loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow)
1204     loadp JSGlobalData::jsArrayClassInfo[t1], t2
1205     loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
1206     bpneq [t0], t2, .opGetByValSlow
1207     loadp JSArray::m_storage[t0], t3
1208     biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow
1209     loadi 4[PC], t0
1210     loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2
1211     loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1
1212     bieq t2, EmptyValueTag, .opGetByValSlow
1213     storei t2, TagOffset[cfr, t0, 8]
1214     storei t1, PayloadOffset[cfr, t0, 8]
1215     loadi 16[PC], t0
1216     valueProfile(t2, t1, t0)
1217     dispatch(5)
1218
1219 .opGetByValSlow:
1220     callSlowPath(_llint_slow_path_get_by_val)
1221     dispatch(5)
1222
1223
1224 _llint_op_get_argument_by_val:
1225     traceExecution()
1226     loadi 8[PC], t0
1227     loadi 12[PC], t1
1228     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentByValSlow
1229     loadConstantOrVariablePayload(t1, Int32Tag, t2, .opGetArgumentByValSlow)
1230     addi 1, t2
1231     loadi ArgumentCount + PayloadOffset[cfr], t1
1232     biaeq t2, t1, .opGetArgumentByValSlow
1233     negi t2
1234     loadi 4[PC], t3
1235     loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0
1236     loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t1
1237     loadi 16[PC], t2
1238     storei t0, TagOffset[cfr, t3, 8]
1239     storei t1, PayloadOffset[cfr, t3, 8]
1240     valueProfile(t0, t1, t2)
1241     dispatch(5)
1242
1243 .opGetArgumentByValSlow:
1244     callSlowPath(_llint_slow_path_get_argument_by_val)
1245     dispatch(5)
1246
1247
1248 _llint_op_get_by_pname:
1249     traceExecution()
1250     loadi 12[PC], t0
1251     loadConstantOrVariablePayload(t0, CellTag, t1, .opGetByPnameSlow)
1252     loadi 16[PC], t0
1253     bpneq t1, PayloadOffset[cfr, t0, 8], .opGetByPnameSlow
1254     loadi 8[PC], t0
1255     loadConstantOrVariablePayload(t0, CellTag, t2, .opGetByPnameSlow)
1256     loadi 20[PC], t0
1257     loadi PayloadOffset[cfr, t0, 8], t3
1258     loadp JSCell::m_structure[t2], t0
1259     bpneq t0, JSPropertyNameIterator::m_cachedStructure[t3], .opGetByPnameSlow
1260     loadi 24[PC], t0
1261     loadi [cfr, t0, 8], t0
1262     subi 1, t0
1263     biaeq t0, JSPropertyNameIterator::m_numCacheableSlots[t3], .opGetByPnameSlow
1264     loadp JSObject::m_propertyStorage[t2], t2
1265     loadi TagOffset[t2, t0, 8], t1
1266     loadi PayloadOffset[t2, t0, 8], t3
1267     loadi 4[PC], t0
1268     storei t1, TagOffset[cfr, t0, 8]
1269     storei t3, PayloadOffset[cfr, t0, 8]
1270     dispatch(7)
1271
1272 .opGetByPnameSlow:
1273     callSlowPath(_llint_slow_path_get_by_pname)
1274     dispatch(7)
1275
1276
1277 _llint_op_put_by_val:
1278     traceExecution()
1279     loadi 4[PC], t0
1280     loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
1281     loadi 8[PC], t0
1282     loadConstantOrVariablePayload(t0, Int32Tag, t2, .opPutByValSlow)
1283     loadp CodeBlock[cfr], t0
1284     loadp CodeBlock::m_globalData[t0], t0
1285     loadp JSGlobalData::jsArrayClassInfo[t0], t0
1286     bpneq [t1], t0, .opPutByValSlow
1287     biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow
1288     loadp JSArray::m_storage[t1], t0
1289     bieq ArrayStorage::m_vector + TagOffset[t0, t2, 8], EmptyValueTag, .opPutByValEmpty
1290 .opPutByValStoreResult:
1291     loadi 12[PC], t3
1292     loadConstantOrVariable2Reg(t3, t1, t3)
1293     writeBarrier(t1, t3)
1294     storei t1, ArrayStorage::m_vector + TagOffset[t0, t2, 8]
1295     storei t3, ArrayStorage::m_vector + PayloadOffset[t0, t2, 8]
1296     dispatch(4)
1297
1298 .opPutByValEmpty:
1299     addi 1, ArrayStorage::m_numValuesInVector[t0]
1300     bib t2, ArrayStorage::m_length[t0], .opPutByValStoreResult
1301     addi 1, t2, t1
1302     storei t1, ArrayStorage::m_length[t0]
1303     jmp .opPutByValStoreResult
1304
1305 .opPutByValSlow:
1306     callSlowPath(_llint_slow_path_put_by_val)
1307     dispatch(4)
1308
1309
1310 _llint_op_loop:
1311     nop
1312 _llint_op_jmp:
1313     traceExecution()
1314     dispatchBranch(4[PC])
1315
1316
1317 macro jumpTrueOrFalse(conditionOp, slow)
1318     loadi 4[PC], t1
1319     loadConstantOrVariablePayload(t1, BooleanTag, t0, .slow)
1320     conditionOp(t0, .target)
1321     dispatch(3)
1322
1323 .target:
1324     dispatchBranch(8[PC])
1325
1326 .slow:
1327     callSlowPath(slow)
1328     dispatch(0)
1329 end
1330
1331
1332 macro equalNull(cellHandler, immediateHandler)
1333     loadi 4[PC], t0
1334     assertNotConstant(t0)
1335     loadi TagOffset[cfr, t0, 8], t1
1336     loadi PayloadOffset[cfr, t0, 8], t0
1337     bineq t1, CellTag, .immediate
1338     loadp JSCell::m_structure[t0], t2
1339     cellHandler(Structure::m_typeInfo + TypeInfo::m_flags[t2], .target)
1340     dispatch(3)
1341
1342 .target:
1343     dispatchBranch(8[PC])
1344
1345 .immediate:
1346     ori 1, t1
1347     immediateHandler(t1, .target)
1348     dispatch(3)
1349 end
1350
1351 _llint_op_jeq_null:
1352     traceExecution()
1353     equalNull(
1354         macro (value, target) btbnz value, MasqueradesAsUndefined, target end,
1355         macro (value, target) bieq value, NullTag, target end)
1356     
1357
1358 _llint_op_jneq_null:
1359     traceExecution()
1360     equalNull(
1361         macro (value, target) btbz value, MasqueradesAsUndefined, target end,
1362         macro (value, target) bineq value, NullTag, target end)
1363
1364
1365 _llint_op_jneq_ptr:
1366     traceExecution()
1367     loadi 4[PC], t0
1368     loadi 8[PC], t1
1369     bineq TagOffset[cfr, t0, 8], CellTag, .opJneqPtrBranch
1370     bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough
1371 .opJneqPtrBranch:
1372     dispatchBranch(12[PC])
1373 .opJneqPtrFallThrough:
1374     dispatch(4)
1375
1376
1377 macro compare(integerCompare, doubleCompare, slowPath)
1378     loadi 4[PC], t2
1379     loadi 8[PC], t3
1380     loadConstantOrVariable(t2, t0, t1)
1381     loadConstantOrVariable2Reg(t3, t2, t3)
1382     bineq t0, Int32Tag, .op1NotInt
1383     bineq t2, Int32Tag, .op2NotInt
1384     integerCompare(t1, t3, .jumpTarget)
1385     dispatch(4)
1386
1387 .op1NotInt:
1388     bia t0, LowestTag, .slow
1389     bib t2, LowestTag, .op1NotIntOp2Double
1390     bineq t2, Int32Tag, .slow
1391     ci2d t3, ft1
1392     jmp .op1NotIntReady
1393 .op1NotIntOp2Double:
1394     fii2d t3, t2, ft1
1395 .op1NotIntReady:
1396     fii2d t1, t0, ft0
1397     doubleCompare(ft0, ft1, .jumpTarget)
1398     dispatch(4)
1399
1400 .op2NotInt:
1401     ci2d t1, ft0
1402     bia t2, LowestTag, .slow
1403     fii2d t3, t2, ft1
1404     doubleCompare(ft0, ft1, .jumpTarget)
1405     dispatch(4)
1406
1407 .jumpTarget:
1408     dispatchBranch(12[PC])
1409
1410 .slow:
1411     callSlowPath(slowPath)
1412     dispatch(0)
1413 end
1414
1415
1416 _llint_op_switch_imm:
1417     traceExecution()
1418     loadi 12[PC], t2
1419     loadi 4[PC], t3
1420     loadConstantOrVariable(t2, t1, t0)
1421     loadp CodeBlock[cfr], t2
1422     loadp CodeBlock::m_rareData[t2], t2
1423     muli sizeof SimpleJumpTable, t3   # FIXME: would be nice to peephole this!
1424     loadp CodeBlock::RareData::m_immediateSwitchJumpTables + VectorBufferOffset[t2], t2
1425     addp t3, t2
1426     bineq t1, Int32Tag, .opSwitchImmNotInt
1427     subi SimpleJumpTable::min[t2], t0
1428     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchImmFallThrough
1429     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t3
1430     loadi [t3, t0, 4], t1
1431     btiz t1, .opSwitchImmFallThrough
1432     dispatchBranchWithOffset(t1)
1433
1434 .opSwitchImmNotInt:
1435     bib t1, LowestTag, .opSwitchImmSlow  # Go to slow path if it's a double.
1436 .opSwitchImmFallThrough:
1437     dispatchBranch(8[PC])
1438
1439 .opSwitchImmSlow:
1440     callSlowPath(_llint_slow_path_switch_imm)
1441     dispatch(0)
1442
1443
1444 _llint_op_switch_char:
1445     traceExecution()
1446     loadi 12[PC], t2
1447     loadi 4[PC], t3
1448     loadConstantOrVariable(t2, t1, t0)
1449     loadp CodeBlock[cfr], t2
1450     loadp CodeBlock::m_rareData[t2], t2
1451     muli sizeof SimpleJumpTable, t3
1452     loadp CodeBlock::RareData::m_characterSwitchJumpTables + VectorBufferOffset[t2], t2
1453     addp t3, t2
1454     bineq t1, CellTag, .opSwitchCharFallThrough
1455     loadp JSCell::m_structure[t0], t1
1456     bbneq Structure::m_typeInfo + TypeInfo::m_type[t1], StringType, .opSwitchCharFallThrough
1457     bineq JSString::m_length[t0], 1, .opSwitchCharFallThrough
1458     loadp JSString::m_value[t0], t0
1459     btpz  t0, .opSwitchOnRope
1460     loadp StringImpl::m_data8[t0], t1
1461     btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
1462     loadh [t1], t0
1463     jmp .opSwitchCharReady
1464 .opSwitchChar8Bit:
1465     loadb [t1], t0
1466 .opSwitchCharReady:
1467     subi SimpleJumpTable::min[t2], t0
1468     biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchCharFallThrough
1469     loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t2
1470     loadi [t2, t0, 4], t1
1471     btiz t1, .opSwitchCharFallThrough
1472     dispatchBranchWithOffset(t1)
1473
1474 .opSwitchCharFallThrough:
1475     dispatchBranch(8[PC])
1476
1477 .opSwitchOnRope:
1478     callSlowPath(_llint_slow_path_switch_char)
1479     dispatch(0)
1480
1481
1482 _llint_op_new_func:
1483     traceExecution()
1484     btiz 12[PC], .opNewFuncUnchecked
1485     loadi 4[PC], t1
1486     bineq TagOffset[cfr, t1, 8], EmptyValueTag, .opNewFuncDone
1487 .opNewFuncUnchecked:
1488     callSlowPath(_llint_slow_path_new_func)
1489 .opNewFuncDone:
1490     dispatch(4)
1491
1492
1493 macro doCall(slowPath)
1494     loadi 4[PC], t0
1495     loadi 16[PC], t1
1496     loadp LLIntCallLinkInfo::callee[t1], t2
1497     loadConstantOrVariablePayload(t0, CellTag, t3, .opCallSlow)
1498     bineq t3, t2, .opCallSlow
1499     loadi 12[PC], t3
1500     addp 24, PC
1501     lshifti 3, t3
1502     addp cfr, t3  # t3 contains the new value of cfr
1503     loadp JSFunction::m_scopeChain[t2], t0
1504     storei t2, Callee + PayloadOffset[t3]
1505     storei t0, ScopeChain + PayloadOffset[t3]
1506     loadi 8 - 24[PC], t2
1507     storei PC, ArgumentCount + TagOffset[cfr]
1508     storep cfr, CallerFrame[t3]
1509     storei t2, ArgumentCount + PayloadOffset[t3]
1510     storei CellTag, Callee + TagOffset[t3]
1511     storei CellTag, ScopeChain + TagOffset[t3]
1512     move t3, cfr
1513     call LLIntCallLinkInfo::machineCodeTarget[t1]
1514     dispatchAfterCall()
1515
1516 .opCallSlow:
1517     slowPathForCall(6, slowPath)
1518 end
1519
1520
1521 _llint_op_tear_off_activation:
1522     traceExecution()
1523     loadi 4[PC], t0
1524     loadi 8[PC], t1
1525     bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffActivationCreated
1526     bieq TagOffset[cfr, t1, 8], EmptyValueTag, .opTearOffActivationNotCreated
1527 .opTearOffActivationCreated:
1528     callSlowPath(_llint_slow_path_tear_off_activation)
1529 .opTearOffActivationNotCreated:
1530     dispatch(3)
1531
1532
1533 _llint_op_tear_off_arguments:
1534     traceExecution()
1535     loadi 4[PC], t0
1536     subi 1, t0   # Get the unmodifiedArgumentsRegister
1537     bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffArgumentsNotCreated
1538     callSlowPath(_llint_slow_path_tear_off_arguments)
1539 .opTearOffArgumentsNotCreated:
1540     dispatch(2)
1541
1542
1543 _llint_op_ret:
1544     traceExecution()
1545     checkSwitchToJITForEpilogue()
1546     loadi 4[PC], t2
1547     loadConstantOrVariable(t2, t1, t0)
1548     doReturn()
1549
1550
1551 _llint_op_call_put_result:
1552     loadi 4[PC], t2
1553     loadi 8[PC], t3
1554     storei t1, TagOffset[cfr, t2, 8]
1555     storei t0, PayloadOffset[cfr, t2, 8]
1556     valueProfile(t1, t0, t3)
1557     traceExecution() # Needs to be here because it would clobber t1, t0
1558     dispatch(3)
1559
1560
1561 _llint_op_ret_object_or_this:
1562     traceExecution()
1563     checkSwitchToJITForEpilogue()
1564     loadi 4[PC], t2
1565     loadConstantOrVariable(t2, t1, t0)
1566     bineq t1, CellTag, .opRetObjectOrThisNotObject
1567     loadp JSCell::m_structure[t0], t2
1568     bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opRetObjectOrThisNotObject
1569     doReturn()
1570
1571 .opRetObjectOrThisNotObject:
1572     loadi 8[PC], t2
1573     loadConstantOrVariable(t2, t1, t0)
1574     doReturn()
1575
1576
1577 _llint_op_to_primitive:
1578     traceExecution()
1579     loadi 8[PC], t2
1580     loadi 4[PC], t3
1581     loadConstantOrVariable(t2, t1, t0)
1582     bineq t1, CellTag, .opToPrimitiveIsImm
1583     loadp JSCell::m_structure[t0], t2
1584     bbneq Structure::m_typeInfo + TypeInfo::m_type[t2], StringType, .opToPrimitiveSlowCase
1585 .opToPrimitiveIsImm:
1586     storei t1, TagOffset[cfr, t3, 8]
1587     storei t0, PayloadOffset[cfr, t3, 8]
1588     dispatch(3)
1589
1590 .opToPrimitiveSlowCase:
1591     callSlowPath(_llint_slow_path_to_primitive)
1592     dispatch(3)
1593
1594
1595 _llint_op_next_pname:
1596     traceExecution()
1597     loadi 12[PC], t1
1598     loadi 16[PC], t2
1599     loadi PayloadOffset[cfr, t1, 8], t0
1600     bieq t0, PayloadOffset[cfr, t2, 8], .opNextPnameEnd
1601     loadi 20[PC], t2
1602     loadi PayloadOffset[cfr, t2, 8], t2
1603     loadp JSPropertyNameIterator::m_jsStrings[t2], t3
1604     loadi [t3, t0, 8], t3
1605     addi 1, t0
1606     storei t0, PayloadOffset[cfr, t1, 8]
1607     loadi 4[PC], t1
1608     storei CellTag, TagOffset[cfr, t1, 8]
1609     storei t3, PayloadOffset[cfr, t1, 8]
1610     loadi 8[PC], t3
1611     loadi PayloadOffset[cfr, t3, 8], t3
1612     loadp JSCell::m_structure[t3], t1
1613     bpneq t1, JSPropertyNameIterator::m_cachedStructure[t2], .opNextPnameSlow
1614     loadp JSPropertyNameIterator::m_cachedPrototypeChain[t2], t0
1615     loadp StructureChain::m_vector[t0], t0
1616     btpz [t0], .opNextPnameTarget
1617 .opNextPnameCheckPrototypeLoop:
1618     bieq Structure::m_prototype + TagOffset[t1], NullTag, .opNextPnameSlow
1619     loadp Structure::m_prototype + PayloadOffset[t1], t2
1620     loadp JSCell::m_structure[t2], t1
1621     bpneq t1, [t0], .opNextPnameSlow
1622     addp 4, t0
1623     btpnz [t0], .opNextPnameCheckPrototypeLoop
1624 .opNextPnameTarget:
1625     dispatchBranch(24[PC])
1626
1627 .opNextPnameEnd:
1628     dispatch(7)
1629
1630 .opNextPnameSlow:
1631     callSlowPath(_llint_slow_path_next_pname) # This either keeps the PC where it was (causing us to loop) or sets it to target.
1632     dispatch(0)
1633
1634
1635 _llint_op_catch:
1636     # This is where we end up from the JIT's throw trampoline (because the
1637     # machine code return address will be set to _llint_op_catch), and from
1638     # the interpreter's throw trampoline (see _llint_throw_trampoline).
1639     # The JIT throwing protocol calls for the cfr to be in t0. The throwing
1640     # code must have known that we were throwing to the interpreter, and have
1641     # set JSGlobalData::targetInterpreterPCForThrow.
1642     move t0, cfr
1643     loadp JITStackFrame::globalData[sp], t3
1644     loadi JSGlobalData::targetInterpreterPCForThrow[t3], PC
1645     loadi JSGlobalData::exception + PayloadOffset[t3], t0
1646     loadi JSGlobalData::exception + TagOffset[t3], t1
1647     storei 0, JSGlobalData::exception + PayloadOffset[t3]
1648     storei EmptyValueTag, JSGlobalData::exception + TagOffset[t3]       
1649     loadi 4[PC], t2
1650     storei t0, PayloadOffset[cfr, t2, 8]
1651     storei t1, TagOffset[cfr, t2, 8]
1652     traceExecution()  # This needs to be here because we don't want to clobber t0, t1, t2, t3 above.
1653     dispatch(2)
1654
1655
1656 _llint_op_end:
1657     traceExecution()
1658     checkSwitchToJITForEpilogue()
1659     loadi 4[PC], t0
1660     assertNotConstant(t0)
1661     loadi TagOffset[cfr, t0, 8], t1
1662     loadi PayloadOffset[cfr, t0, 8], t0
1663     doReturn()
1664
1665
1666 _llint_throw_from_slow_path_trampoline:
1667     # When throwing from the interpreter (i.e. throwing from LLIntSlowPaths), so
1668     # the throw target is not necessarily interpreted code, we come to here.
1669     # This essentially emulates the JIT's throwing protocol.
1670     loadp JITStackFrame::globalData[sp], t1
1671     loadp JSGlobalData::callFrameForThrow[t1], t0
1672     jmp JSGlobalData::targetMachinePCForThrow[t1]
1673
1674
1675 _llint_throw_during_call_trampoline:
1676     preserveReturnAddressAfterCall(t2)
1677     loadp JITStackFrame::globalData[sp], t1
1678     loadp JSGlobalData::callFrameForThrow[t1], t0
1679     jmp JSGlobalData::targetMachinePCForThrow[t1]
1680
1681
1682 macro nativeCallTrampoline(executableOffsetToFunction)
1683     storep 0, CodeBlock[cfr]
1684     loadp CallerFrame[cfr], t0
1685     loadi ScopeChain + PayloadOffset[t0], t1
1686     storei CellTag, ScopeChain + TagOffset[cfr]
1687     storei t1, ScopeChain + PayloadOffset[cfr]
1688     if X86
1689         loadp JITStackFrame::globalData + 4[sp], t3 # Additional offset for return address
1690         storep cfr, JSGlobalData::topCallFrame[t3]
1691         peek 0, t1
1692         storep t1, ReturnPC[cfr]
1693         move cfr, t2  # t2 = ecx
1694         subp 16 - 4, sp
1695         loadi Callee + PayloadOffset[cfr], t1
1696         loadp JSFunction::m_executable[t1], t1
1697         move t0, cfr
1698         call executableOffsetToFunction[t1]
1699         addp 16 - 4, sp
1700         loadp JITStackFrame::globalData + 4[sp], t3
1701     elsif ARMv7
1702         loadp JITStackFrame::globalData[sp], t3
1703         storep cfr, JSGlobalData::topCallFrame[t3]
1704         move t0, t2
1705         preserveReturnAddressAfterCall(t3)
1706         storep t3, ReturnPC[cfr]
1707         move cfr, t0
1708         loadi Callee + PayloadOffset[cfr], t1
1709         loadp JSFunction::m_executable[t1], t1
1710         move t2, cfr
1711         call executableOffsetToFunction[t1]
1712         restoreReturnAddressBeforeReturn(t3)
1713         loadp JITStackFrame::globalData[sp], t3
1714     else  
1715         error
1716     end
1717     bineq JSGlobalData::exception + TagOffset[t3], EmptyValueTag, .exception
1718     ret
1719 .exception:
1720     preserveReturnAddressAfterCall(t1) # This is really only needed on X86
1721     loadi ArgumentCount + TagOffset[cfr], PC
1722     callSlowPath(_llint_throw_from_native_call)
1723     jmp _llint_throw_from_slow_path_trampoline
1724 end
1725