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 const offsetOfMySizeClass = JSGlobalData::heap + Heap::m_objectSpace + MarkedSpace::m_preciseSizeClasses + sizeClassIndex * sizeof MarkedSpace::SizeClass
583
584 # FIXME: we can get the global data in one load from the stack.
585 loadp CodeBlock[cfr], scratch1
586 loadp CodeBlock::m_globalData[scratch1], scratch1
587
588 # Get the object from the free list.
589 loadp offsetOfMySizeClass + MarkedSpace::SizeClass::firstFreeCell[scratch1], result
590 btpz result, slowCase
591
592 # Remove the object from the free list.
593 loadp [result], scratch2
594 storep scratch2, offsetOfMySizeClass + MarkedSpace::SizeClass::firstFreeCell[scratch1]
595
596 # Initialize the object.
597 loadp classInfoOffset[scratch1], scratch2
598 storep scratch2, [result]
599 storep structure, JSCell::m_structure[result]
600 storep 0, JSObject::m_inheritorID[result]
601 addp sizeof JSObject, result, scratch1
602 storep scratch1, JSObject::m_propertyStorage[result]
603end
604
605_llint_op_create_this:
606 traceExecution()
607 loadi 8[PC], t0
608 assertNotConstant(t0)
609 bineq TagOffset[cfr, t0, 8], CellTag, .opCreateThisSlow
610 loadi PayloadOffset[cfr, t0, 8], t0
611 loadp JSCell::m_structure[t0], t1
612 bbb Structure::m_typeInfo + TypeInfo::m_type[t1], ObjectType, .opCreateThisSlow
613 loadp JSObject::m_inheritorID[t0], t2
614 btpz t2, .opCreateThisSlow
615 allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t2, t0, t1, t3, .opCreateThisSlow)
616 loadi 4[PC], t1
617 storei CellTag, TagOffset[cfr, t1, 8]
618 storei t0, PayloadOffset[cfr, t1, 8]
619 dispatch(3)
620
621.opCreateThisSlow:
622 callHelper(_llint_helper_create_this)
623 dispatch(3)
624
625
626_llint_op_get_callee:
627 traceExecution()
628 loadi 4[PC], t0
629 loadp PayloadOffset + Callee[cfr], t1
630 storei CellTag, TagOffset[cfr, t0, 8]
631 storei t1, PayloadOffset[cfr, t0, 8]
632 dispatch(2)
633
634
635_llint_op_convert_this:
636 traceExecution()
637 loadi 4[PC], t0
638 bineq TagOffset[cfr, t0, 8], CellTag, .opConvertThisSlow
639 loadi PayloadOffset[cfr, t0, 8], t0
640 loadp JSCell::m_structure[t0], t0
641 bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow
642 dispatch(2)
643
644.opConvertThisSlow:
645 callHelper(_llint_helper_convert_this)
646 dispatch(2)
647
648
649_llint_op_new_object:
650 traceExecution()
651 loadp CodeBlock[cfr], t0
652 loadp CodeBlock::m_globalObject[t0], t0
653 loadp JSGlobalObject::m_emptyObjectStructure[t0], t1
654 allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t1, t0, t2, t3, .opNewObjectSlow)
655 loadi 4[PC], t1
656 storei CellTag, TagOffset[cfr, t1, 8]
657 storei t0, PayloadOffset[cfr, t1, 8]
658 dispatch(2)
659
660.opNewObjectSlow:
661 callHelper(_llint_helper_new_object)
662 dispatch(2)
663
664
665_llint_op_new_array:
666 traceExecution()
667 callHelper(_llint_helper_new_array)
668 dispatch(4)
669
670
671_llint_op_new_array_buffer:
672 traceExecution()
673 callHelper(_llint_helper_new_array_buffer)
674 dispatch(4)
675
676
677_llint_op_new_regexp:
678 traceExecution()
679 callHelper(_llint_helper_new_regexp)
680 dispatch(3)
681
682
683_llint_op_mov:
684 traceExecution()
685 loadi 8[PC], t1
686 loadi 4[PC], t0
687 loadConstantOrVariable(t1, t2, t3)
688 storei t2, TagOffset[cfr, t0, 8]
689 storei t3, PayloadOffset[cfr, t0, 8]
690 dispatch(3)
691
692
693_llint_op_not:
694 traceExecution()
695 loadi 8[PC], t0
696 loadi 4[PC], t1
697 loadConstantOrVariable(t0, t2, t3)
698 bineq t2, BooleanTag, .opNotSlow
699 xori 1, t3
700 storei t2, TagOffset[cfr, t1, 8]
701 storei t3, PayloadOffset[cfr, t1, 8]
702 dispatch(3)
703
704.opNotSlow:
705 callHelper(_llint_helper_not)
706 dispatch(3)
707
708
709_llint_op_eq:
710 traceExecution()
711 loadi 12[PC], t2
712 loadi 8[PC], t0
713 loadConstantOrVariable(t2, t3, t1)
714 loadConstantOrVariable2Reg(t0, t2, t0)
715 bineq t2, t3, .opEqSlow
716 bieq t2, CellTag, .opEqSlow
717 bib t2, LowestTag, .opEqSlow
718 loadi 4[PC], t2
719 cieq t0, t1, t0
720 storei BooleanTag, TagOffset[cfr, t2, 8]
721 storei t0, PayloadOffset[cfr, t2, 8]
722 dispatch(4)
723
724.opEqSlow:
725 callHelper(_llint_helper_eq)
726 dispatch(4)
727
728
729_llint_op_eq_null:
730 traceExecution()
731 loadi 8[PC], t0
732 loadi 4[PC], t3
733 assertNotConstant(t0)
734 loadi TagOffset[cfr, t0, 8], t1
735 loadi PayloadOffset[cfr, t0, 8], t0
736 bineq t1, CellTag, .opEqNullImmediate
737 loadp JSCell::m_structure[t0], t1
738 tbnz Structure::m_typeInfo + TypeInfo::m_flags[t1], MasqueradesAsUndefined, t1
739 jmp .opEqNullNotImmediate
740.opEqNullImmediate:
741 cieq t1, NullTag, t2
742 cieq t1, UndefinedTag, t1
743 ori t2, t1
744.opEqNullNotImmediate:
745 storei BooleanTag, TagOffset[cfr, t3, 8]
746 storei t1, PayloadOffset[cfr, t3, 8]
747 dispatch(3)
748
749
750_llint_op_neq:
751 traceExecution()
752 loadi 12[PC], t2
753 loadi 8[PC], t0
754 loadConstantOrVariable(t2, t3, t1)
755 loadConstantOrVariable2Reg(t0, t2, t0)
756 bineq t2, t3, .opNeqSlow
757 bieq t2, CellTag, .opNeqSlow
758 bib t2, LowestTag, .opNeqSlow
759 loadi 4[PC], t2
760 cineq t0, t1, t0
761 storei BooleanTag, TagOffset[cfr, t2, 8]
762 storei t0, PayloadOffset[cfr, t2, 8]
763 dispatch(4)
764
765.opNeqSlow:
766 callHelper(_llint_helper_neq)
767 dispatch(4)
768
769
770_llint_op_neq_null:
771 traceExecution()
772 loadi 8[PC], t0
773 loadi 4[PC], t3
774 assertNotConstant(t0)
775 loadi TagOffset[cfr, t0, 8], t1
776 loadi PayloadOffset[cfr, t0, 8], t0
777 bineq t1, CellTag, .opNeqNullImmediate
778 loadp JSCell::m_structure[t0], t1
779 tbz Structure::m_typeInfo + TypeInfo::m_flags[t1], MasqueradesAsUndefined, t1
780 jmp .opNeqNullNotImmediate
781.opNeqNullImmediate:
782 cineq t1, NullTag, t2
783 cineq t1, UndefinedTag, t1
784 andi t2, t1
785.opNeqNullNotImmediate:
786 storei BooleanTag, TagOffset[cfr, t3, 8]
787 storei t1, PayloadOffset[cfr, t3, 8]
788 dispatch(3)
789
790
791macro strictEq(equalityOperation, helper)
792 loadi 12[PC], t2
793 loadi 8[PC], t0
794 loadConstantOrVariable(t2, t3, t1)
795 loadConstantOrVariable2Reg(t0, t2, t0)
796 bineq t2, t3, .slow
797 bib t2, LowestTag, .slow
798 bineq t2, CellTag, .notString
799 loadp JSCell::m_structure[t0], t2
800 loadp JSCell::m_structure[t1], t3
801 bbneq Structure::m_typeInfo + TypeInfo::m_type[t2], StringType, .notString
802 bbeq Structure::m_typeInfo + TypeInfo::m_type[t3], StringType, .slow
803.notString:
804 loadi 4[PC], t2
805 equalityOperation(t0, t1, t0)
806 storei BooleanTag, TagOffset[cfr, t2, 8]
807 storei t0, PayloadOffset[cfr, t2, 8]
808 dispatch(4)
809
810.slow:
811 callHelper(helper)
812 dispatch(4)
813end
814
815_llint_op_stricteq:
816 traceExecution()
817 strictEq(macro (left, right, result) cieq left, right, result end, _llint_helper_stricteq)
818
819
820_llint_op_nstricteq:
821 traceExecution()
822 strictEq(macro (left, right, result) cineq left, right, result end, _llint_helper_nstricteq)
823
824
825_llint_op_less:
826 traceExecution()
827 callHelper(_llint_helper_less)
828 dispatch(4)
829
830
831_llint_op_lesseq:
832 traceExecution()
833 callHelper(_llint_helper_lesseq)
834 dispatch(4)
835
836
837_llint_op_greater:
838 traceExecution()
839 callHelper(_llint_helper_greater)
840 dispatch(4)
841
842
843_llint_op_greatereq:
844 traceExecution()
845 callHelper(_llint_helper_greatereq)
846 dispatch(4)
847
848
849_llint_op_pre_inc:
850 traceExecution()
851 loadi 4[PC], t0
852 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPreIncSlow
853 loadi PayloadOffset[cfr, t0, 8], t1
854 baddio 1, t1, .opPreIncSlow
855 storei t1, PayloadOffset[cfr, t0, 8]
856 dispatch(2)
857
858.opPreIncSlow:
859 callHelper(_llint_helper_pre_inc)
860 dispatch(2)
861
862
863_llint_op_pre_dec:
864 traceExecution()
865 loadi 4[PC], t0
866 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPreDecSlow
867 loadi PayloadOffset[cfr, t0, 8], t1
868 bsubio 1, t1, .opPreDecSlow
869 storei t1, PayloadOffset[cfr, t0, 8]
870 dispatch(2)
871
872.opPreDecSlow:
873 callHelper(_llint_helper_pre_dec)
874 dispatch(2)
875
876
877_llint_op_post_inc:
878 traceExecution()
879 loadi 8[PC], t0
880 loadi 4[PC], t1
881 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPostIncSlow
882 bieq t0, t1, .opPostIncDone
883 loadi PayloadOffset[cfr, t0, 8], t2
884 move t2, t3
885 baddio 1, t3, .opPostIncSlow
886 storei Int32Tag, TagOffset[cfr, t1, 8]
887 storei t2, PayloadOffset[cfr, t1, 8]
888 storei t3, PayloadOffset[cfr, t0, 8]
889.opPostIncDone:
890 dispatch(3)
891
892.opPostIncSlow:
893 callHelper(_llint_helper_post_inc)
894 dispatch(3)
895
896
897_llint_op_post_dec:
898 traceExecution()
899 loadi 8[PC], t0
900 loadi 4[PC], t1
901 bineq TagOffset[cfr, t0, 8], Int32Tag, .opPostDecSlow
902 bieq t0, t1, .opPostDecDone
903 loadi PayloadOffset[cfr, t0, 8], t2
904 move t2, t3
905 bsubio 1, t3, .opPostDecSlow
906 storei Int32Tag, TagOffset[cfr, t1, 8]
907 storei t2, PayloadOffset[cfr, t1, 8]
908 storei t3, PayloadOffset[cfr, t0, 8]
909.opPostDecDone:
910 dispatch(3)
911
912.opPostDecSlow:
913 callHelper(_llint_helper_post_dec)
914 dispatch(3)
915
916
917_llint_op_to_jsnumber:
918 traceExecution()
919 loadi 8[PC], t0
920 loadi 4[PC], t1
921 loadConstantOrVariable(t0, t2, t3)
922 bieq t2, Int32Tag, .opToJsnumberIsInt
923 biaeq t2, EmptyValueTag, .opToJsnumberSlow
924.opToJsnumberIsInt:
925 storei t2, TagOffset[cfr, t1, 8]
926 storei t3, PayloadOffset[cfr, t1, 8]
927 dispatch(3)
928
929.opToJsnumberSlow:
930 callHelper(_llint_helper_to_jsnumber)
931 dispatch(3)
932
933
934_llint_op_negate:
935 traceExecution()
936 loadi 8[PC], t0
937 loadi 4[PC], t3
938 loadConstantOrVariable(t0, t1, t2)
939 bineq t1, Int32Tag, .opNegateSrcNotInt
940 btiz t2, 0x7fffffff, .opNegateSlow
941 negi t2
942 storei Int32Tag, TagOffset[cfr, t3, 8]
943 storei t2, PayloadOffset[cfr, t3, 8]
944 dispatch(3)
945.opNegateSrcNotInt:
946 bia t1, LowestTag, .opNegateSlow
947 xori 0x80000000, t1
948 storei t1, TagOffset[cfr, t3, 8]
949 storei t2, PayloadOffset[cfr, t3, 8]
950 dispatch(3)
951
952.opNegateSlow:
953 callHelper(_llint_helper_negate)
954 dispatch(3)
955
956
957macro binaryOpCustomStore(integerOperationAndStore, doubleOperation, helper)
958 loadi 12[PC], t2
959 loadi 8[PC], t0
960 loadConstantOrVariable(t2, t3, t1)
961 loadConstantOrVariable2Reg(t0, t2, t0)
962 bineq t2, Int32Tag, .op1NotInt
963 bineq t3, Int32Tag, .op2NotInt
964 loadi 4[PC], t2
965 integerOperationAndStore(t3, t1, t0, .slow, t2)
966 dispatch(5)
967
968.op1NotInt:
969 # First operand is definitely not an int, the second operand could be anything.
970 bia t2, LowestTag, .slow
971 bib t3, LowestTag, .op1NotIntOp2Double
972 bineq t3, Int32Tag, .slow
973 ci2d t1, ft1
974 jmp .op1NotIntReady
975.op1NotIntOp2Double:
976 fii2d t1, t3, ft1
977.op1NotIntReady:
978 loadi 4[PC], t1
979 fii2d t0, t2, ft0
980 doubleOperation(ft1, ft0)
981 stored ft0, [cfr, t1, 8]
982 dispatch(5)
983
984.op2NotInt:
985 # First operand is definitely an int, the second operand is definitely not.
986 loadi 4[PC], t2
987 bia t3, LowestTag, .slow
988 ci2d t0, ft0
989 fii2d t1, t3, ft1
990 doubleOperation(ft1, ft0)
991 stored ft0, [cfr, t2, 8]
992 dispatch(5)
993
994.slow:
995 callHelper(helper)
996 dispatch(5)
997end
998
999macro binaryOp(integerOperation, doubleOperation, helper)
1000 binaryOpCustomStore(
1001 macro (int32Tag, left, right, slow, index)
1002 integerOperation(left, right, slow)
1003 storei int32Tag, TagOffset[cfr, index, 8]
1004 storei right, PayloadOffset[cfr, index, 8]
1005 end,
1006 doubleOperation, helper)
1007end
1008
1009_llint_op_add:
1010 traceExecution()
1011 binaryOp(
1012 macro (left, right, slow) baddio left, right, slow end,
1013 macro (left, right) addd left, right end,
1014 _llint_helper_add)
1015
1016
1017_llint_op_mul:
1018 traceExecution()
1019 binaryOpCustomStore(
1020 macro (int32Tag, left, right, slow, index)
1021 const scratch = int32Tag # We know that we can reuse the int32Tag register since it has a constant.
1022 move right, scratch
1023 bmulio left, scratch, slow
1024 btinz scratch, .done
1025 bilt left, 0, slow
1026 bilt right, 0, slow
1027 .done:
1028 storei Int32Tag, TagOffset[cfr, index, 8]
1029 storei scratch, PayloadOffset[cfr, index, 8]
1030 end,
1031 macro (left, right) muld left, right end,
1032 _llint_helper_mul)
1033
1034
1035_llint_op_sub:
1036 traceExecution()
1037 binaryOp(
1038 macro (left, right, slow) bsubio left, right, slow end,
1039 macro (left, right) subd left, right end,
1040 _llint_helper_sub)
1041
1042
1043_llint_op_div:
1044 traceExecution()
1045 binaryOpCustomStore(
1046 macro (int32Tag, left, right, slow, index)
1047 ci2d left, ft0
1048 ci2d right, ft1
1049 divd ft0, ft1
1050 bcd2i ft1, right, .notInt
1051 storei int32Tag, TagOffset[cfr, index, 8]
1052 storei right, PayloadOffset[cfr, index, 8]
1053 jmp .done
1054 .notInt:
1055 stored ft1, [cfr, index, 8]
1056 .done:
1057 end,
1058 macro (left, right) divd left, right end,
1059 _llint_helper_div)
1060
1061
1062_llint_op_mod:
1063 traceExecution()
1064 callHelper(_llint_helper_mod)
1065 dispatch(4)
1066
1067
1068macro bitOp(operation, helper, advance)
1069 loadi 12[PC], t2
1070 loadi 8[PC], t0
1071 loadConstantOrVariable(t2, t3, t1)
1072 loadConstantOrVariable2Reg(t0, t2, t0)
1073 bineq t3, Int32Tag, .slow
1074 bineq t2, Int32Tag, .slow
1075 loadi 4[PC], t2
1076 operation(t1, t0, .slow)
1077 storei t3, TagOffset[cfr, t2, 8]
1078 storei t0, PayloadOffset[cfr, t2, 8]
1079 dispatch(advance)
1080
1081.slow:
1082 callHelper(helper)
1083 dispatch(advance)
1084end
1085
1086_llint_op_lshift:
1087 traceExecution()
1088 bitOp(
1089 macro (left, right, slow) lshifti left, right end,
1090 _llint_helper_lshift,
1091 4)
1092
1093
1094_llint_op_rshift:
1095 traceExecution()
1096 bitOp(
1097 macro (left, right, slow) rshifti left, right end,
1098 _llint_helper_rshift,
1099 4)
1100
1101
1102_llint_op_urshift:
1103 traceExecution()
1104 bitOp(
1105 macro (left, right, slow)
1106 urshifti left, right
1107 bilt right, 0, slow
1108 end,
1109 _llint_helper_urshift,
1110 4)
1111
1112
1113_llint_op_bitand:
1114 traceExecution()
1115 bitOp(
1116 macro (left, right, slow) andi left, right end,
1117 _llint_helper_bitand,
1118 5)
1119
1120
1121_llint_op_bitxor:
1122 traceExecution()
1123 bitOp(
1124 macro (left, right, slow) xori left, right end,
1125 _llint_helper_bitxor,
1126 5)
1127
1128
1129_llint_op_bitor:
1130 traceExecution()
1131 bitOp(
1132 macro (left, right, slow) ori left, right end,
1133 _llint_helper_bitor,
1134 5)
1135
1136
1137_llint_op_bitnot:
1138 traceExecution()
1139 loadi 8[PC], t1
1140 loadi 4[PC], t0
1141 loadConstantOrVariable(t1, t2, t3)
1142 bineq t2, Int32Tag, .opBitnotSlow
1143 noti t3
1144 storei t2, TagOffset[cfr, t0, 8]
1145 storei t3, PayloadOffset[cfr, t0, 8]
1146 dispatch(3)
1147
1148.opBitnotSlow:
1149 callHelper(_llint_helper_bitnot)
1150 dispatch(3)
1151
1152
1153_llint_op_check_has_instance:
1154 traceExecution()
1155 loadi 4[PC], t1
1156 loadConstantOrVariablePayload(t1, CellTag, t0, .opCheckHasInstanceSlow)
1157 loadp JSCell::m_structure[t0], t0
1158 btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsHasInstance, .opCheckHasInstanceSlow
1159 dispatch(2)
1160
1161.opCheckHasInstanceSlow:
1162 callHelper(_llint_helper_check_has_instance)
1163 dispatch(2)
1164
1165
1166_llint_op_instanceof:
1167 traceExecution()
1168 # Check that baseVal implements the default HasInstance behavior.
1169 # FIXME: This should be deprecated.
1170 loadi 12[PC], t1
1171 loadConstantOrVariablePayloadUnchecked(t1, t0)
1172 loadp JSCell::m_structure[t0], t0
1173 btbz Structure::m_typeInfo + TypeInfo::m_flags[t0], ImplementsDefaultHasInstance, .opInstanceofSlow
1174
1175 # Actually do the work.
1176 loadi 16[PC], t0
1177 loadi 4[PC], t3
1178 loadConstantOrVariablePayload(t0, CellTag, t1, .opInstanceofSlow)
1179 loadp JSCell::m_structure[t1], t2
1180 bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opInstanceofSlow
1181 loadi 8[PC], t0
1182 loadConstantOrVariablePayload(t0, CellTag, t2, .opInstanceofSlow)
1183
1184 # Register state: t1 = prototype, t2 = value
1185 move 1, t0
1186.opInstanceofLoop:
1187 loadp JSCell::m_structure[t2], t2
1188 loadi Structure::m_prototype + PayloadOffset[t2], t2
1189 bpeq t2, t1, .opInstanceofDone
1190 btinz t2, .opInstanceofLoop
1191
1192 move 0, t0
1193.opInstanceofDone:
1194 storei BooleanTag, TagOffset[cfr, t3, 8]
1195 storei t0, PayloadOffset[cfr, t3, 8]
1196 dispatch(5)
1197
1198.opInstanceofSlow:
1199 callHelper(_llint_helper_instanceof)
1200 dispatch(5)
1201
1202
1203_llint_op_typeof:
1204 traceExecution()
1205 callHelper(_llint_helper_typeof)
1206 dispatch(3)
1207
1208
1209_llint_op_is_undefined:
1210 traceExecution()
1211 callHelper(_llint_helper_is_undefined)
1212 dispatch(3)
1213
1214
1215_llint_op_is_boolean:
1216 traceExecution()
1217 callHelper(_llint_helper_is_boolean)
1218 dispatch(3)
1219
1220
1221_llint_op_is_number:
1222 traceExecution()
1223 callHelper(_llint_helper_is_number)
1224 dispatch(3)
1225
1226
1227_llint_op_is_string:
1228 traceExecution()
1229 callHelper(_llint_helper_is_string)
1230 dispatch(3)
1231
1232
1233_llint_op_is_object:
1234 traceExecution()
1235 callHelper(_llint_helper_is_object)
1236 dispatch(3)
1237
1238
1239_llint_op_is_function:
1240 traceExecution()
1241 callHelper(_llint_helper_is_function)
1242 dispatch(3)
1243
1244
1245_llint_op_in:
1246 traceExecution()
1247 callHelper(_llint_helper_in)
1248 dispatch(4)
1249
1250
1251_llint_op_resolve:
1252 traceExecution()
1253 callHelper(_llint_helper_resolve)
1254 dispatch(4)
1255
1256
1257_llint_op_resolve_skip:
1258 traceExecution()
1259 callHelper(_llint_helper_resolve_skip)
1260 dispatch(5)
1261
1262
1263macro resolveGlobal(size, slow)
1264 # Operands are as follows:
1265 # 4[PC] Destination for the load.
1266 # 8[PC] Property identifier index in the code block.
1267 # 12[PC] Structure pointer, initialized to 0 by bytecode generator.
1268 # 16[PC] Offset in global object, initialized to 0 by bytecode generator.
1269 loadp CodeBlock[cfr], t0
1270 loadp CodeBlock::m_globalObject[t0], t0
1271 loadp JSCell::m_structure[t0], t1
1272 bpneq t1, 12[PC], slow
1273 loadi 16[PC], t1
1274 loadp JSObject::m_propertyStorage[t0], t0
1275 loadi TagOffset[t0, t1, 8], t2
1276 loadi PayloadOffset[t0, t1, 8], t3
1277 loadi 4[PC], t0
1278 storei t2, TagOffset[cfr, t0, 8]
1279 storei t3, PayloadOffset[cfr, t0, 8]
1280 loadi (size - 1) * 4[PC], t0
1281 valueProfile(t2, t3, t0)
1282end
1283
1284_llint_op_resolve_global:
1285 traceExecution()
1286 resolveGlobal(6, .opResolveGlobalSlow)
1287 dispatch(6)
1288
1289.opResolveGlobalSlow:
1290 callHelper(_llint_helper_resolve_global)
1291 dispatch(6)
1292
1293
1294# Gives you the scope in t0, while allowing you to optionally perform additional checks on the
1295# scopes as they are traversed. scopeCheck() is called with two arguments: the register
1296# holding the scope, and a register that can be used for scratch. Note that this does not
1297# use t3, so you can hold stuff in t3 if need be.
1298macro getScope(deBruijinIndexOperand, scopeCheck)
1299 loadp ScopeChain + PayloadOffset[cfr], t0
1300 loadi deBruijinIndexOperand, t2
1301
1302 btiz t2, .done
1303
1304 loadp CodeBlock[cfr], t1
1305 bineq CodeBlock::m_codeType[t1], FunctionCode, .loop
1306 btbz CodeBlock::m_needsFullScopeChain[t1], .loop
1307
1308 loadi CodeBlock::m_activationRegister[t1], t1
1309
1310 # Need to conditionally skip over one scope.
1311 bieq TagOffset[cfr, t1, 8], EmptyValueTag, .noActivation
1312 scopeCheck(t0, t1)
1313 loadp ScopeChainNode::next[t0], t0
1314.noActivation:
1315 subi 1, t2
1316
1317 btiz t2, .done
1318.loop:
1319 scopeCheck(t0, t1)
1320 loadp ScopeChainNode::next[t0], t0
1321 subi 1, t2
1322 btinz t2, .loop
1323
1324.done:
1325end
1326
1327_llint_op_resolve_global_dynamic:
1328 traceExecution()
1329 loadp JITStackFrame::globalData[sp], t3
1330 loadp JSGlobalData::activationStructure[t3], t3
1331 getScope(
1332 20[PC],
1333 macro (scope, scratch)
1334 loadp ScopeChainNode::object[scope], scratch
1335 bpneq JSCell::m_structure[scratch], t3, .opResolveGlobalDynamicSuperSlow
1336 end)
1337 resolveGlobal(7, .opResolveGlobalDynamicSlow)
1338 dispatch(7)
1339
1340.opResolveGlobalDynamicSuperSlow:
1341 callHelper(_llint_helper_resolve_for_resolve_global_dynamic)
1342 dispatch(7)
1343
1344.opResolveGlobalDynamicSlow:
1345 callHelper(_llint_helper_resolve_global_dynamic)
1346 dispatch(7)
1347
1348
1349_llint_op_get_scoped_var:
1350 traceExecution()
1351 # Operands are as follows:
1352 # 4[PC] Destination for the load.
1353 # 8[PC] Index of register in the scope.
1354 # 12[PC] De Bruijin index.
1355 getScope(12[PC], macro (scope, scratch) end)
1356 loadi 4[PC], t1
1357 loadi 8[PC], t2
1358 loadp ScopeChainNode::object[t0], t0
1359 loadp JSVariableObject::m_registers[t0], t0
1360 loadi TagOffset[t0, t2, 8], t3
1361 loadi PayloadOffset[t0, t2, 8], t0
1362 storei t3, TagOffset[cfr, t1, 8]
1363 storei t0, PayloadOffset[cfr, t1, 8]
1364 loadi 16[PC], t1
1365 valueProfile(t3, t0, t1)
1366 dispatch(5)
1367
1368
1369_llint_op_put_scoped_var:
1370 traceExecution()
1371 getScope(8[PC], macro (scope, scratch) end)
1372 loadi 12[PC], t1
1373 loadConstantOrVariable(t1, t3, t2)
1374 loadi 4[PC], t1
1375 writeBarrier(t3, t2)
1376 loadp ScopeChainNode::object[t0], t0
1377 loadp JSVariableObject::m_registers[t0], t0
1378 storei t3, TagOffset[t0, t1, 8]
1379 storei t2, PayloadOffset[t0, t1, 8]
1380 dispatch(4)
1381
1382
1383_llint_op_get_global_var:
1384 traceExecution()
1385 loadi 8[PC], t1
1386 loadi 4[PC], t3
1387 loadp CodeBlock[cfr], t0
1388 loadp CodeBlock::m_globalObject[t0], t0
1389 loadp JSGlobalObject::m_registers[t0], t0
1390 loadi TagOffset[t0, t1, 8], t2
1391 loadi PayloadOffset[t0, t1, 8], t1
1392 storei t2, TagOffset[cfr, t3, 8]
1393 storei t1, PayloadOffset[cfr, t3, 8]
1394 loadi 12[PC], t3
1395 valueProfile(t2, t1, t3)
1396 dispatch(4)
1397
1398
1399_llint_op_put_global_var:
1400 traceExecution()
1401 loadi 8[PC], t1
1402 loadp CodeBlock[cfr], t0
1403 loadp CodeBlock::m_globalObject[t0], t0
1404 loadp JSGlobalObject::m_registers[t0], t0
1405 loadConstantOrVariable(t1, t2, t3)
1406 loadi 4[PC], t1
1407 writeBarrier(t2, t3)
1408 storei t2, TagOffset[t0, t1, 8]
1409 storei t3, PayloadOffset[t0, t1, 8]
1410 dispatch(3)
1411
1412
1413_llint_op_resolve_base:
1414 traceExecution()
1415 callHelper(_llint_helper_resolve_base)
1416 dispatch(5)
1417
1418
1419_llint_op_ensure_property_exists:
1420 traceExecution()
1421 callHelper(_llint_helper_ensure_property_exists)
1422 dispatch(3)
1423
1424
1425_llint_op_resolve_with_base:
1426 traceExecution()
1427 callHelper(_llint_helper_resolve_with_base)
1428 dispatch(5)
1429
1430
1431_llint_op_resolve_with_this:
1432 traceExecution()
1433 callHelper(_llint_helper_resolve_with_this)
1434 dispatch(5)
1435
1436
1437_llint_op_get_by_id:
1438 traceExecution()
1439 # We only do monomorphic get_by_id caching for now, and we do not modify the
1440 # opcode. We do, however, allow for the cache to change anytime if fails, since
1441 # ping-ponging is free. At best we get lucky and the get_by_id will continue
1442 # to take fast path on the new cache. At worst we take slow path, which is what
1443 # we would have been doing anyway.
1444 loadi 8[PC], t0
1445 loadi 16[PC], t1
1446 loadConstantOrVariablePayload(t0, CellTag, t3, .opGetByIdSlow)
1447 loadi 20[PC], t2
1448 loadp JSObject::m_propertyStorage[t3], t0
1449 bpneq JSCell::m_structure[t3], t1, .opGetByIdSlow
1450 loadi 4[PC], t1
1451 loadi TagOffset[t0, t2], t3
1452 loadi PayloadOffset[t0, t2], t2
1453 storei t3, TagOffset[cfr, t1, 8]
1454 storei t2, PayloadOffset[cfr, t1, 8]
1455 loadi 32[PC], t1
1456 valueProfile(t3, t2, t1)
1457 dispatch(9)
1458
1459.opGetByIdSlow:
1460 callHelper(_llint_helper_get_by_id)
1461 dispatch(9)
1462
1463
1464_llint_op_get_arguments_length:
1465 traceExecution()
1466 loadi 8[PC], t0
1467 loadi 4[PC], t1
1468 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentsLengthSlow
1469 loadi ArgumentCount + PayloadOffset[cfr], t2
1470 subi 1, t2
1471 storei Int32Tag, TagOffset[cfr, t1, 8]
1472 storei t2, PayloadOffset[cfr, t1, 8]
1473 dispatch(4)
1474
1475.opGetArgumentsLengthSlow:
1476 callHelper(_llint_helper_get_arguments_length)
1477 dispatch(4)
1478
1479
1480_llint_op_put_by_id:
1481 traceExecution()
1482 loadi 4[PC], t3
1483 loadi 16[PC], t1
1484 loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1485 loadi 12[PC], t2
1486 loadp JSObject::m_propertyStorage[t0], t3
1487 bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1488 loadi 20[PC], t1
1489 loadConstantOrVariable2Reg(t2, t0, t2)
1490 writeBarrier(t0, t2)
1491 storei t0, TagOffset[t3, t1]
1492 storei t2, PayloadOffset[t3, t1]
1493 dispatch(9)
1494
1495.opPutByIdSlow:
1496 callHelper(_llint_helper_put_by_id)
1497 dispatch(9)
1498
1499
1500macro putByIdTransition(additionalChecks)
1501 traceExecution()
1502 loadi 4[PC], t3
1503 loadi 16[PC], t1
1504 loadConstantOrVariablePayload(t3, CellTag, t0, .opPutByIdSlow)
1505 loadi 12[PC], t2
1506 bpneq JSCell::m_structure[t0], t1, .opPutByIdSlow
1507 additionalChecks(t1, t3, .opPutByIdSlow)
1508 loadi 20[PC], t1
1509 loadp JSObject::m_propertyStorage[t0], t3
1510 addp t1, t3
1511 loadConstantOrVariable2Reg(t2, t1, t2)
1512 writeBarrier(t1, t2)
1513 storei t1, TagOffset[t3]
1514 loadi 24[PC], t1
1515 storei t2, PayloadOffset[t3]
1516 storep t1, JSCell::m_structure[t0]
1517 dispatch(9)
1518end
1519
1520_llint_op_put_by_id_transition_direct:
1521 putByIdTransition(macro (oldStructure, scratch, slow) end)
1522
1523
1524_llint_op_put_by_id_transition_normal:
1525 putByIdTransition(
1526 macro (oldStructure, scratch, slow)
1527 const protoCell = oldStructure # Reusing the oldStructure register for the proto
1528
1529 loadp 28[PC], scratch
1530 assert(macro (ok) btpnz scratch, ok end)
1531 loadp StructureChain::m_vector[scratch], scratch
1532 assert(macro (ok) btpnz scratch, ok end)
1533 bieq Structure::m_prototype + TagOffset[oldStructure], NullTag, .done
1534 .loop:
1535 loadi Structure::m_prototype + PayloadOffset[oldStructure], protoCell
1536 loadp JSCell::m_structure[protoCell], oldStructure
1537 bpneq oldStructure, [scratch], slow
1538 addp 4, scratch
1539 bineq Structure::m_prototype + TagOffset[oldStructure], NullTag, .loop
1540 .done:
1541 end)
1542
1543
1544_llint_op_del_by_id:
1545 traceExecution()
1546 callHelper(_llint_helper_del_by_id)
1547 dispatch(4)
1548
1549
1550_llint_op_get_by_val:
1551 traceExecution()
1552 loadp CodeBlock[cfr], t1
1553 loadi 8[PC], t2
1554 loadi 12[PC], t3
1555 loadp CodeBlock::m_globalData[t1], t1
1556 loadConstantOrVariablePayload(t2, CellTag, t0, .opGetByValSlow)
1557 loadp JSGlobalData::jsArrayClassInfo[t1], t2
1558 loadConstantOrVariablePayload(t3, Int32Tag, t1, .opGetByValSlow)
1559 bpneq [t0], t2, .opGetByValSlow
1560 loadp JSArray::m_storage[t0], t3
1561 biaeq t1, JSArray::m_vectorLength[t0], .opGetByValSlow
1562 loadi 4[PC], t0
1563 loadi ArrayStorage::m_vector + TagOffset[t3, t1, 8], t2
1564 loadi ArrayStorage::m_vector + PayloadOffset[t3, t1, 8], t1
1565 bieq t2, EmptyValueTag, .opGetByValSlow
1566 storei t2, TagOffset[cfr, t0, 8]
1567 storei t1, PayloadOffset[cfr, t0, 8]
1568 loadi 16[PC], t0
1569 valueProfile(t2, t1, t0)
1570 dispatch(5)
1571
1572.opGetByValSlow:
1573 callHelper(_llint_helper_get_by_val)
1574 dispatch(5)
1575
1576
1577_llint_op_get_argument_by_val:
1578 traceExecution()
1579 loadi 8[PC], t0
1580 loadi 12[PC], t1
1581 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opGetArgumentByValSlow
1582 loadConstantOrVariablePayload(t1, Int32Tag, t2, .opGetArgumentByValSlow)
1583 addi 1, t2
1584 loadi ArgumentCount + PayloadOffset[cfr], t1
1585 biaeq t2, t1, .opGetArgumentByValSlow
1586 negi t2
1587 loadi 4[PC], t3
1588 loadi ThisArgumentOffset + TagOffset[cfr, t2, 8], t0
1589 loadi ThisArgumentOffset + PayloadOffset[cfr, t2, 8], t1
1590 storei t0, TagOffset[cfr, t3, 8]
1591 storei t1, PayloadOffset[cfr, t3, 8]
1592 dispatch(4)
1593
1594.opGetArgumentByValSlow:
1595 callHelper(_llint_helper_get_argument_by_val)
1596 dispatch(4)
1597
1598
1599_llint_op_get_by_pname:
1600 traceExecution()
1601 loadi 12[PC], t0
1602 loadConstantOrVariablePayload(t0, CellTag, t1, .opGetByPnameSlow)
1603 loadi 16[PC], t0
1604 bpneq t1, PayloadOffset[cfr, t0, 8], .opGetByPnameSlow
1605 loadi 8[PC], t0
1606 loadConstantOrVariablePayload(t0, CellTag, t2, .opGetByPnameSlow)
1607 loadi 20[PC], t0
1608 loadi PayloadOffset[cfr, t0, 8], t3
1609 loadp JSCell::m_structure[t2], t0
1610 bpneq t0, JSPropertyNameIterator::m_cachedStructure[t3], .opGetByPnameSlow
1611 loadi 24[PC], t0
1612 loadi [cfr, t0, 8], t0
1613 subi 1, t0
1614 biaeq t0, JSPropertyNameIterator::m_numCacheableSlots[t3], .opGetByPnameSlow
1615 loadp JSObject::m_propertyStorage[t2], t2
1616 loadi TagOffset[t2, t0, 8], t1
1617 loadi PayloadOffset[t2, t0, 8], t3
1618 loadi 4[PC], t0
1619 storei t1, TagOffset[cfr, t0, 8]
1620 storei t3, PayloadOffset[cfr, t0, 8]
1621 dispatch(7)
1622
1623.opGetByPnameSlow:
1624 callHelper(_llint_helper_get_by_pname)
1625 dispatch(7)
1626
1627
1628_llint_op_put_by_val:
1629 traceExecution()
1630 loadi 4[PC], t0
1631 loadConstantOrVariablePayload(t0, CellTag, t1, .opPutByValSlow)
1632 loadi 8[PC], t0
1633 loadConstantOrVariablePayload(t0, Int32Tag, t2, .opPutByValSlow)
1634 loadp CodeBlock[cfr], t0
1635 loadp CodeBlock::m_globalData[t0], t0
1636 loadp JSGlobalData::jsArrayClassInfo[t0], t0
1637 bpneq [t1], t0, .opPutByValSlow
1638 biaeq t2, JSArray::m_vectorLength[t1], .opPutByValSlow
1639 loadp JSArray::m_storage[t1], t0
1640 bieq ArrayStorage::m_vector + TagOffset[t0, t2, 8], EmptyValueTag, .opPutByValEmpty
1641.opPutByValStoreResult:
1642 loadi 12[PC], t3
1643 loadConstantOrVariable2Reg(t3, t1, t3)
1644 writeBarrier(t1, t3)
1645 storei t1, ArrayStorage::m_vector + TagOffset[t0, t2, 8]
1646 storei t3, ArrayStorage::m_vector + PayloadOffset[t0, t2, 8]
1647 dispatch(4)
1648
1649.opPutByValEmpty:
1650 addi 1, ArrayStorage::m_numValuesInVector[t0]
1651 bib t2, ArrayStorage::m_length[t0], .opPutByValStoreResult
1652 addi 1, t2, t1
1653 storei t1, ArrayStorage::m_length[t0]
1654 jmp .opPutByValStoreResult
1655
1656.opPutByValSlow:
1657 callHelper(_llint_helper_put_by_val)
1658 dispatch(4)
1659
1660
1661_llint_op_del_by_val:
1662 traceExecution()
1663 callHelper(_llint_helper_del_by_val)
1664 dispatch(4)
1665
1666
1667_llint_op_put_by_index:
1668 traceExecution()
1669 callHelper(_llint_helper_put_by_index)
1670 dispatch(4)
1671
1672
1673_llint_op_put_getter_setter:
1674 traceExecution()
1675 callHelper(_llint_helper_put_getter_setter)
1676 dispatch(5)
1677
1678
1679_llint_op_loop:
1680 nop
1681_llint_op_jmp:
1682 traceExecution()
1683 dispatchBranch(4[PC])
1684
1685
1686_llint_op_jmp_scopes:
1687 traceExecution()
1688 callHelper(_llint_helper_jmp_scopes)
1689 dispatch(0)
1690
1691
1692macro jumpTrueOrFalse(conditionOp, slow)
1693 loadi 4[PC], t1
1694 loadConstantOrVariablePayload(t1, BooleanTag, t0, .slow)
1695 conditionOp(t0, .target)
1696 dispatch(3)
1697
1698.target:
1699 dispatchBranch(8[PC])
1700
1701.slow:
1702 callHelper(slow)
1703 dispatch(0)
1704end
1705
1706_llint_op_loop_if_true:
1707 nop
1708_llint_op_jtrue:
1709 traceExecution()
1710 jumpTrueOrFalse(
1711 macro (value, target) btinz value, target end,
1712 _llint_helper_jtrue)
1713
1714
1715_llint_op_loop_if_false:
1716 nop
1717_llint_op_jfalse:
1718 traceExecution()
1719 jumpTrueOrFalse(
1720 macro (value, target) btiz value, target end,
1721 _llint_helper_jfalse)
1722
1723
1724macro equalNull(cellHandler, immediateHandler)
1725 loadi 4[PC], t0
1726 loadi TagOffset[cfr, t0, 8], t1
1727 loadi PayloadOffset[cfr, t0, 8], t0
1728 bineq t1, CellTag, .immediate
1729 loadp JSCell::m_structure[t0], t2
1730 cellHandler(Structure::m_typeInfo + TypeInfo::m_flags[t2], .target)
1731 dispatch(3)
1732
1733.target:
1734 dispatchBranch(8[PC])
1735
1736.immediate:
1737 ori 1, t1
1738 immediateHandler(t1, .target)
1739 dispatch(3)
1740end
1741
1742_llint_op_jeq_null:
1743 traceExecution()
1744 equalNull(
1745 macro (value, target) btbnz value, MasqueradesAsUndefined, target end,
1746 macro (value, target) bieq value, NullTag, target end)
1747
1748
1749_llint_op_jneq_null:
1750 traceExecution()
1751 equalNull(
1752 macro (value, target) btbz value, MasqueradesAsUndefined, target end,
1753 macro (value, target) bineq value, NullTag, target end)
1754
1755
1756_llint_op_jneq_ptr:
1757 traceExecution()
1758 loadi 4[PC], t0
1759 loadi 8[PC], t1
1760 bineq TagOffset[cfr, t0, 8], CellTag, .opJneqPtrBranch
1761 bpeq PayloadOffset[cfr, t0, 8], t1, .opJneqPtrFallThrough
1762.opJneqPtrBranch:
1763 dispatchBranch(12[PC])
1764.opJneqPtrFallThrough:
1765 dispatch(4)
1766
1767
1768macro compare(integerCompare, doubleCompare, helper)
1769 loadi 4[PC], t2
1770 loadi 8[PC], t3
1771 loadConstantOrVariable(t2, t0, t1)
1772 loadConstantOrVariable2Reg(t3, t2, t3)
1773 bineq t0, Int32Tag, .op1NotInt
1774 bineq t2, Int32Tag, .op2NotInt
1775 integerCompare(t1, t3, .jumpTarget)
1776 dispatch(4)
1777
1778.op1NotInt:
1779 bia t0, LowestTag, .slow
1780 bib t2, LowestTag, .op1NotIntOp2Double
1781 bineq t2, Int32Tag, .slow
1782 ci2d t3, ft1
1783 jmp .op1NotIntReady
1784.op1NotIntOp2Double:
1785 fii2d t3, t2, ft1
1786.op1NotIntReady:
1787 fii2d t1, t0, ft0
1788 doubleCompare(ft0, ft1, .jumpTarget)
1789 dispatch(4)
1790
1791.op2NotInt:
1792 ci2d t1, ft0
1793 bia t2, LowestTag, .slow
1794 fii2d t3, t2, ft1
1795 doubleCompare(ft0, ft1, .jumpTarget)
1796 dispatch(4)
1797
1798.jumpTarget:
1799 dispatchBranch(12[PC])
1800
1801.slow:
1802 callHelper(helper)
1803 dispatch(0)
1804end
1805
1806_llint_op_loop_if_less:
1807 nop
1808_llint_op_jless:
1809 traceExecution()
1810 compare(
1811 macro (left, right, target) bilt left, right, target end,
1812 macro (left, right, target) bdlt left, right, target end,
1813 _llint_helper_jless)
1814
1815
1816_llint_op_jnless:
1817 traceExecution()
1818 compare(
1819 macro (left, right, target) bigteq left, right, target end,
1820 macro (left, right, target) bdgtequn left, right, target end,
1821 _llint_helper_jnless)
1822
1823
1824_llint_op_loop_if_greater:
1825 nop
1826_llint_op_jgreater:
1827 traceExecution()
1828 compare(
1829 macro (left, right, target) bigt left, right, target end,
1830 macro (left, right, target) bdgt left, right, target end,
1831 _llint_helper_jgreater)
1832
1833
1834_llint_op_jngreater:
1835 traceExecution()
1836 compare(
1837 macro (left, right, target) bilteq left, right, target end,
1838 macro (left, right, target) bdltequn left, right, target end,
1839 _llint_helper_jngreater)
1840
1841
1842_llint_op_loop_if_lesseq:
1843 nop
1844_llint_op_jlesseq:
1845 traceExecution()
1846 compare(
1847 macro (left, right, target) bilteq left, right, target end,
1848 macro (left, right, target) bdlteq left, right, target end,
1849 _llint_helper_jlesseq)
1850
1851
1852_llint_op_jnlesseq:
1853 traceExecution()
1854 compare(
1855 macro (left, right, target) bigt left, right, target end,
1856 macro (left, right, target) bdgtun left, right, target end,
1857 _llint_helper_jnlesseq)
1858
1859
1860_llint_op_loop_if_greatereq:
1861 nop
1862_llint_op_jgreatereq:
1863 traceExecution()
1864 compare(
1865 macro (left, right, target) bigteq left, right, target end,
1866 macro (left, right, target) bdgteq left, right, target end,
1867 _llint_helper_jgreatereq)
1868
1869
1870_llint_op_jngreatereq:
1871 traceExecution()
1872 compare(
1873 macro (left, right, target) bilt left, right, target end,
1874 macro (left, right, target) bdltun left, right, target end,
1875 _llint_helper_jngreatereq)
1876
1877
1878_llint_op_loop_hint:
1879 traceExecution()
1880 checkSwitchToJITForLoop()
1881 dispatch(1)
1882
1883
1884_llint_op_switch_imm:
1885 traceExecution()
1886 loadi 12[PC], t2
1887 loadi 4[PC], t3
1888 loadConstantOrVariable(t2, t1, t0)
1889 loadp CodeBlock[cfr], t2
1890 loadp CodeBlock::m_rareData[t2], t2
1891 muli sizeof SimpleJumpTable, t3 # FIXME: would be nice to peephole this!
1892 loadp CodeBlock::RareData::m_immediateSwitchJumpTables + VectorBufferOffset[t2], t2
1893 addp t3, t2
1894 bineq t1, Int32Tag, .opSwitchImmNotInt
1895 subi SimpleJumpTable::min[t2], t0
1896 biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchImmFallThrough
1897 loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t3
1898 loadi [t3, t0, 4], t1
1899 btiz t1, .opSwitchImmFallThrough
1900 dispatchBranchWithOffset(t1)
1901
1902.opSwitchImmNotInt:
1903 bib t1, LowestTag, .opSwitchImmSlow # Go to slow path if it's a double.
1904.opSwitchImmFallThrough:
1905 dispatchBranch(8[PC])
1906
1907.opSwitchImmSlow:
1908 callHelper(_llint_helper_switch_imm)
1909 dispatch(0)
1910
1911
1912_llint_op_switch_char:
1913 traceExecution()
1914 loadi 12[PC], t2
1915 loadi 4[PC], t3
1916 loadConstantOrVariable(t2, t1, t0)
1917 loadp CodeBlock[cfr], t2
1918 loadp CodeBlock::m_rareData[t2], t2
1919 muli sizeof SimpleJumpTable, t3
1920 loadp CodeBlock::RareData::m_characterSwitchJumpTables + VectorBufferOffset[t2], t2
1921 addp t3, t2
1922 bineq t1, CellTag, .opSwitchCharFallThrough
1923 loadp JSCell::m_structure[t0], t1
1924 bbneq Structure::m_typeInfo + TypeInfo::m_type[t1], StringType, .opSwitchCharFallThrough
1925 loadp JSString::m_value[t0], t0
1926 bineq StringImpl::m_length[t0], 1, .opSwitchCharFallThrough
1927 loadp StringImpl::m_data8[t0], t1
1928 btinz StringImpl::m_hashAndFlags[t0], HashFlags8BitBuffer, .opSwitchChar8Bit
1929 loadh [t1], t0
1930 jmp .opSwitchCharReady
1931.opSwitchChar8Bit:
1932 loadb [t1], t0
1933.opSwitchCharReady:
1934 subi SimpleJumpTable::min[t2], t0
1935 biaeq t0, SimpleJumpTable::branchOffsets + VectorSizeOffset[t2], .opSwitchCharFallThrough
1936 loadp SimpleJumpTable::branchOffsets + VectorBufferOffset[t2], t2
1937 loadi [t2, t0, 4], t1
1938 btiz t1, .opSwitchImmFallThrough
1939 dispatchBranchWithOffset(t1)
1940
1941.opSwitchCharFallThrough:
1942 dispatchBranch(8[PC])
1943
1944
1945_llint_op_switch_string:
1946 traceExecution()
1947 callHelper(_llint_helper_switch_string)
1948 dispatch(0)
1949
1950
1951_llint_op_new_func:
1952 traceExecution()
1953 btiz 12[PC], .opNewFuncUnchecked
1954 loadi 4[PC], t1
1955 bineq TagOffset[cfr, t1, 8], EmptyValueTag, .opNewFuncDone
1956.opNewFuncUnchecked:
1957 callHelper(_llint_helper_new_func)
1958.opNewFuncDone:
1959 dispatch(4)
1960
1961
1962_llint_op_new_func_exp:
1963 traceExecution()
1964 callHelper(_llint_helper_new_func_exp)
1965 dispatch(3)
1966
1967
1968macro doCall(helper)
1969 loadi 4[PC], t0
1970 loadi 16[PC], t1
1971 loadp LLIntCallLinkInfo::callee[t1], t2
1972 loadConstantOrVariablePayload(t0, CellTag, t3, .opCallSlow)
1973 bineq t3, t2, .opCallSlow
1974 loadi 12[PC], t3
1975 addp 24, PC
1976 lshifti 3, t3
1977 addp cfr, t3 # t3 contains the new value of cfr
1978 loadp JSFunction::m_scopeChain[t2], t0
1979 storei t2, Callee + PayloadOffset[t3]
1980 storei t0, ScopeChain + PayloadOffset[t3]
1981 loadi 8 - 24[PC], t2
1982 storei PC, ArgumentCount + TagOffset[cfr]
1983 storep cfr, CallerFrame[t3]
1984 storei t2, ArgumentCount + PayloadOffset[t3]
1985 storei CellTag, Callee + TagOffset[t3]
1986 storei CellTag, ScopeChain + TagOffset[t3]
1987 move t3, cfr
1988 call LLIntCallLinkInfo::machineCodeTarget[t1]
1989 dispatchAfterCall()
1990
1991.opCallSlow:
1992 slowPathForCall(6, helper)
1993end
1994
1995_llint_op_call:
1996 traceExecution()
1997 doCall(_llint_helper_call)
1998
1999
2000_llint_op_construct:
2001 traceExecution()
2002 doCall(_llint_helper_construct)
2003
2004
2005_llint_op_call_varargs:
2006 traceExecution()
2007 slowPathForCall(6, _llint_helper_call_varargs)
2008
2009
2010_llint_op_call_eval:
2011 traceExecution()
2012
2013 # Eval is executed in one of two modes:
2014 #
2015 # 1) We find that we're really invoking eval() in which case the
2016 # execution is perfomed entirely inside the helper, and it
2017 # returns the PC of a function that just returns the return value
2018 # that the eval returned.
2019 #
2020 # 2) We find that we're invoking something called eval() that is not
2021 # the real eval. Then the helper returns the PC of the thing to
2022 # call, and we call it.
2023 #
2024 # This allows us to handle two cases, which would require a total of
2025 # up to four pieces of state that cannot be easily packed into two
2026 # registers (C functions can return up to two registers, easily):
2027 #
2028 # - The call frame register. This may or may not have been modified
2029 # by the helper, but the convention is that it returns it. It's not
2030 # totally clear if that's necessary, since the cfr is callee save.
2031 # But that's our style in this here interpreter so we stick with it.
2032 #
2033 # - A bit to say if the helper successfully executed the eval and has
2034 # the return value, or did not execute the eval but has a PC for us
2035 # to call.
2036 #
2037 # - Either:
2038 # - The JS return value (two registers), or
2039 #
2040 # - The PC to call.
2041 #
2042 # It turns out to be easier to just always have this return the cfr
2043 # and a PC to call, and that PC may be a dummy thunk that just
2044 # returns the JS value that the eval returned.
2045
2046 slowPathForCall(4, _llint_helper_call_eval)
2047
2048
2049_llint_generic_return_point:
2050 dispatchAfterCall()
2051
2052
2053_llint_op_tear_off_activation:
2054 traceExecution()
2055 loadi 4[PC], t0
2056 loadi 8[PC], t1
2057 bineq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffActivationCreated
2058 bieq TagOffset[cfr, t1, 8], EmptyValueTag, .opTearOffActivationNotCreated
2059.opTearOffActivationCreated:
2060 callHelper(_llint_helper_tear_off_activation)
2061.opTearOffActivationNotCreated:
2062 dispatch(3)
2063
2064
2065_llint_op_tear_off_arguments:
2066 traceExecution()
2067 loadi 4[PC], t0
2068 subi 1, t0 # Get the unmodifiedArgumentsRegister
2069 bieq TagOffset[cfr, t0, 8], EmptyValueTag, .opTearOffArgumentsNotCreated
2070 callHelper(_llint_helper_tear_off_arguments)
2071.opTearOffArgumentsNotCreated:
2072 dispatch(2)
2073
2074
2075macro doReturn()
2076 loadp ReturnPC[cfr], t2
2077 loadp CallerFrame[cfr], cfr
2078 restoreReturnAddressBeforeReturn(t2)
2079 ret
2080end
2081
2082_llint_op_ret:
2083 traceExecution()
2084 checkSwitchToJITForEpilogue()
2085 loadi 4[PC], t2
2086 loadConstantOrVariable(t2, t1, t0)
2087 doReturn()
2088
2089
2090_llint_op_call_put_result:
2091 loadi 4[PC], t2
2092 loadi 8[PC], t3
2093 storei t1, TagOffset[cfr, t2, 8]
2094 storei t0, PayloadOffset[cfr, t2, 8]
2095 valueProfile(t1, t0, t3)
2096 traceExecution() # Needs to be here because it would clobber t1, t0
2097 dispatch(3)
2098
2099
2100_llint_op_ret_object_or_this:
2101 traceExecution()
2102 checkSwitchToJITForEpilogue()
2103 loadi 4[PC], t2
2104 loadConstantOrVariable(t2, t1, t0)
2105 bineq t1, CellTag, .opRetObjectOrThisNotObject
2106 loadp JSCell::m_structure[t0], t2
2107 bbb Structure::m_typeInfo + TypeInfo::m_type[t2], ObjectType, .opRetObjectOrThisNotObject
2108 doReturn()
2109
2110.opRetObjectOrThisNotObject:
2111 loadi 8[PC], t2
2112 loadConstantOrVariable(t2, t1, t0)
2113 doReturn()
2114
2115
2116_llint_op_method_check:
2117 traceExecution()
2118 # We ignore method checks and use normal get_by_id optimizations.
2119 dispatch(1)
2120
2121
2122_llint_op_strcat:
2123 traceExecution()
2124 callHelper(_llint_helper_strcat)
2125 dispatch(4)
2126
2127
2128_llint_op_to_primitive:
2129 traceExecution()
2130 loadi 8[PC], t2
2131 loadi 4[PC], t3
2132 loadConstantOrVariable(t2, t1, t0)
2133 bineq t1, CellTag, .opToPrimitiveIsImm
2134 loadp JSCell::m_structure[t0], t2
2135 bbneq Structure::m_typeInfo + TypeInfo::m_type[t2], StringType, .opToPrimitiveSlowCase
2136.opToPrimitiveIsImm:
2137 storei t1, TagOffset[cfr, t3, 8]
2138 storei t0, PayloadOffset[cfr, t3, 8]
2139 dispatch(3)
2140
2141.opToPrimitiveSlowCase:
2142 callHelper(_llint_helper_to_primitive)
2143 dispatch(3)
2144
2145
2146_llint_op_get_pnames:
2147 traceExecution()
2148 callHelper(_llint_helper_get_pnames)
2149 dispatch(0) # The helper either advances the PC or jumps us to somewhere else.
2150
2151
2152_llint_op_next_pname:
2153 traceExecution()
2154 loadi 12[PC], t1
2155 loadi 16[PC], t2
2156 loadi PayloadOffset[cfr, t1, 8], t0
2157 bieq t0, PayloadOffset[cfr, t2, 8], .opNextPnameEnd
2158 loadi 20[PC], t2
2159 loadi PayloadOffset[cfr, t2, 8], t2
2160 loadp JSPropertyNameIterator::m_jsStrings[t2], t3
2161 loadi [t3, t0, 8], t3
2162 addi 1, t0
2163 storei t0, PayloadOffset[cfr, t1, 8]
2164 loadi 4[PC], t1
2165 storei CellTag, TagOffset[cfr, t1, 8]
2166 storei t3, PayloadOffset[cfr, t1, 8]
2167 loadi 8[PC], t3
2168 loadi PayloadOffset[cfr, t3, 8], t3
2169 loadp JSCell::m_structure[t3], t1
2170 bpneq t1, JSPropertyNameIterator::m_cachedStructure[t2], .opNextPnameSlow
2171 loadp JSPropertyNameIterator::m_cachedPrototypeChain[t2], t0
2172 loadp StructureChain::m_vector[t0], t0
2173 btpz [t0], .opNextPnameTarget
2174.opNextPnameCheckPrototypeLoop:
2175 bieq Structure::m_prototype + TagOffset[t1], NullTag, .opNextPnameSlow
2176 loadp Structure::m_prototype + PayloadOffset[t1], t2
2177 loadp JSCell::m_structure[t2], t1
2178 bpneq t1, [t0], .opNextPnameSlow
2179 addp 4, t0
2180 btpnz [t0], .opNextPnameCheckPrototypeLoop
2181.opNextPnameTarget:
2182 dispatchBranch(24[PC])
2183
2184.opNextPnameEnd:
2185 dispatch(7)
2186
2187.opNextPnameSlow:
2188 callHelper(_llint_helper_next_pname) # This either keeps the PC where it was (causing us to loop) or sets it to target.
2189 dispatch(0)
2190
2191
2192_llint_op_push_scope:
2193 traceExecution()
2194 callHelper(_llint_helper_push_scope)
2195 dispatch(2)
2196
2197
2198_llint_op_pop_scope:
2199 traceExecution()
2200 callHelper(_llint_helper_pop_scope)
2201 dispatch(1)
2202
2203
2204_llint_op_push_new_scope:
2205 traceExecution()
2206 callHelper(_llint_helper_push_new_scope)
2207 dispatch(4)
2208
2209
2210_llint_op_catch:
2211 # This is where we end up from the JIT's throw trampoline (because the
2212 # machine code return address will be set to _llint_op_catch), and from
2213 # the interpreter's throw trampoline (see _llint_throw_trampoline).
2214 # The JIT throwing protocol calls for the cfr to be in t0. The throwing
2215 # code must have known that we were throwing to the interpreter, and have
2216 # set JSGlobalData::targetInterpreterPCForThrow.
2217 move t0, cfr
2218 loadp JITStackFrame::globalData[sp], t3
2219 loadi JSGlobalData::targetInterpreterPCForThrow[t3], PC
2220 loadi JSGlobalData::exception + PayloadOffset[t3], t0
2221 loadi JSGlobalData::exception + TagOffset[t3], t1
2222 storei 0, JSGlobalData::exception + PayloadOffset[t3]
2223 storei EmptyValueTag, JSGlobalData::exception + TagOffset[t3]
2224 loadi 4[PC], t2
2225 storei t0, PayloadOffset[cfr, t2, 8]
2226 storei t1, TagOffset[cfr, t2, 8]
2227 traceExecution() # This needs to be here because we don't want to clobber t0, t1, t2, t3 above.
2228 dispatch(2)
2229
2230
2231_llint_op_throw:
2232 traceExecution()
2233 callHelper(_llint_helper_throw)
2234 dispatch(2)
2235
2236
2237_llint_op_throw_reference_error:
2238 traceExecution()
2239 callHelper(_llint_helper_throw_reference_error)
2240 dispatch(2)
2241
2242
2243_llint_op_jsr:
2244 traceExecution()
2245 loadi 4[PC], t0
2246 addi 3 * 4, PC, t1
2247 storei t1, [cfr, t0, 8]
2248 dispatchBranch(8[PC])
2249
2250
2251_llint_op_sret:
2252 traceExecution()
2253 loadi 4[PC], t0
2254 loadp [cfr, t0, 8], PC
2255 dispatch(0)
2256
2257
2258_llint_op_debug:
2259 traceExecution()
2260 callHelper(_llint_helper_debug)
2261 dispatch(4)
2262
2263
2264_llint_op_profile_will_call:
2265 traceExecution()
2266 loadp JITStackFrame::enabledProfilerReference[sp], t0
2267 btpz [t0], .opProfileWillCallDone
2268 callHelper(_llint_helper_profile_will_call)
2269.opProfileWillCallDone:
2270 dispatch(2)
2271
2272
2273_llint_op_profile_did_call:
2274 traceExecution()
2275 loadp JITStackFrame::enabledProfilerReference[sp], t0
2276 btpz [t0], .opProfileWillCallDone
2277 callHelper(_llint_helper_profile_did_call)
2278.opProfileDidCallDone:
2279 dispatch(2)
2280
2281
2282_llint_op_end:
2283 traceExecution()
2284 checkSwitchToJITForEpilogue()
2285 loadi 4[PC], t0
2286 loadi TagOffset[cfr, t0, 8], t1
2287 loadi PayloadOffset[cfr, t0, 8], t0
2288 doReturn()
2289
2290
2291_llint_throw_from_helper_trampoline:
2292 # When throwing from the interpreter (i.e. throwing from LLIntHelpers), so
2293 # the throw target is not necessarily interpreted code, we come to here.
2294 # This essentially emulates the JIT's throwing protocol.
2295 loadp JITStackFrame::globalData[sp], t1
2296 loadp JSGlobalData::callFrameForThrow[t1], t0
2297 jmp JSGlobalData::targetMachinePCForThrow[t1]
2298
2299
2300_llint_throw_during_call_trampoline:
2301 preserveReturnAddressAfterCall(t2)
2302 loadp JITStackFrame::globalData[sp], t1
2303 loadp JSGlobalData::callFrameForThrow[t1], t0
2304 jmp JSGlobalData::targetMachinePCForThrow[t1]
2305
2306
2307# Lastly, make sure that we can link even though we don't support all opcodes.
2308# These opcodes should never arise when using LLInt or either JIT. We assert
2309# as much.
2310
2311macro notSupported()
2312 if ASSERT_ENABLED
2313 crash()
2314 else
2315 # We should use whatever the smallest possible instruction is, just to
2316 # ensure that there is a gap between instruction labels. If multiple
2317 # smallest instructions exist, we should pick the one that is most
2318 # likely result in execution being halted. Currently that is the break
2319 # instruction on all architectures we're interested in. (Break is int3
2320 # on Intel, which is 1 byte, and bkpt on ARMv7, which is 2 bytes.)
2321 break
2322 end
2323end
2324
2325_llint_op_get_array_length:
2326 notSupported()
2327
2328_llint_op_get_by_id_chain:
2329 notSupported()
2330
2331_llint_op_get_by_id_custom_chain:
2332 notSupported()
2333
2334_llint_op_get_by_id_custom_proto:
2335 notSupported()
2336
2337_llint_op_get_by_id_custom_self:
2338 notSupported()
2339
2340_llint_op_get_by_id_generic:
2341 notSupported()
2342
2343_llint_op_get_by_id_getter_chain:
2344 notSupported()
2345
2346_llint_op_get_by_id_getter_proto:
2347 notSupported()
2348
2349_llint_op_get_by_id_getter_self:
2350 notSupported()
2351
2352_llint_op_get_by_id_proto:
2353 notSupported()
2354
2355_llint_op_get_by_id_self:
2356 notSupported()
2357
2358_llint_op_get_string_length:
2359 notSupported()
2360
2361_llint_op_put_by_id_generic:
2362 notSupported()
2363
2364_llint_op_put_by_id_replace:
2365 notSupported()
2366
2367_llint_op_put_by_id_transition:
2368 notSupported()
2369
2370
2371# Indicate the end of LLInt.
2372_llint_end:
2373 crash()
2374