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