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