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