1 # Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
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.
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.
25 # Crash course on the language that this is written in (which I just call
26 # "assembly" even though it's more than that):
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
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.
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.
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 "_"
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.
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
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
70 # Below we have a bunch of constant declarations. Each constant must have
71 # a corresponding ASSERT() in LLIntData.cpp.
74 # Value representation constants.
78 const UndefinedTag = -4
80 const EmptyValueTag = -6
81 const DeletedValueTag = -7
82 const LowestTag = DeletedValueTag
86 macro dispatch(advance)
91 macro dispatchBranchWithOffset(pcOffset)
97 macro dispatchBranch(pcOffset)
99 dispatchBranchWithOffset(t0)
102 macro dispatchAfterCall()
103 loadi ArgumentCount + TagOffset[cfr], PC
107 macro cCall2(function, arg1, arg2)
120 # This barely works. arg3 and arg4 should probably be immediates.
121 macro cCall4(function, arg1, arg2, arg3, arg4)
138 macro callSlowPath(slowPath)
139 cCall2(slowPath, cfr, PC)
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)
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
157 macro traceValue(fromWhere, operand)
158 cCall4(_llint_trace_value, cfr, PC, fromWhere, operand)
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)
172 macro checkSwitchToJITForLoop()
176 storei PC, ArgumentCount + TagOffset[cfr]
177 cCall2(_llint_loop_osr, cfr, PC)
182 loadi ArgumentCount + TagOffset[cfr], PC
186 # Index, tag, and payload must be different registers. Index is not
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
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
203 macro loadConstantOrVariableTag(index, tag)
204 bigteq index, FirstConstantRegisterIndex, .constant
205 loadi TagOffset[cfr, index, 8], tag
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
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
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.
229 loadp PayloadOffset[tag], payload
230 loadp TagOffset[tag], tag
234 macro loadConstantOrVariablePayloadTagCustom(index, tagCheck, payload)
235 bigteq index, FirstConstantRegisterIndex, .constant
236 tagCheck(TagOffset[cfr, index, 8])
237 loadi PayloadOffset[cfr, index, 8], payload
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
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
254 macro loadConstantOrVariablePayload(index, expectedTag, payload, slow)
255 loadConstantOrVariablePayloadTagCustom(
257 macro (actualTag) bineq actualTag, expectedTag, slow end,
261 macro loadConstantOrVariablePayloadUnchecked(index, payload)
262 loadConstantOrVariablePayloadTagCustom(
264 macro (actualTag) end,
268 macro writeBarrier(tag, payload)
269 # Nothing to do, since we don't have a generational or incremental collector.
272 macro valueProfile(tag, payload, profile)
274 storei tag, ValueProfile::m_buckets + TagOffset[profile]
275 storei payload, ValueProfile::m_buckets + PayloadOffset[profile]
280 # Entrypoints into the interpreter
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
289 loadp JITStackFrame::globalData[sp], t1
290 loadp JSGlobalData::callFrameForThrow[t1], t0
291 jmp JSGlobalData::targetMachinePCForThrow[t1]
293 # Reload CodeBlock and PC, since the slow_path clobbered it.
294 loadp CodeBlock[cfr], t1
295 loadp CodeBlock::m_instructions[t1], PC
300 # Instruction implementations
304 loadp CodeBlock[cfr], t2
305 loadi CodeBlock::m_numVars[t2], t2
306 btiz t2, .opEnterDone
307 move UndefinedTag, t0
311 storei t0, TagOffset[cfr, t2, 8]
312 storei t1, PayloadOffset[cfr, t2, 8]
313 btinz t2, .opEnterLoop
318 _llint_op_create_activation:
321 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateActivationDone
322 callSlowPath(_llint_slow_path_create_activation)
323 .opCreateActivationDone:
327 _llint_op_init_lazy_reg:
330 storei EmptyValueTag, TagOffset[cfr, t0, 8]
331 storei 0, PayloadOffset[cfr, t0, 8]
335 _llint_op_create_arguments:
338 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateArgumentsDone
339 callSlowPath(_llint_slow_path_create_arguments)
340 .opCreateArgumentsDone:
344 _llint_op_create_this:
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)
356 storei CellTag, TagOffset[cfr, t1, 8]
357 storei t0, PayloadOffset[cfr, t1, 8]
361 callSlowPath(_llint_slow_path_create_this)
365 _llint_op_get_callee:
368 loadp PayloadOffset + Callee[cfr], t1
369 storei CellTag, TagOffset[cfr, t0, 8]
370 storei t1, PayloadOffset[cfr, t0, 8]
374 _llint_op_convert_this:
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
384 callSlowPath(_llint_slow_path_convert_this)
388 _llint_op_new_object:
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)
395 storei CellTag, TagOffset[cfr, t1, 8]
396 storei t0, PayloadOffset[cfr, t1, 8]
400 callSlowPath(_llint_slow_path_new_object)
408 loadConstantOrVariable(t1, t2, t3)
409 storei t2, TagOffset[cfr, t0, 8]
410 storei t3, PayloadOffset[cfr, t0, 8]
418 loadConstantOrVariable(t0, t2, t3)
419 bineq t2, BooleanTag, .opNotSlow
421 storei t2, TagOffset[cfr, t1, 8]
422 storei t3, PayloadOffset[cfr, t1, 8]
426 callSlowPath(_llint_slow_path_not)
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
441 storei BooleanTag, TagOffset[cfr, t2, 8]
442 storei t0, PayloadOffset[cfr, t2, 8]
446 callSlowPath(_llint_slow_path_eq)
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
463 cieq t1, UndefinedTag, t1
465 .opEqNullNotImmediate:
466 storei BooleanTag, TagOffset[cfr, t3, 8]
467 storei t1, PayloadOffset[cfr, t3, 8]
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
482 storei BooleanTag, TagOffset[cfr, t2, 8]
483 storei t0, PayloadOffset[cfr, t2, 8]
487 callSlowPath(_llint_slow_path_neq)
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
503 cineq t1, NullTag, t2
504 cineq t1, UndefinedTag, t1
506 .opNeqNullNotImmediate:
507 storei BooleanTag, TagOffset[cfr, t3, 8]
508 storei t1, PayloadOffset[cfr, t3, 8]
512 macro strictEq(equalityOperation, slowPath)
515 loadConstantOrVariable(t2, t3, t1)
516 loadConstantOrVariable2Reg(t0, t2, t0)
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
526 equalityOperation(t0, t1, t0)
527 storei BooleanTag, TagOffset[cfr, t2, 8]
528 storei t0, PayloadOffset[cfr, t2, 8]
532 callSlowPath(slowPath)
538 strictEq(macro (left, right, result) cieq left, right, result end, _llint_slow_path_stricteq)
543 strictEq(macro (left, right, result) cineq left, right, result end, _llint_slow_path_nstricteq)
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]
556 callSlowPath(_llint_slow_path_pre_inc)
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]
570 callSlowPath(_llint_slow_path_pre_dec)
578 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPostIncSlow
579 bieq t0, t1, .opPostIncDone
580 loadi PayloadOffset[cfr, t0, 8], t2
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]
590 callSlowPath(_llint_slow_path_post_inc)
598 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPostDecSlow
599 bieq t0, t1, .opPostDecDone
600 loadi PayloadOffset[cfr, t0, 8], t2
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]
610 callSlowPath(_llint_slow_path_post_dec)
614 _llint_op_to_jsnumber:
618 loadConstantOrVariable(t0, t2, t3)
619 bieq t2, Int32Tag, .opToJsnumberIsInt
620 biaeq t2, EmptyValueTag, .opToJsnumberSlow
622 storei t2, TagOffset[cfr, t1, 8]
623 storei t3, PayloadOffset[cfr, t1, 8]
627 callSlowPath(_llint_slow_path_to_jsnumber)
635 loadConstantOrVariable(t0, t1, t2)
636 bineq t1, Int32Tag, .opNegateSrcNotInt
637 btiz t2, 0x7fffffff, .opNegateSlow
639 storei Int32Tag, TagOffset[cfr, t3, 8]
640 storei t2, PayloadOffset[cfr, t3, 8]
643 bia t1, LowestTag, .opNegateSlow
645 storei t1, TagOffset[cfr, t3, 8]
646 storei t2, PayloadOffset[cfr, t3, 8]
650 callSlowPath(_llint_slow_path_negate)
654 macro binaryOpCustomStore(integerOperationAndStore, doubleOperation, slowPath)
657 loadConstantOrVariable(t2, t3, t1)
658 loadConstantOrVariable2Reg(t0, t2, t0)
659 bineq t2, Int32Tag, .op1NotInt
660 bineq t3, Int32Tag, .op2NotInt
662 integerOperationAndStore(t3, t1, t0, .slow, t2)
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
677 doubleOperation(ft1, ft0)
678 stored ft0, [cfr, t1, 8]
682 # First operand is definitely an int, the second operand is definitely not.
684 bia t3, LowestTag, .slow
687 doubleOperation(ft1, ft0)
688 stored ft0, [cfr, t2, 8]
692 callSlowPath(slowPath)
696 macro binaryOp(integerOperation, doubleOperation, slowPath)
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]
703 doubleOperation, slowPath)
709 macro (left, right, slow) baddio left, right, slow end,
710 macro (left, right) addd left, right end,
711 _llint_slow_path_add)
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.
720 bmulio left, scratch, slow
725 storei Int32Tag, TagOffset[cfr, index, 8]
726 storei scratch, PayloadOffset[cfr, index, 8]
728 macro (left, right) muld left, right end,
729 _llint_slow_path_mul)
735 macro (left, right, slow) bsubio left, right, slow end,
736 macro (left, right) subd left, right end,
737 _llint_slow_path_sub)
743 macro (int32Tag, left, right, slow, index)
747 bcd2i ft1, right, .notInt
748 storei int32Tag, TagOffset[cfr, index, 8]
749 storei right, PayloadOffset[cfr, index, 8]
752 stored ft1, [cfr, index, 8]
755 macro (left, right) divd left, right end,
756 _llint_slow_path_div)
759 macro bitOp(operation, slowPath, advance)
762 loadConstantOrVariable(t2, t3, t1)
763 loadConstantOrVariable2Reg(t0, t2, t0)
764 bineq t3, Int32Tag, .slow
765 bineq t2, Int32Tag, .slow
767 operation(t1, t0, .slow)
768 storei t3, TagOffset[cfr, t2, 8]
769 storei t0, PayloadOffset[cfr, t2, 8]
773 callSlowPath(slowPath)
780 macro (left, right, slow) lshifti left, right end,
781 _llint_slow_path_lshift,
788 macro (left, right, slow) rshifti left, right end,
789 _llint_slow_path_rshift,
796 macro (left, right, slow)
800 _llint_slow_path_urshift,
807 macro (left, right, slow) andi left, right end,
808 _llint_slow_path_bitand,
815 macro (left, right, slow) xori left, right end,
816 _llint_slow_path_bitxor,
823 macro (left, right, slow) ori left, right end,
824 _llint_slow_path_bitor,
828 _llint_op_check_has_instance:
831 loadConstantOrVariablePayload(t1, CellTag, t0, .opCheckHasInstanceSlow)
832 loadp JSCell::m_structure[t0], t0
833 btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsHasInstance, .opCheckHasInstanceSlow
836 .opCheckHasInstanceSlow:
837 callSlowPath(_llint_slow_path_check_has_instance)
841 _llint_op_instanceof:
843 # Check that baseVal implements the default HasInstance behavior.
844 # FIXME: This should be deprecated.
846 loadConstantOrVariablePayloadUnchecked(t1, t0)
847 loadp JSCell::m_structure[t0], t0
848 btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opInstanceofSlow
850 # Actually do the work.
853 loadConstantOrVariablePayload(t0, CellTag, t1, .opInstanceofSlow)
854 loadp JSCell::m_structure[t1], t2
855 bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opInstanceofSlow
857 loadConstantOrVariablePayload(t0, CellTag, t2, .opInstanceofSlow)
859 # Register state: t1 = prototype, t2 = value
862 loadp JSCell::m_structure[t2], t2
863 loadi Structure::m_prototype + PayloadOffset[t2], t2
864 bpeq t2, t1, .opInstanceofDone
865 btinz t2, .opInstanceofLoop
869 storei BooleanTag, TagOffset[cfr, t3, 8]
870 storei t0, PayloadOffset[cfr, t3, 8]
874 callSlowPath(_llint_slow_path_instanceof)
878 _llint_op_is_undefined:
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]
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]
895 _llint_op_is_boolean:
899 loadConstantOrVariableTag(t1, t0)
900 cieq t0, BooleanTag, t0
901 storei BooleanTag, TagOffset[cfr, t2, 8]
902 storei t0, PayloadOffset[cfr, t2, 8]
910 loadConstantOrVariableTag(t1, t0)
911 storei BooleanTag, TagOffset[cfr, t2, 8]
913 cib t0, LowestTag + 1, t1
914 storei t1, PayloadOffset[cfr, t2, 8]
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]
930 storep 0, PayloadOffset[cfr, t2, 8]
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
945 loadp JSObject::m_propertyStorage[t0], t0
946 loadi TagOffset[t0, t1, 8], t2
947 loadi PayloadOffset[t0, t1, 8], t3
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)
955 _llint_op_resolve_global:
957 resolveGlobal(6, .opResolveGlobalSlow)
960 .opResolveGlobalSlow:
961 callSlowPath(_llint_slow_path_resolve_global)
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
975 loadp CodeBlock[cfr], t1
976 bineq CodeBlock::m_codeType[t1], FunctionCode, .loop
977 btbz CodeBlock::m_needsFullScopeChain[t1], .loop
979 loadi CodeBlock::m_activationRegister[t1], t1
981 # Need to conditionally skip over one scope.
982 bieq TagOffset[cfr, t1, 8], EmptyValueTag, .noActivation
984 loadp ScopeChainNode::next[t0], t0
991 loadp ScopeChainNode::next[t0], t0
998 _llint_op_resolve_global_dynamic:
1000 loadp JITStackFrame::globalData[sp], t3
1001 loadp JSGlobalData::activationStructure[t3], t3
1004 macro (scope, scratch)
1005 loadp ScopeChainNode::object[scope], scratch
1006 bpneq JSCell::m_structure[scratch], t3, .opResolveGlobalDynamicSuperSlow
1008 resolveGlobal(7, .opResolveGlobalDynamicSlow)
1011 .opResolveGlobalDynamicSuperSlow:
1012 callSlowPath(_llint_slow_path_resolve_for_resolve_global_dynamic)
1015 .opResolveGlobalDynamicSlow:
1016 callSlowPath(_llint_slow_path_resolve_global_dynamic)
1020 _llint_op_get_scoped_var:
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)
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]
1036 valueProfile(t3, t0, t1)
1040 _llint_op_put_scoped_var:
1042 getScope(8[PC], macro (scope, scratch) end)
1044 loadConstantOrVariable(t1, t3, t2)
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]
1054 _llint_op_get_global_var:
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]
1066 valueProfile(t2, t1, t3)
1070 _llint_op_put_global_var:
1073 loadp CodeBlock[cfr], t0
1074 loadp CodeBlock::m_globalObject[t0], t0
1075 loadp JSGlobalObject::m_registers[t0], t0
1076 loadConstantOrVariable(t1, t2, t3)
1078 writeBarrier(t2, t3)
1079 storei t2, TagOffset[t0, t1, 8]
1080 storei t3, PayloadOffset[t0, t1, 8]
1084 _llint_op_get_by_id:
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.
1093 loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow)
1095 loadp JSObject::m_propertyStorage[t3], t0
1096 bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
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]
1103 valueProfile(t3, t2, t1)
1107 callSlowPath(_llint_slow_path_get_by_id)
1111 _llint_op_get_arguments_length:
1115 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentsLengthSlow
1116 loadi ArgumentCount + PayloadOffset[cfr], t2
1118 storei Int32Tag, TagOffset[cfr, t1, 8]
1119 storei t2, PayloadOffset[cfr, t1, 8]
1122 .opGetArgumentsLengthSlow:
1123 callSlowPath(_llint_slow_path_get_arguments_length)
1127 _llint_op_put_by_id:
1131 loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1133 loadp JSObject::m_propertyStorage[t0], t3
1134 bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1136 loadConstantOrVariable2Reg(t2, t0, t2)
1137 writeBarrier(t0, t2)
1138 storei t0, TagOffset[t3, t1]
1139 storei t2, PayloadOffset[t3, t1]
1143 callSlowPath(_llint_slow_path_put_by_id)
1147 macro putByIdTransition(additionalChecks)
1151 loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1153 bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1154 additionalChecks(t1, t3, .opPutByIdSlow)
1156 loadp JSObject::m_propertyStorage[t0], t3
1158 loadConstantOrVariable2Reg(t2, t1, t2)
1159 writeBarrier(t1, t2)
1160 storei t1, TagOffset[t3]
1162 storei t2, PayloadOffset[t3]
1163 storep t1, JSCell::m_structure[t0]
1167 _llint_op_put_by_id_transition_direct:
1168 putByIdTransition(macro (oldStructure, scratch, slow) end)
1171 _llint_op_put_by_id_transition_normal:
1173 macro (oldStructure, scratch, slow)
1174 const protoCell = oldStructure # Reusing the oldStructure register for the proto
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
1182 loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell
1183 loadp JSCell::m_structure[protoCell], oldStructure
1184 bpneq oldStructure, [scratch], slow
1186 bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop
1191 _llint_op_get_by_val:
1193 loadp CodeBlock[cfr], t1
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
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]
1210 valueProfile(t2, t1, t0)
1214 callSlowPath(_llint_slow_path_get_by_val)
1218 _llint_op_get_argument_by_val:
1222 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentByValSlow
1223 loadConstantOrVariablePayload(t1, Int32Tag, t2, .opGetArgumentByValSlow)
1225 loadi ArgumentCount + PayloadOffset[cfr], t1
1226 biaeq t2, t1, .opGetArgumentByValSlow
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]
1235 .opGetArgumentByValSlow:
1236 callSlowPath(_llint_slow_path_get_argument_by_val)
1240 _llint_op_get_by_pname:
1243 loadConstantOrVariablePayload(t0, CellTag, t1, .opGetByPnameSlow)
1245 bpneq t1, PayloadOffset[cfr, t0, 8], .opGetByPnameSlow
1247 loadConstantOrVariablePayload(t0, CellTag, t2, .opGetByPnameSlow)
1249 loadi PayloadOffset[cfr, t0, 8], t3
1250 loadp JSCell::m_structure[t2], t0
1251 bpneq t0, JSPropertyNameIterator::m_cachedStructure[t3], .opGetByPnameSlow
1253 loadi [cfr, t0, 8], 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
1260 storei t1, TagOffset[cfr, t0, 8]
1261 storei t3, PayloadOffset[cfr, t0, 8]
1265 callSlowPath(_llint_slow_path_get_by_pname)
1269 _llint_op_put_by_val:
1272 loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
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:
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]
1291 addi 1, ArrayStorage::m_numValuesInVector[t0]
1292 bib t2, ArrayStorage::m_length[t0], .opPutByValStoreResult
1294 storei t1, ArrayStorage::m_length[t0]
1295 jmp .opPutByValStoreResult
1298 callSlowPath(_llint_slow_path_put_by_val)
1306 dispatchBranch(4[PC])
1309 macro jumpTrueOrFalse(conditionOp, slow)
1311 loadConstantOrVariablePayload(t1, BooleanTag, t0, .slow)
1312 conditionOp(t0, .target)
1316 dispatchBranch(8[PC])
1324 macro equalNull(cellHandler, immediateHandler)
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)
1335 dispatchBranch(8[PC])
1339 immediateHandler(t1, .target)
1346 macro (value, target) btbnz value, MasqueradesAsUndefined, target end,
1347 macro (value, target) bieq value, NullTag, target end)
1350 _llint_op_jneq_null:
1353 macro (value, target) btbz value, MasqueradesAsUndefined, target end,
1354 macro (value, target) bineq value, NullTag, target end)
1361 bineq TagOffset[cfr, t0, 8], CellTag, .opJneqPtrBranch
1362 bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough
1364 dispatchBranch(12[PC])
1365 .opJneqPtrFallThrough:
1369 macro compare(integerCompare, doubleCompare, slowPath)
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)
1380 bia t0, LowestTag, .slow
1381 bib t2, LowestTag, .op1NotIntOp2Double
1382 bineq t2, Int32Tag, .slow
1385 .op1NotIntOp2Double:
1389 doubleCompare(ft0, ft1, .jumpTarget)
1394 bia t2, LowestTag, .slow
1396 doubleCompare(ft0, ft1, .jumpTarget)
1400 dispatchBranch(12[PC])
1403 callSlowPath(slowPath)
1408 _llint_op_switch_imm:
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
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)
1427 bib t1, LowestTag, .opSwitchImmSlow # Go to slow path if it's a double.
1428 .opSwitchImmFallThrough:
1429 dispatchBranch(8[PC])
1432 callSlowPath(_llint_slow_path_switch_imm)
1436 _llint_op_switch_char:
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
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
1455 jmp .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)
1466 .opSwitchCharFallThrough:
1467 dispatchBranch(8[PC])
1470 callSlowPath(_llint_slow_path_switch_char)
1476 btiz 12[PC], .opNewFuncUnchecked
1478 bineq TagOffset[cfr, t1, 8], EmptyValueTag, .opNewFuncDone
1479 .opNewFuncUnchecked:
1480 callSlowPath(_llint_slow_path_new_func)
1485 macro doCall(slowPath)
1488 loadp LLIntCallLinkInfo::callee[t1], t2
1489 loadConstantOrVariablePayload(t0, CellTag, t3, .opCallSlow)
1490 bineq t3, t2, .opCallSlow
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]
1505 call LLIntCallLinkInfo::machineCodeTarget[t1]
1509 slowPathForCall(6, slowPath)
1513 _llint_op_tear_off_activation:
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:
1525 _llint_op_tear_off_arguments:
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:
1537 checkSwitchToJITForEpilogue()
1539 loadConstantOrVariable(t2, t1, t0)
1543 _llint_op_call_put_result:
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
1553 _llint_op_ret_object_or_this:
1555 checkSwitchToJITForEpilogue()
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
1563 .opRetObjectOrThisNotObject:
1565 loadConstantOrVariable(t2, t1, t0)
1569 _llint_op_to_primitive:
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]
1582 .opToPrimitiveSlowCase:
1583 callSlowPath(_llint_slow_path_to_primitive)
1587 _llint_op_next_pname:
1591 loadi PayloadOffset[cfr, t1, 8], t0
1592 bieq t0, PayloadOffset[cfr, t2, 8], .opNextPnameEnd
1594 loadi PayloadOffset[cfr, t2, 8], t2
1595 loadp JSPropertyNameIterator::m_jsStrings[t2], t3
1596 loadi [t3, t0, 8], t3
1598 storei t0, PayloadOffset[cfr, t1, 8]
1600 storei CellTag, TagOffset[cfr, t1, 8]
1601 storei t3, PayloadOffset[cfr, t1, 8]
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
1615 btpnz [t0], .opNextPnameCheckPrototypeLoop
1617 dispatchBranch(24[PC])
1623 callSlowPath(_llint_slow_path_next_pname) # This either keeps the PC where it was (causing us to loop) or sets it to target.
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.
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]
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.
1650 checkSwitchToJITForEpilogue()
1652 assertNotConstant(t0)
1653 loadi TagOffset[cfr, t0, 8], t1
1654 loadi PayloadOffset[cfr, t0, 8], t0
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]
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]
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]
1681 loadp JITStackFrame::globalData + 4[sp], t3 # Additional offset for return address
1682 storep cfr, JSGlobalData::topCallFrame[t3]
1684 storep t1, ReturnPC[cfr]
1685 move cfr, t2 # t2 = ecx
1687 loadi Callee + PayloadOffset[cfr], t1
1688 loadp JSFunction::m_executable[t1], t1
1690 call executableOffsetToFunction[t1]
1692 loadp JITStackFrame::globalData + 4[sp], t3
1694 loadp JITStackFrame::globalData[sp], t3
1695 storep cfr, JSGlobalData::topCallFrame[t3]
1697 preserveReturnAddressAfterCall(t3)
1698 storep t3, ReturnPC[cfr]
1700 loadi Callee + PayloadOffset[cfr], t1
1701 loadp JSFunction::m_executable[t1], t1
1703 call executableOffsetToFunction[t1]
1704 restoreReturnAddressBeforeReturn(t3)
1705 loadp JITStackFrame::globalData[sp], t3
1709 bineq JSGlobalData::exception + TagOffset[t3], EmptyValueTag, .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