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# These declarations must match interpreter/RegisterFile.h.
71const CallFrameHeaderSize = 48
72const ArgumentCount = -48
73const CallerFrame = -40
74const Callee = -32
75const ScopeChain = -24
76const ReturnPC = -16
77const CodeBlock = -8
78
79const ThisArgumentOffset = -CallFrameHeaderSize - 8
80
81# Declare some aliases for the registers we will use.
82const PC = t4
83
84# Offsets needed for reasoning about value representation.
85if BIG_ENDIAN
86 const TagOffset = 0
87 const PayloadOffset = 4
88else
89 const TagOffset = 4
90 const PayloadOffset = 0
91end
92
93# Value representation constants.
94const Int32Tag = -1
95const BooleanTag = -2
96const NullTag = -3
97const UndefinedTag = -4
98const CellTag = -5
99const EmptyValueTag = -6
100const DeletedValueTag = -7
101const LowestTag = DeletedValueTag
102
103# Type constants.
104const StringType = 5
105const ObjectType = 10
106
107# Type flags constants.
108const MasqueradesAsUndefined = 1
109const ImplementsHasInstance = 2
110const ImplementsDefaultHasInstance = 8
111
112# Heap allocation constants.
113const JSFinalObjectSizeClassIndex = 3
114
115# Bytecode operand constants.
116const FirstConstantRegisterIndex = 0x40000000
117
118# Code type constants.
119const GlobalCode = 0
120const EvalCode = 1
121const FunctionCode = 2
122
123# The interpreter steals the tag word of the argument count.
124const LLIntReturnPC = ArgumentCount + TagOffset
125
126# This must match wtf/Vector.h.
127const VectorSizeOffset = 0
128const VectorBufferOffset = 4
129
130# String flags.
131const HashFlags8BitBuffer = 64
132
133# Utilities
134macro crash()
135 storei 0, 0xbbadbeef[]
136 move 0, t0
137 call t0
138end
139
140macro assert(assertion)
141 if ASSERT_ENABLED
142 assertion(.ok)
143 crash()
144 .ok:
145 end
146end
147
148macro preserveReturnAddressAfterCall(destinationRegister)
149 if ARMv7
150 move lr, destinationRegister
151 elsif X86
152 pop destinationRegister
153 else
154 error
155 end
156end
157
158macro restoreReturnAddressBeforeReturn(sourceRegister)
159 if ARMv7
160 move sourceRegister, lr
161 elsif X86
162 push sourceRegister
163 else
164 error
165 end
166end
167
168macro dispatch(advance)
169 addp advance * 4, PC
170 jmp [PC]
171end
172
173macro dispatchBranchWithOffset(pcOffset)
174 lshifti 2, pcOffset
175 addp pcOffset, PC
176 jmp [PC]
177end
178
179macro dispatchBranch(pcOffset)
180 loadi pcOffset, t0
181 dispatchBranchWithOffset(t0)
182end
183
184macro dispatchAfterCall()
185 loadi ArgumentCount + TagOffset[cfr], PC
186 jmp [PC]
187end
188
189macro cCall2(function, arg1, arg2)
190 if ARMv7
191 move arg1, t0
192 move arg2, t1
193 elsif X86
194 poke arg1, 0
195 poke arg2, 1
196 else
197 error
198 end
199 call function
200end
201
202# This barely works. arg3 and arg4 should probably be immediates.
203macro cCall4(function, arg1, arg2, arg3, arg4)
204 if ARMv7
205 move arg1, t0
206 move arg2, t1
207 move arg3, t2
208 move arg4, t3
209 elsif X86
210 poke arg1, 0
211 poke arg2, 1
212 poke arg3, 2
213 poke arg4, 3
214 else
215 error
216 end
217 call function
218end
219
220macro callHelper(helper)
221 cCall2(helper, cfr, PC)
222 move t0, PC
223 move t1, cfr
224end
225
226# Debugging operation if you'd like to print an operand in the instruction stream. fromWhere
227# should be an immediate integer - any integer you like; use it to identify the place you're
228# debugging from. operand should likewise be an immediate, and should identify the operand
229# in the instruction stream you'd like to print out.
230macro traceOperand(fromWhere, operand)
231 cCall4(_llint_trace_operand, cfr, PC, fromWhere, operand)
232 move t0, PC
233 move t1, cfr
234end
235
236# Debugging operation if you'd like to print the value of an operand in the instruction
237# stream. Same as traceOperand(), but assumes that the operand is a register, and prints its
238# value.
239macro traceValue(fromWhere, operand)
240 cCall4(_llint_trace_value, cfr, PC, fromWhere, operand)
241 move t0, PC
242 move t1, cfr
243end
244
245macro traceExecution()
246 if EXECUTION_TRACING
247 callHelper(_llint_trace)
248 end
249end
250
251# Call a helper for call opcodes.
252macro callCallHelper(advance, helper, action)
253 addp advance * 4, PC, t0
254 storep t0, ArgumentCount + TagOffset[cfr]
255 cCall2(helper, cfr, PC)
256 move t1, cfr
257 action(t0)
258end
259
260macro slowPathForCall(advance, helper)
261 callCallHelper(
262 advance,
263 helper,
264 macro (callee)
265 call callee
266 dispatchAfterCall()
267 end)
268end
269
270macro checkSwitchToJIT(increment, action)
271 if JIT_ENABLED
272 loadp CodeBlock[cfr], t0
273 baddis increment, CodeBlock::m_llintExecuteCounter[t0], .continue
274 action()
275 .continue:
276 end
277end
278
279macro checkSwitchToJITForLoop()
280 checkSwitchToJIT(
281 1,
282 macro ()
283 storei PC, ArgumentCount + TagOffset[cfr]
284 cCall2(_llint_loop_osr, cfr, PC)
285 move t1, cfr
286 btpz t0, .recover
287 jmp t0
288 .recover:
289 loadi ArgumentCount + TagOffset[cfr], PC
290 end)
291end
292
293macro checkSwitchToJITForEpilogue()
294 checkSwitchToJIT(
295 10,
296 macro ()
297 callHelper(_llint_replace)
298 end)
299end
300
301macro assertNotConstant(index)
302 assert(macro (ok) bilt index, FirstConstantRegisterIndex, ok end)
303end
304
305# Index, tag, and payload must be different registers. Index is not
306# changed.
307macro loadConstantOrVariable(index, tag, payload)
308 bigteq index, FirstConstantRegisterIndex, .constant
309 loadi TagOffset[cfr, index, 8], tag
310 loadi PayloadOffset[cfr, index, 8], payload
311 jmp .done
312.constant:
313 loadp CodeBlock[cfr], payload
314 loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload
315 # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
316 # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
317 loadp TagOffset[payload, index, 8], tag
318 loadp PayloadOffset[payload, index, 8], payload
319.done:
320end
321
322# Index and payload may be the same register. Index may be clobbered.
323macro loadConstantOrVariable2Reg(index, tag, payload)
324 bigteq index, FirstConstantRegisterIndex, .constant
325 loadi TagOffset[cfr, index, 8], tag
326 loadi PayloadOffset[cfr, index, 8], payload
327 jmp .done
328.constant:
329 loadp CodeBlock[cfr], tag
330 loadp CodeBlock::m_constantRegisters + VectorBufferOffset[tag], tag
331 # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
332 # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
333 lshifti 3, index
334 addp index, tag
335 loadp PayloadOffset[tag], payload
336 loadp TagOffset[tag], tag
337.done:
338end
339
340macro loadConstantOrVariablePayloadTagCustom(index, tagCheck, payload)
341 bigteq index, FirstConstantRegisterIndex, .constant
342 tagCheck(TagOffset[cfr, index, 8])
343 loadi PayloadOffset[cfr, index, 8], payload
344 jmp .done
345.constant:
346 loadp CodeBlock[cfr], payload
347 loadp CodeBlock::m_constantRegisters + VectorBufferOffset[payload], payload
348 # There is a bit of evil here: if the index contains a value >= FirstConstantRegisterIndex,
349 # then value << 3 will be equal to (value - FirstConstantRegisterIndex) << 3.
350 tagCheck(TagOffset[payload, index, 8])
351 loadp PayloadOffset[payload, index, 8], payload
352.done:
353end
354
355# Index and payload must be different registers. Index is not mutated. Use
356# this if you know what the tag of the variable should be. Doing the tag
357# test as part of loading the variable reduces register use, but may not
358# be faster than doing loadConstantOrVariable followed by a branch on the
359# tag.
360macro loadConstantOrVariablePayload(index, expectedTag, payload, slow)
361 loadConstantOrVariablePayloadTagCustom(
362 index,
363 macro (actualTag) bineq actualTag, expectedTag, slow end,
364 payload)
365end
366
367macro loadConstantOrVariablePayloadUnchecked(index, payload)
368 loadConstantOrVariablePayloadTagCustom(
369 index,
370 macro (actualTag) end,
371 payload)
372end
373
374macro writeBarrier(tag, payload)
375 # Nothing to do, since we don't have a generational or incremental collector.
376end
377
378macro valueProfile(tag, payload, profile)
379 storei tag, ValueProfile::m_buckets + TagOffset[profile]
380 storei payload, ValueProfile::m_buckets + PayloadOffset[profile]
381end
382
383
384# Indicate the beginning of LLInt.
385_llint_begin:
386 crash()
387
388
389# Entrypoints into the interpreter
390
391macro functionForCallCodeBlockGetter(targetRegister)
392 loadp Callee[cfr], targetRegister
393 loadp JSFunction::m_executable[targetRegister], targetRegister
394 loadp FunctionExecutable::m_codeBlockForCall[targetRegister], targetRegister
395end
396
397macro functionForConstructCodeBlockGetter(targetRegister)
398 loadp Callee[cfr], targetRegister
399 loadp JSFunction::m_executable[targetRegister], targetRegister
400 loadp FunctionExecutable::m_codeBlockForConstruct[targetRegister], targetRegister
401end
402
403macro notFunctionCodeBlockGetter(targetRegister)
404 loadp CodeBlock[cfr], targetRegister
405end
406
407macro functionCodeBlockSetter(sourceRegister)
408 storep sourceRegister, CodeBlock[cfr]
409end
410
411macro notFunctionCodeBlockSetter(sourceRegister)
412 # Nothing to do!
413end
414
415# Do the bare minimum required to execute code. Sets up the PC, leave the CodeBlock*
416# in t1. May also trigger prologue entry OSR.
417macro prologue(codeBlockGetter, codeBlockSetter, osrHelper, traceHelper)
418 preserveReturnAddressAfterCall(t2)
419
420 # Set up the call frame and check if we should OSR.
421 storep t2, ReturnPC[cfr]
422 if EXECUTION_TRACING
423 callHelper(traceHelper)
424 end
425 codeBlockGetter(t1)
426 if JIT_ENABLED
427 baddis 5, CodeBlock::m_llintExecuteCounter[t1], .continue
428 cCall2(osrHelper, cfr, PC)
429 move t1, cfr
430 btpz t0, .recover
431 loadp ReturnPC[cfr], t2
432 restoreReturnAddressBeforeReturn(t2)
433 jmp t0
434 .recover:
435 codeBlockGetter(t1)
436 .continue:
437 end
438 codeBlockSetter(t1)
439
440 # Set up the PC.
441 loadp CodeBlock::m_instructions[t1], t0
442 loadp CodeBlock::Instructions::m_instructions + VectorBufferOffset[t0], PC
443end
444
445# Expects that CodeBlock is in t1, which is what prologue() leaves behind.
446# Must call dispatch(0) after calling this.
447macro functionInitialization(profileArgSkip)
448 # Profile the arguments. Unfortunately, we have no choice but to do this. This
449 # code is pretty horrendous because of the difference in ordering between
450 # arguments and value profiles, the desire to have a simple loop-down-to-zero
451 # loop, and the desire to use only three registers so as to preserve the PC and
452 # the code block. It is likely that this code should be rewritten in a more
453 # optimal way for architectures that have more than five registers available
454 # for arbitrary use in the interpreter.
455 loadi CodeBlock::m_numParameters[t1], t0
456 addi -profileArgSkip, t0 # Use addi because that's what has the peephole
457 assert(macro (ok) bigteq t0, 0, ok end)
458 btiz t0, .argumentProfileDone
459 loadp CodeBlock::m_argumentValueProfiles + VectorBufferOffset[t1], t3
460 muli sizeof ValueProfile, t0, t2 # Aaaaahhhh! Need strength reduction!
461 negi t0
462 lshifti 3, t0
463 addp t2, t3
464.argumentProfileLoop:
465 loadi ThisArgumentOffset + TagOffset + 8 - profileArgSkip * 8[cfr, t0], t2
466 subp sizeof ValueProfile, t3
467 storei t2, profileArgSkip * sizeof ValueProfile + ValueProfile::m_buckets + TagOffset[t3]
468 loadi ThisArgumentOffset + PayloadOffset + 8 - profileArgSkip * 8[cfr, t0], t2
469 storei t2, profileArgSkip * sizeof ValueProfile + ValueProfile::m_buckets + PayloadOffset[t3]
470 baddinz 8, t0, .argumentProfileLoop
471.argumentProfileDone:
472
473 # Check stack height.
474 loadi CodeBlock::m_numCalleeRegisters[t1], t0
475 loadp CodeBlock::m_globalData[t1], t2
476 loadp JSGlobalData::interpreter[t2], t2 # FIXME: Can get to the RegisterFile from the JITStackFrame
477 lshifti 3, t0
478 addp t0, cfr, t0
479 bpaeq Interpreter::m_registerFile + RegisterFile::m_end[t2], t0, .stackHeightOK
480
481 # Stack height check failed - need to call a helper.
482 callHelper(_llint_register_file_check)
483.stackHeightOK:
484end
485
486# Expects that CodeBlock is in t1, which is what prologue() leaves behind.
487macro functionArityCheck(doneLabel, helper)
488 loadi PayloadOffset + ArgumentCount[cfr], t0
489 biaeq t0, CodeBlock::m_numParameters[t1], doneLabel
490 cCall2(helper, cfr, PC) # This helper has a simple protocol: t0 = 0 => no error, t0 != 0 => error
491 move t1, cfr
492 btiz t0, .continue
493 loadp JITStackFrame::globalData[sp], t1
494 loadp JSGlobalData::callFrameForThrow[t1], t0
495 jmp JSGlobalData::targetMachinePCForThrow[t1]
496.continue:
497 # Reload CodeBlock and PC, since the helper clobbered it.
498 loadp CodeBlock[cfr], t1
499 loadp CodeBlock::m_instructions[t1], t0
500 loadp CodeBlock::Instructions::m_instructions + VectorBufferOffset[t0], PC
501 jmp doneLabel
502end
503
504_llint_program_prologue:
505 prologue(notFunctionCodeBlockGetter, notFunctionCodeBlockSetter, _llint_entry_osr, _llint_trace_prologue)
506 dispatch(0)
507
508
509_llint_eval_prologue:
510 prologue(notFunctionCodeBlockGetter, notFunctionCodeBlockSetter, _llint_entry_osr, _llint_trace_prologue)
511 dispatch(0)
512
513
514_llint_function_for_call_prologue:
515 prologue(functionForCallCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_call, _llint_trace_prologue_function_for_call)
516.functionForCallBegin:
517 functionInitialization(0)
518 dispatch(0)
519
520
521_llint_function_for_construct_prologue:
522 prologue(functionForConstructCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_construct, _llint_trace_prologue_function_for_construct)
523.functionForConstructBegin:
524 functionInitialization(1)
525 dispatch(0)
526
527
528_llint_function_for_call_arity_check:
529 prologue(functionForCallCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_call_arityCheck, _llint_trace_arityCheck_for_call)
530 functionArityCheck(.functionForCallBegin, _llint_helper_call_arityCheck)
531
532
533_llint_function_for_construct_arity_check:
534 prologue(functionForConstructCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_construct_arityCheck, _llint_trace_arityCheck_for_construct)
535 functionArityCheck(.functionForConstructBegin, _llint_helper_construct_arityCheck)
536
537# Instruction implementations
538
539_llint_op_enter:
540 traceExecution()
541 loadp CodeBlock[cfr], t2
542 loadi CodeBlock::m_numVars[t2], t2
543 btiz t2, .opEnterDone
544 move UndefinedTag, t0
545 move 0, t1
546.opEnterLoop:
547 subi 1, t2
548 storei t0, TagOffset[cfr, t2, 8]
549 storei t1, PayloadOffset[cfr, t2, 8]
550 btinz t2, .opEnterLoop
551.opEnterDone:
552 dispatch(1)
553
554
555_llint_op_create_activation:
556 traceExecution()
557 loadi 4[PC], t0
558 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateActivationDone
559 callHelper(_llint_helper_create_activation)
560.opCreateActivationDone:
561 dispatch(2)
562
563
564_llint_op_init_lazy_reg:
565 traceExecution()
566 loadi 4[PC], t0
567 storei EmptyValueTag, TagOffset[cfr, t0, 8]
568 storei 0, PayloadOffset[cfr, t0, 8]
569 dispatch(2)
570
571
572_llint_op_create_arguments:
573 traceExecution()
574 loadi 4[PC], t0
575 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opCreateArgumentsDone
576 callHelper(_llint_helper_create_arguments)
577.opCreateArgumentsDone:
578 dispatch(2)
579
580
581macro allocateBasicJSObject(sizeClassIndex, classInfoOffset, structure, result, scratch1, scratch2, slowCase)
582 if ALWAYS_ALLOCATE_SLOW
583 jmp slowCase
584 else
585 const offsetOfMySizeClass = JSGlobalData::heap + Heap::m_objectSpace + MarkedSpace::m_preciseSizeClasses + sizeClassIndex * sizeof MarkedAllocator
586
587 # FIXME: we can get the global data in one load from the stack.
588 loadp CodeBlock[cfr], scratch1
589 loadp CodeBlock::m_globalData[scratch1], scratch1
590
591 # Get the object from the free list.
592 loadp offsetOfMySizeClass + MarkedAllocator::m_firstFreeCell[scratch1], result
593 btpz result, slowCase
594
595 # Remove the object from the free list.
596 loadp [result], scratch2
597 storep scratch2, offsetOfMySizeClass + MarkedAllocator::m_firstFreeCell[scratch1]
598
599 # Initialize the object.
600 loadp classInfoOffset[scratch1], scratch2
601 storep scratch2, [result]
602 storep structure, JSCell::m_structure[result]
603 storep 0, JSObject::m_inheritorID[result]
604 addp sizeof JSObject, result, scratch1
605 storep scratch1, JSObject::m_propertyStorage[result]
606 end
607end
608
609_llint_op_create_this:
610 traceExecution()
611 loadi 8[PC], t0
612 assertNotConstant(t0)
613 bineq TagOffset[cfr, t0, 8], CellTag, .opCreateThisSlow
614 loadi PayloadOffset[cfr, t0, 8], t0
615 loadp JSCell::m_structure[t0], t1
616 bbb Structure::m_typeInfo + TypeInfo::m_type[t1], ObjectType, .opCreateThisSlow
617 loadp JSObject::m_inheritorID[t0], t2
618 btpz t2, .opCreateThisSlow
619 allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t2, t0, t1, t3, .opCreateThisSlow)
620 loadi 4[PC], t1
621 storei CellTag, TagOffset[cfr, t1, 8]
622 storei t0, PayloadOffset[cfr, t1, 8]
623 dispatch(3)
624
625.opCreateThisSlow:
626 callHelper(_llint_helper_create_this)
627 dispatch(3)
628
629
630_llint_op_get_callee:
631 traceExecution()
632 loadi 4[PC], t0
633 loadp PayloadOffset + Callee[cfr], t1
634 storei CellTag, TagOffset[cfr, t0, 8]
635 storei t1, PayloadOffset[cfr, t0, 8]
636 dispatch(2)
637
638
639_llint_op_convert_this:
640 traceExecution()
641 loadi 4[PC], t0
642 bineq TagOffset[cfr, t0, 8], CellTag, .opConvertThisSlow
643 loadi PayloadOffset[cfr, t0, 8], t0
644 loadp JSCell::m_structure[t0], t0
645 bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow
646 dispatch(2)
647
648.opConvertThisSlow:
649 callHelper(_llint_helper_convert_this)
650 dispatch(2)
651
652
653_llint_op_new_object:
654 traceExecution()
655 loadp CodeBlock[cfr], t0
656 loadp CodeBlock::m_globalObject[t0], t0
657 loadp JSGlobalObject::m_emptyObjectStructure[t0], t1
658 allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t1, t0, t2, t3, .opNewObjectSlow)
659 loadi 4[PC], t1
660 storei CellTag, TagOffset[cfr, t1, 8]
661 storei t0, PayloadOffset[cfr, t1, 8]
662 dispatch(2)
663
664.opNewObjectSlow:
665 callHelper(_llint_helper_new_object)
666 dispatch(2)
667
668
669_llint_op_new_array:
670 traceExecution()
671 callHelper(_llint_helper_new_array)
672 dispatch(4)
673
674
675_llint_op_new_array_buffer:
676 traceExecution()
677 callHelper(_llint_helper_new_array_buffer)
678 dispatch(4)
679
680
681_llint_op_new_regexp:
682 traceExecution()
683 callHelper(_llint_helper_new_regexp)
684 dispatch(3)
685
686
687_llint_op_mov:
688 traceExecution()
689 loadi 8[PC], t1
690 loadi 4[PC], t0
691 loadConstantOrVariable(t1, t2, t3)
692 storei t2, TagOffset[cfr, t0, 8]
693 storei t3, PayloadOffset[cfr, t0, 8]
694 dispatch(3)
695
696
697_llint_op_not:
698 traceExecution()
699 loadi 8[PC], t0
700 loadi 4[PC], t1
701 loadConstantOrVariable(t0, t2, t3)
702 bineq t2, BooleanTag, .opNotSlow
703 xori 1, t3
704 storei t2, TagOffset[cfr, t1, 8]
705 storei t3, PayloadOffset[cfr, t1, 8]
706 dispatch(3)
707
708.opNotSlow:
709 callHelper(_llint_helper_not)
710 dispatch(3)
711
712
713_llint_op_eq:
714 traceExecution()
715 loadi 12[PC], t2
716 loadi 8[PC], t0
717 loadConstantOrVariable(t2, t3, t1)
718 loadConstantOrVariable2Reg(t0, t2, t0)
719 bineq t2, t3, .opEqSlow
720 bieq t2, CellTag, .opEqSlow
721 bib t2, LowestTag, .opEqSlow
722 loadi 4[PC], t2
723 cieq t0, t1, t0
724 storei BooleanTag, TagOffset[cfr, t2, 8]
725 storei t0, PayloadOffset[cfr, t2, 8]
726 dispatch(4)
727
728.opEqSlow:
729 callHelper(_llint_helper_eq)
730 dispatch(4)
731
732
733_llint_op_eq_null:
734 traceExecution()
735 loadi 8[PC], t0
736 loadi 4[PC], t3
737 assertNotConstant(t0)
738 loadi TagOffset[cfr, t0, 8], t1
739 loadi PayloadOffset[cfr, t0, 8], t0
740 bineq t1, CellTag, .opEqNullImmediate
741 loadp JSCell::m_structure[t0], t1
742 tbnz Structure::m_typeInfo + TypeInfo::m_flags[t1], MasqueradesAsUndefined, t1
743 jmp .opEqNullNotImmediate
744.opEqNullImmediate:
745 cieq t1, NullTag, t2
746 cieq t1, UndefinedTag, t1
747 ori t2, t1
748.opEqNullNotImmediate:
749 storei BooleanTag, TagOffset[cfr, t3, 8]
750 storei t1, PayloadOffset[cfr, t3, 8]
751 dispatch(3)
752
753
754_llint_op_neq:
755 traceExecution()
756 loadi 12[PC], t2
757 loadi 8[PC], t0
758 loadConstantOrVariable(t2, t3, t1)
759 loadConstantOrVariable2Reg(t0, t2, t0)
760 bineq t2, t3, .opNeqSlow
761 bieq t2, CellTag, .opNeqSlow
762 bib t2, LowestTag, .opNeqSlow
763 loadi 4[PC], t2
764 cineq t0, t1, t0
765 storei BooleanTag, TagOffset[cfr, t2, 8]
766 storei t0, PayloadOffset[cfr, t2, 8]
767 dispatch(4)
768
769.opNeqSlow:
770 callHelper(_llint_helper_neq)
771 dispatch(4)
772
773
774_llint_op_neq_null:
775 traceExecution()
776 loadi 8[PC], t0
777 loadi 4[PC], t3
778 assertNotConstant(t0)
779 loadi TagOffset[cfr, t0, 8], t1
780 loadi PayloadOffset[cfr, t0, 8], t0
781 bineq t1, CellTag, .opNeqNullImmediate
782 loadp JSCell::m_structure[t0], t1
783 tbz Structure::m_typeInfo + TypeInfo::m_flags[t1], MasqueradesAsUndefined, t1
784 jmp .opNeqNullNotImmediate
785.opNeqNullImmediate:
786 cineq t1, NullTag, t2
787 cineq t1, UndefinedTag, t1
788 andi t2, t1
789.opNeqNullNotImmediate:
790 storei BooleanTag, TagOffset[cfr, t3, 8]
791 storei t1, PayloadOffset[cfr, t3, 8]
792 dispatch(3)
793
794
795macro strictEq(equalityOperation, helper)
796 loadi 12[PC], t2
797 loadi 8[PC], t0
798 loadConstantOrVariable(t2, t3, t1)
799 loadConstantOrVariable2Reg(t0, t2, t0)
800 bineq t2, t3, .slow
801 bib t2, LowestTag, .slow
802 bineq t2, CellTag, .notString
803 loadp JSCell::m_structure[t0], t2
804 loadp JSCell::m_structure[t1], t3
805 bbneq Structure::m_typeInfo + TypeInfo::m_type[t2], StringType, .notString
806 bbeq Structure::m_typeInfo + TypeInfo::m_type[t3], StringType, .slow
807.notString:
808 loadi 4[PC], t2
809 equalityOperation(t0, t1, t0)
810 storei BooleanTag, TagOffset[cfr, t2, 8]
811 storei t0, PayloadOffset[cfr, t2, 8]
812 dispatch(4)
813
814.slow:
815 callHelper(helper)
816 dispatch(4)
817end
818
819_llint_op_stricteq:
820 traceExecution()
821 strictEq(macro (left, right, result) cieq left, right, result end, _llint_helper_stricteq)
822
823
824_llint_op_nstricteq:
825 traceExecution()
826 strictEq(macro (left, right, result) cineq left, right, result end, _llint_helper_nstricteq)
827
828
829_llint_op_less:
830 traceExecution()
831 callHelper(_llint_helper_less)
832 dispatch(4)
833
834
835_llint_op_lesseq:
836 traceExecution()
837 callHelper(_llint_helper_lesseq)
838 dispatch(4)
839
840
841_llint_op_greater:
842 traceExecution()
843 callHelper(_llint_helper_greater)
844 dispatch(4)
845
846
847_llint_op_greatereq:
848 traceExecution()
849 callHelper(_llint_helper_greatereq)
850 dispatch(4)
851
852
853_llint_op_pre_inc:
854 traceExecution()
855 loadi 4[PC], t0
856 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPreIncSlow
857 loadi PayloadOffset[cfr, t0, 8], t1
858 baddio 1, t1, .opPreIncSlow
859 storei t1, PayloadOffset[cfr, t0, 8]
860 dispatch(2)
861
862.opPreIncSlow:
863 callHelper(_llint_helper_pre_inc)
864 dispatch(2)
865
866
867_llint_op_pre_dec:
868 traceExecution()
869 loadi 4[PC], t0
870 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPreDecSlow
871 loadi PayloadOffset[cfr, t0, 8], t1
872 bsubio 1, t1, .opPreDecSlow
873 storei t1, PayloadOffset[cfr, t0, 8]
874 dispatch(2)
875
876.opPreDecSlow:
877 callHelper(_llint_helper_pre_dec)
878 dispatch(2)
879
880
881_llint_op_post_inc:
882 traceExecution()
883 loadi 8[PC], t0
884 loadi 4[PC], t1
885 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPostIncSlow
886 bieq t0, t1, .opPostIncDone
887 loadi PayloadOffset[cfr, t0, 8], t2
888 move t2, t3
889 baddio 1, t3, .opPostIncSlow
890 storei Int32Tag, TagOffset[cfr, t1, 8]
891 storei t2, PayloadOffset[cfr, t1, 8]
892 storei t3, PayloadOffset[cfr, t0, 8]
893.opPostIncDone:
894 dispatch(3)
895
896.opPostIncSlow:
897 callHelper(_llint_helper_post_inc)
898 dispatch(3)
899
900
901_llint_op_post_dec:
902 traceExecution()
903 loadi 8[PC], t0
904 loadi 4[PC], t1
905 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPostDecSlow
906 bieq t0, t1, .opPostDecDone
907 loadi PayloadOffset[cfr, t0, 8], t2
908 move t2, t3
909 bsubio 1, t3, .opPostDecSlow
910 storei Int32Tag, TagOffset[cfr, t1, 8]
911 storei t2, PayloadOffset[cfr, t1, 8]
912 storei t3, PayloadOffset[cfr, t0, 8]
913.opPostDecDone:
914 dispatch(3)
915
916.opPostDecSlow:
917 callHelper(_llint_helper_post_dec)
918 dispatch(3)
919
920
921_llint_op_to_jsnumber:
922 traceExecution()
923 loadi 8[PC], t0
924 loadi 4[PC], t1
925 loadConstantOrVariable(t0, t2, t3)
926 bieq t2, Int32Tag, .opToJsnumberIsInt
927 biaeq t2, EmptyValueTag, .opToJsnumberSlow
928.opToJsnumberIsInt:
929 storei t2, TagOffset[cfr, t1, 8]
930 storei t3, PayloadOffset[cfr, t1, 8]
931 dispatch(3)
932
933.opToJsnumberSlow:
934 callHelper(_llint_helper_to_jsnumber)
935 dispatch(3)
936
937
938_llint_op_negate:
939 traceExecution()
940 loadi 8[PC], t0
941 loadi 4[PC], t3
942 loadConstantOrVariable(t0, t1, t2)
943 bineq t1, Int32Tag, .opNegateSrcNotInt
944 btiz t2, 0x7fffffff, .opNegateSlow
945 negi t2
946 storei Int32Tag, TagOffset[cfr, t3, 8]
947 storei t2, PayloadOffset[cfr, t3, 8]
948 dispatch(3)
949.opNegateSrcNotInt:
950 bia t1, LowestTag, .opNegateSlow
951 xori 0x80000000, t1
952 storei t1, TagOffset[cfr, t3, 8]
953 storei t2, PayloadOffset[cfr, t3, 8]
954 dispatch(3)
955
956.opNegateSlow:
957 callHelper(_llint_helper_negate)
958 dispatch(3)
959
960
961macro binaryOpCustomStore(integerOperationAndStore, doubleOperation, helper)
962 loadi 12[PC], t2
963 loadi 8[PC], t0
964 loadConstantOrVariable(t2, t3, t1)
965 loadConstantOrVariable2Reg(t0, t2, t0)
966 bineq t2, Int32Tag, .op1NotInt
967 bineq t3, Int32Tag, .op2NotInt
968 loadi 4[PC], t2
969 integerOperationAndStore(t3, t1, t0, .slow, t2)
970 dispatch(5)
971
972.op1NotInt:
973 # First operand is definitely not an int, the second operand could be anything.
974 bia t2, LowestTag, .slow
975 bib t3, LowestTag, .op1NotIntOp2Double
976 bineq t3, Int32Tag, .slow
977 ci2d t1, ft1
978 jmp .op1NotIntReady
979.op1NotIntOp2Double:
980 fii2d t1, t3, ft1
981.op1NotIntReady:
982 loadi 4[PC], t1
983 fii2d t0, t2, ft0
984 doubleOperation(ft1, ft0)
985 stored ft0, [cfr, t1, 8]
986 dispatch(5)
987
988.op2NotInt:
989 # First operand is definitely an int, the second operand is definitely not.
990 loadi 4[PC], t2
991 bia t3, LowestTag, .slow
992 ci2d t0, ft0
993 fii2d t1, t3, ft1
994 doubleOperation(ft1, ft0)
995 stored ft0, [cfr, t2, 8]
996 dispatch(5)
997
998.slow:
999 callHelper(helper)
1000 dispatch(5)
1001end
1002
1003macro binaryOp(integerOperation, doubleOperation, helper)
1004 binaryOpCustomStore(
1005 macro (int32Tag, left, right, slow, index)
1006 integerOperation(left, right, slow)
1007 storei int32Tag, TagOffset[cfr, index, 8]
1008 storei right, PayloadOffset[cfr, index, 8]
1009 end,
1010 doubleOperation, helper)
1011end
1012
1013_llint_op_add:
1014 traceExecution()
1015 binaryOp(
1016 macro (left, right, slow) baddio left, right, slow end,
1017 macro (left, right) addd left, right end,
1018 _llint_helper_add)
1019
1020
1021_llint_op_mul:
1022 traceExecution()
1023 binaryOpCustomStore(
1024 macro (int32Tag, left, right, slow, index)
1025 const scratch = int32Tag # We know that we can reuse the int32Tag register since it has a constant.
1026 move right, scratch
1027 bmulio left, scratch, slow
1028 btinz scratch, .done
1029 bilt left, 0, slow
1030 bilt right, 0, slow
1031 .done:
1032 storei Int32Tag, TagOffset[cfr, index, 8]
1033 storei scratch, PayloadOffset[cfr, index, 8]
1034 end,
1035 macro (left, right) muld left, right end,
1036 _llint_helper_mul)
1037
1038
1039_llint_op_sub:
1040 traceExecution()
1041 binaryOp(
1042 macro (left, right, slow) bsubio left, right, slow end,
1043 macro (left, right) subd left, right end,
1044 _llint_helper_sub)
1045
1046
1047_llint_op_div:
1048 traceExecution()
1049 binaryOpCustomStore(
1050 macro (int32Tag, left, right, slow, index)
1051 ci2d left, ft0
1052 ci2d right, ft1
1053 divd ft0, ft1
1054 bcd2i ft1, right, .notInt
1055 storei int32Tag, TagOffset[cfr, index, 8]
1056 storei right, PayloadOffset[cfr, index, 8]
1057 jmp .done
1058 .notInt:
1059 stored ft1, [cfr, index, 8]
1060 .done:
1061 end,
1062 macro (left, right) divd left, right end,
1063 _llint_helper_div)
1064
1065
1066_llint_op_mod:
1067 traceExecution()
1068 callHelper(_llint_helper_mod)
1069 dispatch(4)
1070
1071
1072macro bitOp(operation, helper, advance)
1073 loadi 12[PC], t2
1074 loadi 8[PC], t0
1075 loadConstantOrVariable(t2, t3, t1)
1076 loadConstantOrVariable2Reg(t0, t2, t0)
1077 bineq t3, Int32Tag, .slow
1078 bineq t2, Int32Tag, .slow
1079 loadi 4[PC], t2
1080 operation(t1, t0, .slow)
1081 storei t3, TagOffset[cfr, t2, 8]
1082 storei t0, PayloadOffset[cfr, t2, 8]
1083 dispatch(advance)
1084
1085.slow:
1086 callHelper(helper)
1087 dispatch(advance)
1088end
1089
1090_llint_op_lshift:
1091 traceExecution()
1092 bitOp(
1093 macro (left, right, slow) lshifti left, right end,
1094 _llint_helper_lshift,
1095 4)
1096
1097
1098_llint_op_rshift:
1099 traceExecution()
1100 bitOp(
1101 macro (left, right, slow) rshifti left, right end,
1102 _llint_helper_rshift,
1103 4)
1104
1105
1106_llint_op_urshift:
1107 traceExecution()
1108 bitOp(
1109 macro (left, right, slow)
1110 urshifti left, right
1111 bilt right, 0, slow
1112 end,
1113 _llint_helper_urshift,
1114 4)
1115
1116
1117_llint_op_bitand:
1118 traceExecution()
1119 bitOp(
1120 macro (left, right, slow) andi left, right end,
1121 _llint_helper_bitand,
1122 5)
1123
1124
1125_llint_op_bitxor:
1126 traceExecution()
1127 bitOp(
1128 macro (left, right, slow) xori left, right end,
1129 _llint_helper_bitxor,
1130 5)
1131
1132
1133_llint_op_bitor:
1134 traceExecution()
1135 bitOp(
1136 macro (left, right, slow) ori left, right end,
1137 _llint_helper_bitor,
1138 5)
1139
1140
1141_llint_op_bitnot:
1142 traceExecution()
1143 loadi 8[PC], t1
1144 loadi 4[PC], t0
1145 loadConstantOrVariable(t1, t2, t3)
1146 bineq t2, Int32Tag, .opBitnotSlow
1147 noti t3
1148 storei t2, TagOffset[cfr, t0, 8]
1149 storei t3, PayloadOffset[cfr, t0, 8]
1150 dispatch(3)
1151
1152.opBitnotSlow:
1153 callHelper(_llint_helper_bitnot)
1154 dispatch(3)
1155
1156
1157_llint_op_check_has_instance:
1158 traceExecution()
1159 loadi 4[PC], t1
1160 loadConstantOrVariablePayload(t1, CellTag, t0, .opCheckHasInstanceSlow)
1161 loadp JSCell::m_structure[t0], t0
1162 btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsHasInstance, .opCheckHasInstanceSlow
1163 dispatch(2)
1164
1165.opCheckHasInstanceSlow:
1166 callHelper(_llint_helper_check_has_instance)
1167 dispatch(2)
1168
1169
1170_llint_op_instanceof:
1171 traceExecution()
1172 # Check that baseVal implements the default HasInstance behavior.
1173 # FIXME: This should be deprecated.
1174 loadi 12[PC], t1
1175 loadConstantOrVariablePayloadUnchecked(t1, t0)
1176 loadp JSCell::m_structure[t0], t0
1177 btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opInstanceofSlow
1178
1179 # Actually do the work.
1180 loadi 16[PC], t0
1181 loadi 4[PC], t3
1182 loadConstantOrVariablePayload(t0, CellTag, t1, .opInstanceofSlow)
1183 loadp JSCell::m_structure[t1], t2
1184 bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opInstanceofSlow
1185 loadi 8[PC], t0
1186 loadConstantOrVariablePayload(t0, CellTag, t2, .opInstanceofSlow)
1187
1188 # Register state: t1 = prototype, t2 = value
1189 move 1, t0
1190.opInstanceofLoop:
1191 loadp JSCell::m_structure[t2], t2
1192 loadi Structure::m_prototype + PayloadOffset[t2], t2
1193 bpeq t2, t1, .opInstanceofDone
1194 btinz t2, .opInstanceofLoop
1195
1196 move 0, t0
1197.opInstanceofDone:
1198 storei BooleanTag, TagOffset[cfr, t3, 8]
1199 storei t0, PayloadOffset[cfr, t3, 8]
1200 dispatch(5)
1201
1202.opInstanceofSlow:
1203 callHelper(_llint_helper_instanceof)
1204 dispatch(5)
1205
1206
1207_llint_op_typeof:
1208 traceExecution()
1209 callHelper(_llint_helper_typeof)
1210 dispatch(3)
1211
1212
1213_llint_op_is_undefined:
1214 traceExecution()
1215 callHelper(_llint_helper_is_undefined)
1216 dispatch(3)
1217
1218
1219_llint_op_is_boolean:
1220 traceExecution()
1221 callHelper(_llint_helper_is_boolean)
1222 dispatch(3)
1223
1224
1225_llint_op_is_number:
1226 traceExecution()
1227 callHelper(_llint_helper_is_number)
1228 dispatch(3)
1229
1230
1231_llint_op_is_string:
1232 traceExecution()
1233 callHelper(_llint_helper_is_string)
1234 dispatch(3)
1235
1236
1237_llint_op_is_object:
1238 traceExecution()
1239 callHelper(_llint_helper_is_object)
1240 dispatch(3)
1241
1242
1243_llint_op_is_function:
1244 traceExecution()
1245 callHelper(_llint_helper_is_function)
1246 dispatch(3)
1247
1248
1249_llint_op_in:
1250 traceExecution()
1251 callHelper(_llint_helper_in)
1252 dispatch(4)
1253
1254
1255_llint_op_resolve:
1256 traceExecution()
1257 callHelper(_llint_helper_resolve)
1258 dispatch(4)
1259
1260
1261_llint_op_resolve_skip:
1262 traceExecution()
1263 callHelper(_llint_helper_resolve_skip)
1264 dispatch(5)
1265
1266
1267macro resolveGlobal(size, slow)
1268 # Operands are as follows:
1269 # 4[PC] Destination for the load.
1270 # 8[PC] Property identifier index in the code block.
1271 # 12[PC] Structure pointer, initialized to 0 by bytecode generator.
1272 # 16[PC] Offset in global object, initialized to 0 by bytecode generator.
1273 loadp CodeBlock[cfr], t0
1274 loadp CodeBlock::m_globalObject[t0], t0
1275 loadp JSCell::m_structure[t0], t1
1276 bpneq t1, 12[PC], slow
1277 loadi 16[PC], t1
1278 loadp JSObject::m_propertyStorage[t0], t0
1279 loadi TagOffset[t0, t1, 8], t2
1280 loadi PayloadOffset[t0, t1, 8], t3
1281 loadi 4[PC], t0
1282 storei t2, TagOffset[cfr, t0, 8]
1283 storei t3, PayloadOffset[cfr, t0, 8]
1284 loadi (size - 1) * 4[PC], t0
1285 valueProfile(t2, t3, t0)
1286end
1287
1288_llint_op_resolve_global:
1289 traceExecution()
1290 resolveGlobal(6, .opResolveGlobalSlow)
1291 dispatch(6)
1292
1293.opResolveGlobalSlow:
1294 callHelper(_llint_helper_resolve_global)
1295 dispatch(6)
1296
1297
1298# Gives you the scope in t0, while allowing you to optionally perform additional checks on the
1299# scopes as they are traversed. scopeCheck() is called with two arguments: the register
1300# holding the scope, and a register that can be used for scratch. Note that this does not
1301# use t3, so you can hold stuff in t3 if need be.
1302macro getScope(deBruijinIndexOperand, scopeCheck)
1303 loadp ScopeChain + PayloadOffset[cfr], t0
1304 loadi deBruijinIndexOperand, t2
1305
1306 btiz t2, .done
1307
1308 loadp CodeBlock[cfr], t1
1309 bineq CodeBlock::m_codeType[t1], FunctionCode, .loop
1310 btbz CodeBlock::m_needsFullScopeChain[t1], .loop
1311
1312 loadi CodeBlock::m_activationRegister[t1], t1
1313
1314 # Need to conditionally skip over one scope.
1315 bieq TagOffset[cfr, t1, 8], EmptyValueTag, .noActivation
1316 scopeCheck(t0, t1)
1317 loadp ScopeChainNode::next[t0], t0
1318.noActivation:
1319 subi 1, t2
1320
1321 btiz t2, .done
1322.loop:
1323 scopeCheck(t0, t1)
1324 loadp ScopeChainNode::next[t0], t0
1325 subi 1, t2
1326 btinz t2, .loop
1327
1328.done:
1329end
1330
1331_llint_op_resolve_global_dynamic:
1332 traceExecution()
1333 loadp JITStackFrame::globalData[sp], t3
1334 loadp JSGlobalData::activationStructure[t3], t3
1335 getScope(
1336 20[PC],
1337 macro (scope, scratch)
1338 loadp ScopeChainNode::object[scope], scratch
1339 bpneq JSCell::m_structure[scratch], t3, .opResolveGlobalDynamicSuperSlow
1340 end)
1341 resolveGlobal(7, .opResolveGlobalDynamicSlow)
1342 dispatch(7)
1343
1344.opResolveGlobalDynamicSuperSlow:
1345 callHelper(_llint_helper_resolve_for_resolve_global_dynamic)
1346 dispatch(7)
1347
1348.opResolveGlobalDynamicSlow:
1349 callHelper(_llint_helper_resolve_global_dynamic)
1350 dispatch(7)
1351
1352
1353_llint_op_get_scoped_var:
1354 traceExecution()
1355 # Operands are as follows:
1356 # 4[PC] Destination for the load.
1357 # 8[PC] Index of register in the scope.
1358 # 12[PC] De Bruijin index.
1359 getScope(12[PC], macro (scope, scratch) end)
1360 loadi 4[PC], t1
1361 loadi 8[PC], t2
1362 loadp ScopeChainNode::object[t0], t0
1363 loadp JSVariableObject::m_registers[t0], t0
1364 loadi TagOffset[t0, t2, 8], t3
1365 loadi PayloadOffset[t0, t2, 8], t0
1366 storei t3, TagOffset[cfr, t1, 8]
1367 storei t0, PayloadOffset[cfr, t1, 8]
1368 loadi 16[PC], t1
1369 valueProfile(t3, t0, t1)
1370 dispatch(5)
1371
1372
1373_llint_op_put_scoped_var:
1374 traceExecution()
1375 getScope(8[PC], macro (scope, scratch) end)
1376 loadi 12[PC], t1
1377 loadConstantOrVariable(t1, t3, t2)
1378 loadi 4[PC], t1
1379 writeBarrier(t3, t2)
1380 loadp ScopeChainNode::object[t0], t0
1381 loadp JSVariableObject::m_registers[t0], t0
1382 storei t3, TagOffset[t0, t1, 8]
1383 storei t2, PayloadOffset[t0, t1, 8]
1384 dispatch(4)
1385
1386
1387_llint_op_get_global_var:
1388 traceExecution()
1389 loadi 8[PC], t1
1390 loadi 4[PC], t3
1391 loadp CodeBlock[cfr], t0
1392 loadp CodeBlock::m_globalObject[t0], t0
1393 loadp JSGlobalObject::m_registers[t0], t0
1394 loadi TagOffset[t0, t1, 8], t2
1395 loadi PayloadOffset[t0, t1, 8], t1
1396 storei t2, TagOffset[cfr, t3, 8]
1397 storei t1, PayloadOffset[cfr, t3, 8]
1398 loadi 12[PC], t3
1399 valueProfile(t2, t1, t3)
1400 dispatch(4)
1401
1402
1403_llint_op_put_global_var:
1404 traceExecution()
1405 loadi 8[PC], t1
1406 loadp CodeBlock[cfr], t0
1407 loadp CodeBlock::m_globalObject[t0], t0
1408 loadp JSGlobalObject::m_registers[t0], t0
1409 loadConstantOrVariable(t1, t2, t3)
1410 loadi 4[PC], t1
1411 writeBarrier(t2, t3)
1412 storei t2, TagOffset[t0, t1, 8]
1413 storei t3, PayloadOffset[t0, t1, 8]
1414 dispatch(3)
1415
1416
1417_llint_op_resolve_base:
1418 traceExecution()
1419 callHelper(_llint_helper_resolve_base)
1420 dispatch(5)
1421
1422
1423_llint_op_ensure_property_exists:
1424 traceExecution()
1425 callHelper(_llint_helper_ensure_property_exists)
1426 dispatch(3)
1427
1428
1429_llint_op_resolve_with_base:
1430 traceExecution()
1431 callHelper(_llint_helper_resolve_with_base)
1432 dispatch(5)
1433
1434
1435_llint_op_resolve_with_this:
1436 traceExecution()
1437 callHelper(_llint_helper_resolve_with_this)
1438 dispatch(5)
1439
1440
1441_llint_op_get_by_id:
1442 traceExecution()
1443 # We only do monomorphic get_by_id caching for now, and we do not modify the
1444 # opcode. We do, however, allow for the cache to change anytime if fails, since
1445 # ping-ponging is free. At best we get lucky and the get_by_id will continue
1446 # to take fast path on the new cache. At worst we take slow path, which is what
1447 # we would have been doing anyway.
1448 loadi 8[PC], t0
1449 loadi 16[PC], t1
1450 loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow)
1451 loadi 20[PC], t2
1452 loadp JSObject::m_propertyStorage[t3], t0
1453 bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
1454 loadi 4[PC], t1
1455 loadi TagOffset[t0, t2], t3
1456 loadi PayloadOffset[t0, t2], t2
1457 storei t3, TagOffset[cfr, t1, 8]
1458 storei t2, PayloadOffset[cfr, t1, 8]
1459 loadi 32[PC], t1
1460 valueProfile(t3, t2, t1)
1461 dispatch(9)
1462
1463.opGetByIdSlow:
1464 callHelper(_llint_helper_get_by_id)
1465 dispatch(9)
1466
1467
1468_llint_op_get_arguments_length:
1469 traceExecution()
1470 loadi 8[PC], t0
1471 loadi 4[PC], t1
1472 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentsLengthSlow
1473 loadi ArgumentCount + PayloadOffset[cfr], t2
1474 subi 1, t2
1475 storei Int32Tag, TagOffset[cfr, t1, 8]
1476 storei t2, PayloadOffset[cfr, t1, 8]
1477 dispatch(4)
1478
1479.opGetArgumentsLengthSlow:
1480 callHelper(_llint_helper_get_arguments_length)
1481 dispatch(4)
1482
1483
1484_llint_op_put_by_id:
1485 traceExecution()
1486 loadi 4[PC], t3
1487 loadi 16[PC], t1
1488 loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1489 loadi 12[PC], t2
1490 loadp JSObject::m_propertyStorage[t0], t3
1491 bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1492 loadi 20[PC], t1
1493 loadConstantOrVariable2Reg(t2, t0, t2)
1494 writeBarrier(t0, t2)
1495 storei t0, TagOffset[t3, t1]
1496 storei t2, PayloadOffset[t3, t1]
1497 dispatch(9)
1498
1499.opPutByIdSlow:
1500 callHelper(_llint_helper_put_by_id)
1501 dispatch(9)
1502
1503
1504macro putByIdTransition(additionalChecks)
1505 traceExecution()
1506 loadi 4[PC], t3
1507 loadi 16[PC], t1
1508 loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1509 loadi 12[PC], t2
1510 bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1511 additionalChecks(t1, t3, .opPutByIdSlow)
1512 loadi 20[PC], t1
1513 loadp JSObject::m_propertyStorage[t0], t3
1514 addp t1, t3
1515 loadConstantOrVariable2Reg(t2, t1, t2)
1516 writeBarrier(t1, t2)
1517 storei t1, TagOffset[t3]
1518 loadi 24[PC], t1
1519 storei t2, PayloadOffset[t3]
1520 storep t1, JSCell::m_structure[t0]
1521 dispatch(9)
1522end
1523
1524_llint_op_put_by_id_transition_direct:
1525 putByIdTransition(macro (oldStructure, scratch, slow) end)
1526
1527
1528_llint_op_put_by_id_transition_normal:
1529 putByIdTransition(
1530 macro (oldStructure, scratch, slow)
1531 const protoCell = oldStructure # Reusing the oldStructure register for the proto
1532
1533 loadp 28[PC], scratch
1534 assert(macro (ok) btpnz scratch, ok end)
1535 loadp StructureChain::m_vector[scratch], scratch
1536 assert(macro (ok) btpnz scratch, ok end)
1537 bieq Structure::m_prototype + TagOffset[oldStructure], NullTag, .done
1538 .loop:
1539 loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell
1540 loadp JSCell::m_structure[protoCell], oldStructure
1541 bpneq oldStructure, [scratch], slow
1542 addp 4, scratch
1543 bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop
1544 .done:
1545 end)
1546
1547
1548_llint_op_del_by_id:
1549 traceExecution()
1550 callHelper(_llint_helper_del_by_id)
1551 dispatch(4)
1552
1553
1554_llint_op_get_by_val:
1555 traceExecution()
1556 loadp CodeBlock[cfr], t1
1557 loadi 8[PC], t2
1558 loadi 12[PC], t3
1559 loadp CodeBlock::m_globalData[t1], t1
1560 loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow)
1561 loadp JSGlobalData::jsArrayClassInfo[t1], t2
1562 loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
1563 bpneq [t0], t2, .opGetByValSlow
1564 loadp JSArray::m_storage[t0], t3
1565 biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow
1566 loadi 4[PC], t0
1567 loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2
1568 loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1
1569 bieq t2, EmptyValueTag, .opGetByValSlow
1570 storei t2, TagOffset[cfr, t0, 8]
1571 storei t1, PayloadOffset[cfr, t0, 8]
1572 loadi 16[PC], t0
1573 valueProfile(t2, t1, t0)
1574 dispatch(5)
1575
1576.opGetByValSlow:
1577 callHelper(_llint_helper_get_by_val)
1578 dispatch(5)
1579
1580
1581_llint_op_get_argument_by_val:
1582 traceExecution()
1583 loadi 8[PC], t0
1584 loadi 12[PC], t1
1585 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentByValSlow
1586 loadConstantOrVariablePayload(t1, Int32Tag, t2, .opGetArgumentByValSlow)
1587 addi 1, t2
1588 loadi ArgumentCount + PayloadOffset[cfr], t1
1589 biaeq t2, t1, .opGetArgumentByValSlow
1590 negi t2
1591 loadi 4[PC], t3
1592 loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0
1593 loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t1
1594 storei t0, TagOffset[cfr, t3, 8]
1595 storei t1, PayloadOffset[cfr, t3, 8]
1596 dispatch(5)
1597
1598.opGetArgumentByValSlow:
1599 callHelper(_llint_helper_get_argument_by_val)
1600 dispatch(5)
1601
1602
1603_llint_op_get_by_pname:
1604 traceExecution()
1605 loadi 12[PC], t0
1606 loadConstantOrVariablePayload(t0, CellTag, t1, .opGetByPnameSlow)
1607 loadi 16[PC], t0
1608 bpneq t1, PayloadOffset[cfr, t0, 8], .opGetByPnameSlow
1609 loadi 8[PC], t0
1610 loadConstantOrVariablePayload(t0, CellTag, t2, .opGetByPnameSlow)
1611 loadi 20[PC], t0
1612 loadi PayloadOffset[cfr, t0, 8], t3
1613 loadp JSCell::m_structure[t2], t0
1614 bpneq t0, JSPropertyNameIterator::m_cachedStructure[t3], .opGetByPnameSlow
1615 loadi 24[PC], t0
1616 loadi [cfr, t0, 8], t0
1617 subi 1, t0
1618 biaeq t0, JSPropertyNameIterator::m_numCacheableSlots[t3], .opGetByPnameSlow
1619 loadp JSObject::m_propertyStorage[t2], t2
1620 loadi TagOffset[t2, t0, 8], t1
1621 loadi PayloadOffset[t2, t0, 8], t3
1622 loadi 4[PC], t0
1623 storei t1, TagOffset[cfr, t0, 8]
1624 storei t3, PayloadOffset[cfr, t0, 8]
1625 dispatch(7)
1626
1627.opGetByPnameSlow:
1628 callHelper(_llint_helper_get_by_pname)
1629 dispatch(7)
1630
1631
1632_llint_op_put_by_val:
1633 traceExecution()
1634 loadi 4[PC], t0
1635 loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
1636 loadi 8[PC], t0
1637 loadConstantOrVariablePayload(t0, Int32Tag, t2, .opPutByValSlow)
1638 loadp CodeBlock[cfr], t0
1639 loadp CodeBlock::m_globalData[t0], t0
1640 loadp JSGlobalData::jsArrayClassInfo[t0], t0
1641 bpneq [t1], t0, .opPutByValSlow
1642 biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow
1643 loadp JSArray::m_storage[t1], t0
1644 bieq ArrayStorage::m_vector + TagOffset[t0, t2, 8], EmptyValueTag, .opPutByValEmpty
1645.opPutByValStoreResult:
1646 loadi 12[PC], t3
1647 loadConstantOrVariable2Reg(t3, t1, t3)
1648 writeBarrier(t1, t3)
1649 storei t1, ArrayStorage::m_vector + TagOffset[t0, t2, 8]
1650 storei t3, ArrayStorage::m_vector + PayloadOffset[t0, t2, 8]
1651 dispatch(4)
1652
1653.opPutByValEmpty:
1654 addi 1, ArrayStorage::m_numValuesInVector[t0]
1655 bib t2, ArrayStorage::m_length[t0], .opPutByValStoreResult
1656 addi 1, t2, t1
1657 storei t1, ArrayStorage::m_length[t0]
1658 jmp .opPutByValStoreResult
1659
1660.opPutByValSlow:
1661 callHelper(_llint_helper_put_by_val)
1662 dispatch(4)
1663
1664
1665_llint_op_del_by_val:
1666 traceExecution()
1667 callHelper(_llint_helper_del_by_val)
1668 dispatch(4)
1669
1670
1671_llint_op_put_by_index:
1672 traceExecution()
1673 callHelper(_llint_helper_put_by_index)
1674 dispatch(4)
1675
1676
1677_llint_op_put_getter_setter:
1678 traceExecution()
1679 callHelper(_llint_helper_put_getter_setter)
1680 dispatch(5)
1681
1682
1683_llint_op_loop:
1684 nop
1685_llint_op_jmp:
1686 traceExecution()
1687 dispatchBranch(4[PC])
1688
1689
1690_llint_op_jmp_scopes:
1691 traceExecution()
1692 callHelper(_llint_helper_jmp_scopes)
1693 dispatch(0)
1694
1695
1696macro jumpTrueOrFalse(conditionOp, slow)
1697 loadi 4[PC], t1
1698 loadConstantOrVariablePayload(t1, BooleanTag, t0, .slow)
1699 conditionOp(t0, .target)
1700 dispatch(3)
1701
1702.target:
1703 dispatchBranch(8[PC])
1704
1705.slow:
1706 callHelper(slow)
1707 dispatch(0)
1708end
1709
1710_llint_op_loop_if_true:
1711 nop
1712_llint_op_jtrue:
1713 traceExecution()
1714 jumpTrueOrFalse(
1715 macro (value, target) btinz value, target end,
1716 _llint_helper_jtrue)
1717
1718
1719_llint_op_loop_if_false:
1720 nop
1721_llint_op_jfalse:
1722 traceExecution()
1723 jumpTrueOrFalse(
1724 macro (value, target) btiz value, target end,
1725 _llint_helper_jfalse)
1726
1727
1728macro equalNull(cellHandler, immediateHandler)
1729 loadi 4[PC], t0
1730 loadi TagOffset[cfr, t0, 8], t1
1731 loadi PayloadOffset[cfr, t0, 8], t0
1732 bineq t1, CellTag, .immediate
1733 loadp JSCell::m_structure[t0], t2
1734 cellHandler(Structure::m_typeInfo + TypeInfo::m_flags[t2], .target)
1735 dispatch(3)
1736
1737.target:
1738 dispatchBranch(8[PC])
1739
1740.immediate:
1741 ori 1, t1
1742 immediateHandler(t1, .target)
1743 dispatch(3)
1744end
1745
1746_llint_op_jeq_null:
1747 traceExecution()
1748 equalNull(
1749 macro (value, target) btbnz value, MasqueradesAsUndefined, target end,
1750 macro (value, target) bieq value, NullTag, target end)
1751
1752
1753_llint_op_jneq_null:
1754 traceExecution()
1755 equalNull(
1756 macro (value, target) btbz value, MasqueradesAsUndefined, target end,
1757 macro (value, target) bineq value, NullTag, target end)
1758
1759
1760_llint_op_jneq_ptr:
1761 traceExecution()
1762 loadi 4[PC], t0
1763 loadi 8[PC], t1
1764 bineq TagOffset[cfr, t0, 8], CellTag, .opJneqPtrBranch
1765 bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough
1766.opJneqPtrBranch:
1767 dispatchBranch(12[PC])
1768.opJneqPtrFallThrough:
1769 dispatch(4)
1770
1771
1772macro compare(integerCompare, doubleCompare, helper)
1773 loadi 4[PC], t2
1774 loadi 8[PC], t3
1775 loadConstantOrVariable(t2, t0, t1)
1776 loadConstantOrVariable2Reg(t3, t2, t3)
1777 bineq t0, Int32Tag, .op1NotInt
1778 bineq t2, Int32Tag, .op2NotInt
1779 integerCompare(t1, t3, .jumpTarget)
1780 dispatch(4)
1781
1782.op1NotInt:
1783 bia t0, LowestTag, .slow
1784 bib t2, LowestTag, .op1NotIntOp2Double
1785 bineq t2, Int32Tag, .slow
1786 ci2d t3, ft1
1787 jmp .op1NotIntReady
1788.op1NotIntOp2Double:
1789 fii2d t3, t2, ft1
1790.op1NotIntReady:
1791 fii2d t1, t0, ft0
1792 doubleCompare(ft0, ft1, .jumpTarget)
1793 dispatch(4)
1794
1795.op2NotInt:
1796 ci2d t1, ft0
1797 bia t2, LowestTag, .slow
1798 fii2d t3, t2, ft1
1799 doubleCompare(ft0, ft1, .jumpTarget)
1800 dispatch(4)
1801
1802.jumpTarget:
1803 dispatchBranch(12[PC])
1804
1805.slow:
1806 callHelper(helper)
1807 dispatch(0)
1808end
1809
1810_llint_op_loop_if_less:
1811 nop
1812_llint_op_jless:
1813 traceExecution()
1814 compare(
1815 macro (left, right, target) bilt left, right, target end,
1816 macro (left, right, target) bdlt left, right, target end,
1817 _llint_helper_jless)
1818
1819
1820_llint_op_jnless:
1821 traceExecution()
1822 compare(
1823 macro (left, right, target) bigteq left, right, target end,
1824 macro (left, right, target) bdgtequn left, right, target end,
1825 _llint_helper_jnless)
1826
1827
1828_llint_op_loop_if_greater:
1829 nop
1830_llint_op_jgreater:
1831 traceExecution()
1832 compare(
1833 macro (left, right, target) bigt left, right, target end,
1834 macro (left, right, target) bdgt left, right, target end,
1835 _llint_helper_jgreater)
1836
1837
1838_llint_op_jngreater:
1839 traceExecution()
1840 compare(
1841 macro (left, right, target) bilteq left, right, target end,
1842 macro (left, right, target) bdltequn left, right, target end,
1843 _llint_helper_jngreater)
1844
1845
1846_llint_op_loop_if_lesseq:
1847 nop
1848_llint_op_jlesseq:
1849 traceExecution()
1850 compare(
1851 macro (left, right, target) bilteq left, right, target end,
1852 macro (left, right, target) bdlteq left, right, target end,
1853 _llint_helper_jlesseq)
1854
1855
1856_llint_op_jnlesseq:
1857 traceExecution()
1858 compare(
1859 macro (left, right, target) bigt left, right, target end,
1860 macro (left, right, target) bdgtun left, right, target end,
1861 _llint_helper_jnlesseq)
1862
1863
1864_llint_op_loop_if_greatereq:
1865 nop
1866_llint_op_jgreatereq:
1867 traceExecution()
1868 compare(
1869 macro (left, right, target) bigteq left, right, target end,
1870 macro (left, right, target) bdgteq left, right, target end,
1871 _llint_helper_jgreatereq)
1872
1873
1874_llint_op_jngreatereq:
1875 traceExecution()
1876 compare(
1877 macro (left, right, target) bilt left, right, target end,
1878 macro (left, right, target) bdltun left, right, target end,
1879 _llint_helper_jngreatereq)
1880
1881
1882_llint_op_loop_hint:
1883 traceExecution()
1884 checkSwitchToJITForLoop()
1885 dispatch(1)
1886
1887
1888_llint_op_switch_imm:
1889 traceExecution()
1890 loadi 12[PC], t2
1891 loadi 4[PC], t3
1892 loadConstantOrVariable(t2, t1, t0)
1893 loadp CodeBlock[cfr], t2
1894 loadp CodeBlock::m_rareData[t2], t2
1895 muli sizeof SimpleJumpTable, t3 # FIXME: would be nice to peephole this!
1896 loadp CodeBlock::RareData::m_immediateSwitchJumpTables + VectorBufferOffset[t2], t2
1897 addp t3, t2
1898 bineq t1, Int32Tag, .opSwitchImmNotInt
1899 subi SimpleJumpTable::min[t2], t0
1900 biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchImmFallThrough
1901 loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t3
1902 loadi [t3, t0, 4], t1
1903 btiz t1, .opSwitchImmFallThrough
1904 dispatchBranchWithOffset(t1)
1905
1906.opSwitchImmNotInt:
1907 bib t1, LowestTag, .opSwitchImmSlow # Go to slow path if it's a double.
1908.opSwitchImmFallThrough:
1909 dispatchBranch(8[PC])
1910
1911.opSwitchImmSlow:
1912 callHelper(_llint_helper_switch_imm)
1913 dispatch(0)
1914
1915
1916_llint_op_switch_char:
1917 traceExecution()
1918 loadi 12[PC], t2
1919 loadi 4[PC], t3
1920 loadConstantOrVariable(t2, t1, t0)
1921 loadp CodeBlock[cfr], t2
1922 loadp CodeBlock::m_rareData[t2], t2
1923 muli sizeof SimpleJumpTable, t3
1924 loadp CodeBlock::RareData::m_characterSwitchJumpTables + VectorBufferOffset[t2], t2
1925 addp t3, t2
1926 bineq t1, CellTag, .opSwitchCharFallThrough
1927 loadp JSCell::m_structure[t0], t1
1928 bbneq Structure::m_typeInfo + TypeInfo::m_type[t1], StringType, .opSwitchCharFallThrough
1929 loadp JSString::m_value[t0], t0
1930 bineq StringImpl::m_length[t0], 1, .opSwitchCharFallThrough
1931 loadp StringImpl::m_data8[t0], t1
1932 btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
1933 loadh [t1], t0
1934 jmp .opSwitchCharReady
1935.opSwitchChar8Bit:
1936 loadb [t1], t0
1937.opSwitchCharReady:
1938 subi SimpleJumpTable::min[t2], t0
1939 biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchCharFallThrough
1940 loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t2
1941 loadi [t2, t0, 4], t1
1942 btiz t1, .opSwitchImmFallThrough
1943 dispatchBranchWithOffset(t1)
1944
1945.opSwitchCharFallThrough:
1946 dispatchBranch(8[PC])
1947
1948
1949_llint_op_switch_string:
1950 traceExecution()
1951 callHelper(_llint_helper_switch_string)
1952 dispatch(0)
1953
1954
1955_llint_op_new_func:
1956 traceExecution()
1957 btiz 12[PC], .opNewFuncUnchecked
1958 loadi 4[PC], t1
1959 bineq TagOffset[cfr, t1, 8], EmptyValueTag, .opNewFuncDone
1960.opNewFuncUnchecked:
1961 callHelper(_llint_helper_new_func)
1962.opNewFuncDone:
1963 dispatch(4)
1964
1965
1966_llint_op_new_func_exp:
1967 traceExecution()
1968 callHelper(_llint_helper_new_func_exp)
1969 dispatch(3)
1970
1971
1972macro doCall(helper)
1973 loadi 4[PC], t0
1974 loadi 16[PC], t1
1975 loadp LLIntCallLinkInfo::callee[t1], t2
1976 loadConstantOrVariablePayload(t0, CellTag, t3, .opCallSlow)
1977 bineq t3, t2, .opCallSlow
1978 loadi 12[PC], t3
1979 addp 24, PC
1980 lshifti 3, t3
1981 addp cfr, t3 # t3 contains the new value of cfr
1982 loadp JSFunction::m_scopeChain[t2], t0
1983 storei t2, Callee + PayloadOffset[t3]
1984 storei t0, ScopeChain + PayloadOffset[t3]
1985 loadi 8 - 24[PC], t2
1986 storei PC, ArgumentCount + TagOffset[cfr]
1987 storep cfr, CallerFrame[t3]
1988 storei t2, ArgumentCount + PayloadOffset[t3]
1989 storei CellTag, Callee + TagOffset[t3]
1990 storei CellTag, ScopeChain + TagOffset[t3]
1991 move t3, cfr
1992 call LLIntCallLinkInfo::machineCodeTarget[t1]
1993 dispatchAfterCall()
1994
1995.opCallSlow:
1996 slowPathForCall(6, helper)
1997end
1998
1999_llint_op_call:
2000 traceExecution()
2001 doCall(_llint_helper_call)
2002
2003
2004_llint_op_construct:
2005 traceExecution()
2006 doCall(_llint_helper_construct)
2007
2008
2009_llint_op_call_varargs:
2010 traceExecution()
2011 slowPathForCall(6, _llint_helper_call_varargs)
2012
2013
2014_llint_op_call_eval:
2015 traceExecution()
2016
2017 # Eval is executed in one of two modes:
2018 #
2019 # 1) We find that we're really invoking eval() in which case the
2020 # execution is perfomed entirely inside the helper, and it
2021 # returns the PC of a function that just returns the return value
2022 # that the eval returned.
2023 #
2024 # 2) We find that we're invoking something called eval() that is not
2025 # the real eval. Then the helper returns the PC of the thing to
2026 # call, and we call it.
2027 #
2028 # This allows us to handle two cases, which would require a total of
2029 # up to four pieces of state that cannot be easily packed into two
2030 # registers (C functions can return up to two registers, easily):
2031 #
2032 # - The call frame register. This may or may not have been modified
2033 # by the helper, but the convention is that it returns it. It's not
2034 # totally clear if that's necessary, since the cfr is callee save.
2035 # But that's our style in this here interpreter so we stick with it.
2036 #
2037 # - A bit to say if the helper successfully executed the eval and has
2038 # the return value, or did not execute the eval but has a PC for us
2039 # to call.
2040 #
2041 # - Either:
2042 # - The JS return value (two registers), or
2043 #
2044 # - The PC to call.
2045 #
2046 # It turns out to be easier to just always have this return the cfr
2047 # and a PC to call, and that PC may be a dummy thunk that just
2048 # returns the JS value that the eval returned.
2049
2050 slowPathForCall(4, _llint_helper_call_eval)
2051
2052
2053_llint_generic_return_point:
2054 dispatchAfterCall()
2055
2056
2057_llint_op_tear_off_activation:
2058 traceExecution()
2059 loadi 4[PC], t0
2060 loadi 8[PC], t1
2061 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffActivationCreated
2062 bieq TagOffset[cfr, t1, 8], EmptyValueTag, .opTearOffActivationNotCreated
2063.opTearOffActivationCreated:
2064 callHelper(_llint_helper_tear_off_activation)
2065.opTearOffActivationNotCreated:
2066 dispatch(3)
2067
2068
2069_llint_op_tear_off_arguments:
2070 traceExecution()
2071 loadi 4[PC], t0
2072 subi 1, t0 # Get the unmodifiedArgumentsRegister
2073 bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffArgumentsNotCreated
2074 callHelper(_llint_helper_tear_off_arguments)
2075.opTearOffArgumentsNotCreated:
2076 dispatch(2)
2077
2078
2079macro doReturn()
2080 loadp ReturnPC[cfr], t2
2081 loadp CallerFrame[cfr], cfr
2082 restoreReturnAddressBeforeReturn(t2)
2083 ret
2084end
2085
2086_llint_op_ret:
2087 traceExecution()
2088 checkSwitchToJITForEpilogue()
2089 loadi 4[PC], t2
2090 loadConstantOrVariable(t2, t1, t0)
2091 doReturn()
2092
2093
2094_llint_op_call_put_result:
2095 loadi 4[PC], t2
2096 loadi 8[PC], t3
2097 storei t1, TagOffset[cfr, t2, 8]
2098 storei t0, PayloadOffset[cfr, t2, 8]
2099 valueProfile(t1, t0, t3)
2100 traceExecution() # Needs to be here because it would clobber t1, t0
2101 dispatch(3)
2102
2103
2104_llint_op_ret_object_or_this:
2105 traceExecution()
2106 checkSwitchToJITForEpilogue()
2107 loadi 4[PC], t2
2108 loadConstantOrVariable(t2, t1, t0)
2109 bineq t1, CellTag, .opRetObjectOrThisNotObject
2110 loadp JSCell::m_structure[t0], t2
2111 bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opRetObjectOrThisNotObject
2112 doReturn()
2113
2114.opRetObjectOrThisNotObject:
2115 loadi 8[PC], t2
2116 loadConstantOrVariable(t2, t1, t0)
2117 doReturn()
2118
2119
2120_llint_op_method_check:
2121 traceExecution()
2122 # We ignore method checks and use normal get_by_id optimizations.
2123 dispatch(1)
2124
2125
2126_llint_op_strcat:
2127 traceExecution()
2128 callHelper(_llint_helper_strcat)
2129 dispatch(4)
2130
2131
2132_llint_op_to_primitive:
2133 traceExecution()
2134 loadi 8[PC], t2
2135 loadi 4[PC], t3
2136 loadConstantOrVariable(t2, t1, t0)
2137 bineq t1, CellTag, .opToPrimitiveIsImm
2138 loadp JSCell::m_structure[t0], t2
2139 bbneq Structure::m_typeInfo + TypeInfo::m_type[t2], StringType, .opToPrimitiveSlowCase
2140.opToPrimitiveIsImm:
2141 storei t1, TagOffset[cfr, t3, 8]
2142 storei t0, PayloadOffset[cfr, t3, 8]
2143 dispatch(3)
2144
2145.opToPrimitiveSlowCase:
2146 callHelper(_llint_helper_to_primitive)
2147 dispatch(3)
2148
2149
2150_llint_op_get_pnames:
2151 traceExecution()
2152 callHelper(_llint_helper_get_pnames)
2153 dispatch(0) # The helper either advances the PC or jumps us to somewhere else.
2154
2155
2156_llint_op_next_pname:
2157 traceExecution()
2158 loadi 12[PC], t1
2159 loadi 16[PC], t2
2160 loadi PayloadOffset[cfr, t1, 8], t0
2161 bieq t0, PayloadOffset[cfr, t2, 8], .opNextPnameEnd
2162 loadi 20[PC], t2
2163 loadi PayloadOffset[cfr, t2, 8], t2
2164 loadp JSPropertyNameIterator::m_jsStrings[t2], t3
2165 loadi [t3, t0, 8], t3
2166 addi 1, t0
2167 storei t0, PayloadOffset[cfr, t1, 8]
2168 loadi 4[PC], t1
2169 storei CellTag, TagOffset[cfr, t1, 8]
2170 storei t3, PayloadOffset[cfr, t1, 8]
2171 loadi 8[PC], t3
2172 loadi PayloadOffset[cfr, t3, 8], t3
2173 loadp JSCell::m_structure[t3], t1
2174 bpneq t1, JSPropertyNameIterator::m_cachedStructure[t2], .opNextPnameSlow
2175 loadp JSPropertyNameIterator::m_cachedPrototypeChain[t2], t0
2176 loadp StructureChain::m_vector[t0], t0
2177 btpz [t0], .opNextPnameTarget
2178.opNextPnameCheckPrototypeLoop:
2179 bieq Structure::m_prototype + TagOffset[t1], NullTag, .opNextPnameSlow
2180 loadp Structure::m_prototype + PayloadOffset[t1], t2
2181 loadp JSCell::m_structure[t2], t1
2182 bpneq t1, [t0], .opNextPnameSlow
2183 addp 4, t0
2184 btpnz [t0], .opNextPnameCheckPrototypeLoop
2185.opNextPnameTarget:
2186 dispatchBranch(24[PC])
2187
2188.opNextPnameEnd:
2189 dispatch(7)
2190
2191.opNextPnameSlow:
2192 callHelper(_llint_helper_next_pname) # This either keeps the PC where it was (causing us to loop) or sets it to target.
2193 dispatch(0)
2194
2195
2196_llint_op_push_scope:
2197 traceExecution()
2198 callHelper(_llint_helper_push_scope)
2199 dispatch(2)
2200
2201
2202_llint_op_pop_scope:
2203 traceExecution()
2204 callHelper(_llint_helper_pop_scope)
2205 dispatch(1)
2206
2207
2208_llint_op_push_new_scope:
2209 traceExecution()
2210 callHelper(_llint_helper_push_new_scope)
2211 dispatch(4)
2212
2213
2214_llint_op_catch:
2215 # This is where we end up from the JIT's throw trampoline (because the
2216 # machine code return address will be set to _llint_op_catch), and from
2217 # the interpreter's throw trampoline (see _llint_throw_trampoline).
2218 # The JIT throwing protocol calls for the cfr to be in t0. The throwing
2219 # code must have known that we were throwing to the interpreter, and have
2220 # set JSGlobalData::targetInterpreterPCForThrow.
2221 move t0, cfr
2222 loadp JITStackFrame::globalData[sp], t3
2223 loadi JSGlobalData::targetInterpreterPCForThrow[t3], PC
2224 loadi JSGlobalData::exception + PayloadOffset[t3], t0
2225 loadi JSGlobalData::exception + TagOffset[t3], t1
2226 storei 0, JSGlobalData::exception + PayloadOffset[t3]
2227 storei EmptyValueTag, JSGlobalData::exception + TagOffset[t3]
2228 loadi 4[PC], t2
2229 storei t0, PayloadOffset[cfr, t2, 8]
2230 storei t1, TagOffset[cfr, t2, 8]
2231 traceExecution() # This needs to be here because we don't want to clobber t0, t1, t2, t3 above.
2232 dispatch(2)
2233
2234
2235_llint_op_throw:
2236 traceExecution()
2237 callHelper(_llint_helper_throw)
2238 dispatch(2)
2239
2240
2241_llint_op_throw_reference_error:
2242 traceExecution()
2243 callHelper(_llint_helper_throw_reference_error)
2244 dispatch(2)
2245
2246
2247_llint_op_jsr:
2248 traceExecution()
2249 loadi 4[PC], t0
2250 addi 3 * 4, PC, t1
2251 storei t1, [cfr, t0, 8]
2252 dispatchBranch(8[PC])
2253
2254
2255_llint_op_sret:
2256 traceExecution()
2257 loadi 4[PC], t0
2258 loadp [cfr, t0, 8], PC
2259 dispatch(0)
2260
2261
2262_llint_op_debug:
2263 traceExecution()
2264 callHelper(_llint_helper_debug)
2265 dispatch(4)
2266
2267
2268_llint_op_profile_will_call:
2269 traceExecution()
2270 loadp JITStackFrame::enabledProfilerReference[sp], t0
2271 btpz [t0], .opProfileWillCallDone
2272 callHelper(_llint_helper_profile_will_call)
2273.opProfileWillCallDone:
2274 dispatch(2)
2275
2276
2277_llint_op_profile_did_call:
2278 traceExecution()
2279 loadp JITStackFrame::enabledProfilerReference[sp], t0
2280 btpz [t0], .opProfileWillCallDone
2281 callHelper(_llint_helper_profile_did_call)
2282.opProfileDidCallDone:
2283 dispatch(2)
2284
2285
2286_llint_op_end:
2287 traceExecution()
2288 checkSwitchToJITForEpilogue()
2289 loadi 4[PC], t0
2290 loadi TagOffset[cfr, t0, 8], t1
2291 loadi PayloadOffset[cfr, t0, 8], t0
2292 doReturn()
2293
2294
2295_llint_throw_from_helper_trampoline:
2296 # When throwing from the interpreter (i.e. throwing from LLIntHelpers), so
2297 # the throw target is not necessarily interpreted code, we come to here.
2298 # This essentially emulates the JIT's throwing protocol.
2299 loadp JITStackFrame::globalData[sp], t1
2300 loadp JSGlobalData::callFrameForThrow[t1], t0
2301 jmp JSGlobalData::targetMachinePCForThrow[t1]
2302
2303
2304_llint_throw_during_call_trampoline:
2305 preserveReturnAddressAfterCall(t2)
2306 loadp JITStackFrame::globalData[sp], t1
2307 loadp JSGlobalData::callFrameForThrow[t1], t0
2308 jmp JSGlobalData::targetMachinePCForThrow[t1]
2309
2310
2311# Lastly, make sure that we can link even though we don't support all opcodes.
2312# These opcodes should never arise when using LLInt or either JIT. We assert
2313# as much.
2314
2315macro notSupported()
2316 if ASSERT_ENABLED
2317 crash()
2318 else
2319 # We should use whatever the smallest possible instruction is, just to
2320 # ensure that there is a gap between instruction labels. If multiple
2321 # smallest instructions exist, we should pick the one that is most
2322 # likely result in execution being halted. Currently that is the break
2323 # instruction on all architectures we're interested in. (Break is int3
2324 # on Intel, which is 1 byte, and bkpt on ARMv7, which is 2 bytes.)
2325 break
2326 end
2327end
2328
2329_llint_op_get_array_length:
2330 notSupported()
2331
2332_llint_op_get_by_id_chain:
2333 notSupported()
2334
2335_llint_op_get_by_id_custom_chain:
2336 notSupported()
2337
2338_llint_op_get_by_id_custom_proto:
2339 notSupported()
2340
2341_llint_op_get_by_id_custom_self:
2342 notSupported()
2343
2344_llint_op_get_by_id_generic:
2345 notSupported()
2346
2347_llint_op_get_by_id_getter_chain:
2348 notSupported()
2349
2350_llint_op_get_by_id_getter_proto:
2351 notSupported()
2352
2353_llint_op_get_by_id_getter_self:
2354 notSupported()
2355
2356_llint_op_get_by_id_proto:
2357 notSupported()
2358
2359_llint_op_get_by_id_self:
2360 notSupported()
2361
2362_llint_op_get_string_length:
2363 notSupported()
2364
2365_llint_op_put_by_id_generic:
2366 notSupported()
2367
2368_llint_op_put_by_id_replace:
2369 notSupported()
2370
2371_llint_op_put_by_id_transition:
2372 notSupported()
2373
2374
2375# Indicate the end of LLInt.
2376_llint_end:
2377 crash()
2378