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