]> git.saurik.com Git - apple/javascriptcore.git/blob - llint/LowLevelInterpreter.asm
45a604cc2a64ebbe71b033f4217e83fefa4474c6
[apple/javascriptcore.git] / llint / LowLevelInterpreter.asm
1 # Copyright (C) 2011, 2012, 2013, 2014 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 # First come the common protocols that both interpreters use. Note that each
25 # of these must have an ASSERT() in LLIntData.cpp
26
27 # Work-around for the fact that the toolchain's awareness of armv7s results in
28 # a separate slab in the fat binary, yet the offlineasm doesn't know to expect
29 # it.
30 if ARMv7s
31 end
32
33 # These declarations must match interpreter/JSStack.h.
34
35 if JSVALUE64
36 const PtrSize = 8
37 const CallFrameHeaderSlots = 6
38 else
39 const PtrSize = 4
40 const CallFrameHeaderSlots = 5
41 const CallFrameAlignSlots = 1
42 end
43 const SlotSize = 8
44
45 const CallerFrameAndPCSize = 2 * PtrSize
46
47 const CallerFrame = 0
48 const ReturnPC = CallerFrame + PtrSize
49 const CodeBlock = ReturnPC + PtrSize
50 const ScopeChain = CodeBlock + SlotSize
51 const Callee = ScopeChain + SlotSize
52 const ArgumentCount = Callee + SlotSize
53 const ThisArgumentOffset = ArgumentCount + SlotSize
54 const CallFrameHeaderSize = ThisArgumentOffset
55
56 # Some value representation constants.
57 if JSVALUE64
58 const TagBitTypeOther = 0x2
59 const TagBitBool = 0x4
60 const TagBitUndefined = 0x8
61 const ValueEmpty = 0x0
62 const ValueFalse = TagBitTypeOther | TagBitBool
63 const ValueTrue = TagBitTypeOther | TagBitBool | 1
64 const ValueUndefined = TagBitTypeOther | TagBitUndefined
65 const ValueNull = TagBitTypeOther
66 else
67 const Int32Tag = -1
68 const BooleanTag = -2
69 const NullTag = -3
70 const UndefinedTag = -4
71 const CellTag = -5
72 const EmptyValueTag = -6
73 const DeletedValueTag = -7
74 const LowestTag = DeletedValueTag
75 end
76
77 const CallOpCodeSize = 9
78
79 if X86_64 or ARM64 or C_LOOP
80 const maxFrameExtentForSlowPathCall = 0
81 elsif ARM or ARMv7_TRADITIONAL or ARMv7 or SH4
82 const maxFrameExtentForSlowPathCall = 24
83 elsif X86 or X86_WIN
84 const maxFrameExtentForSlowPathCall = 40
85 elsif MIPS
86 const maxFrameExtentForSlowPathCall = 40
87 elsif X86_64_WIN
88 const maxFrameExtentForSlowPathCall = 64
89 end
90
91 # Watchpoint states
92 const ClearWatchpoint = 0
93 const IsWatched = 1
94 const IsInvalidated = 2
95
96 # Some register conventions.
97 if JSVALUE64
98 # - Use a pair of registers to represent the PC: one register for the
99 # base of the bytecodes, and one register for the index.
100 # - The PC base (or PB for short) should be stored in the csr. It will
101 # get clobbered on calls to other JS code, but will get saved on calls
102 # to C functions.
103 # - C calls are still given the Instruction* rather than the PC index.
104 # This requires an add before the call, and a sub after.
105 const PC = t5
106 const PB = t6
107 const tagTypeNumber = csr1
108 const tagMask = csr2
109
110 macro loadisFromInstruction(offset, dest)
111 loadis offset * 8[PB, PC, 8], dest
112 end
113
114 macro loadpFromInstruction(offset, dest)
115 loadp offset * 8[PB, PC, 8], dest
116 end
117
118 macro storepToInstruction(value, offset)
119 storep value, offset * 8[PB, PC, 8]
120 end
121
122 else
123 const PC = t5
124 macro loadisFromInstruction(offset, dest)
125 loadis offset * 4[PC], dest
126 end
127
128 macro loadpFromInstruction(offset, dest)
129 loadp offset * 4[PC], dest
130 end
131 end
132
133 # Constants for reasoning about value representation.
134 if BIG_ENDIAN
135 const TagOffset = 0
136 const PayloadOffset = 4
137 else
138 const TagOffset = 4
139 const PayloadOffset = 0
140 end
141
142 # Constant for reasoning about butterflies.
143 const IsArray = 1
144 const IndexingShapeMask = 30
145 const NoIndexingShape = 0
146 const Int32Shape = 20
147 const DoubleShape = 22
148 const ContiguousShape = 26
149 const ArrayStorageShape = 28
150 const SlowPutArrayStorageShape = 30
151
152 # Type constants.
153 const StringType = 5
154 const ObjectType = 18
155 const FinalObjectType = 19
156
157 # Type flags constants.
158 const MasqueradesAsUndefined = 1
159 const ImplementsHasInstance = 2
160 const ImplementsDefaultHasInstance = 8
161
162 # Bytecode operand constants.
163 const FirstConstantRegisterIndex = 0x40000000
164
165 # Code type constants.
166 const GlobalCode = 0
167 const EvalCode = 1
168 const FunctionCode = 2
169
170 # The interpreter steals the tag word of the argument count.
171 const LLIntReturnPC = ArgumentCount + TagOffset
172
173 # String flags.
174 const HashFlags8BitBuffer = 32
175
176 # Copied from PropertyOffset.h
177 const firstOutOfLineOffset = 100
178
179 # ResolveType
180 const GlobalProperty = 0
181 const GlobalVar = 1
182 const ClosureVar = 2
183 const GlobalPropertyWithVarInjectionChecks = 3
184 const GlobalVarWithVarInjectionChecks = 4
185 const ClosureVarWithVarInjectionChecks = 5
186 const Dynamic = 6
187
188 const ResolveModeMask = 0xffff
189
190 const MarkedBlockSize = 64 * 1024
191 const MarkedBlockMask = ~(MarkedBlockSize - 1)
192 # Constants for checking mark bits.
193 const AtomNumberShift = 3
194 const BitMapWordShift = 4
195
196 # Allocation constants
197 if JSVALUE64
198 const JSFinalObjectSizeClassIndex = 1
199 else
200 const JSFinalObjectSizeClassIndex = 3
201 end
202
203 # This must match wtf/Vector.h
204 const VectorBufferOffset = 0
205 if JSVALUE64
206 const VectorSizeOffset = 12
207 else
208 const VectorSizeOffset = 8
209 end
210
211 # Some common utilities.
212 macro crash()
213 if C_LOOP
214 cloopCrash
215 else
216 call _llint_crash
217 end
218 end
219
220 macro assert(assertion)
221 if ASSERT_ENABLED
222 assertion(.ok)
223 crash()
224 .ok:
225 end
226 end
227
228 macro checkStackPointerAlignment(tempReg, location)
229 if ARM64 or C_LOOP or SH4
230 # ARM64 will check for us!
231 # C_LOOP does not need the alignment, and can use a little perf
232 # improvement from avoiding useless work.
233 # SH4 does not need specific alignment (4 bytes).
234 else
235 if ARM or ARMv7 or ARMv7_TRADITIONAL
236 # ARM can't do logical ops with the sp as a source
237 move sp, tempReg
238 andp 0xf, tempReg
239 else
240 andp sp, 0xf, tempReg
241 end
242 btpz tempReg, .stackPointerOkay
243 move location, tempReg
244 break
245 .stackPointerOkay:
246 end
247 end
248
249 macro preserveCallerPCAndCFR()
250 if C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS or SH4
251 push lr
252 push cfr
253 elsif X86 or X86_WIN or X86_64 or X86_64_WIN
254 push cfr
255 elsif ARM64
256 pushLRAndFP
257 else
258 error
259 end
260 move sp, cfr
261 end
262
263 macro restoreCallerPCAndCFR()
264 move cfr, sp
265 if C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS or SH4
266 pop cfr
267 pop lr
268 elsif X86 or X86_WIN or X86_64 or X86_64_WIN
269 pop cfr
270 elsif ARM64
271 popLRAndFP
272 end
273 end
274
275 macro preserveReturnAddressAfterCall(destinationRegister)
276 if C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or ARM64 or MIPS or SH4
277 # In C_LOOP case, we're only preserving the bytecode vPC.
278 move lr, destinationRegister
279 elsif X86 or X86_WIN or X86_64 or X86_64_WIN
280 pop destinationRegister
281 else
282 error
283 end
284 end
285
286 macro restoreReturnAddressBeforeReturn(sourceRegister)
287 if C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or ARM64 or MIPS or SH4
288 # In C_LOOP case, we're only restoring the bytecode vPC.
289 move sourceRegister, lr
290 elsif X86 or X86_WIN or X86_64 or X86_64_WIN
291 push sourceRegister
292 else
293 error
294 end
295 end
296
297 macro functionPrologue()
298 if X86 or X86_WIN or X86_64 or X86_64_WIN
299 push cfr
300 elsif ARM64
301 pushLRAndFP
302 elsif C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS or SH4
303 push lr
304 push cfr
305 end
306 move sp, cfr
307 end
308
309 macro functionEpilogue()
310 if X86 or X86_WIN or X86_64 or X86_64_WIN
311 pop cfr
312 elsif ARM64
313 popLRAndFP
314 elsif C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS or SH4
315 pop cfr
316 pop lr
317 end
318 end
319
320 macro callToJavaScriptPrologue()
321 if X86_64 or X86_64_WIN
322 push cfr
323 push t0
324 elsif X86 or X86_WIN
325 push cfr
326 elsif ARM64
327 pushLRAndFP
328 elsif C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS or SH4
329 push lr
330 push cfr
331 end
332 pushCalleeSaves
333 if X86
334 subp 12, sp
335 elsif X86_WIN
336 subp 16, sp
337 move sp, t4
338 move t4, t0
339 move t4, t2
340 andp 0xf, t2
341 andp 0xfffffff0, t0
342 move t0, sp
343 storep t4, [sp]
344 elsif ARM or ARMv7 or ARMv7_TRADITIONAL
345 subp 4, sp
346 move sp, t4
347 clrbp t4, 0xf, t5
348 move t5, sp
349 storep t4, [sp]
350 end
351 end
352
353 macro callToJavaScriptEpilogue()
354 if ARMv7
355 addp CallFrameHeaderSlots * 8, cfr, t4
356 move t4, sp
357 else
358 addp CallFrameHeaderSlots * 8, cfr, sp
359 end
360
361 loadp CallerFrame[cfr], cfr
362
363 if X86
364 addp 12, sp
365 elsif X86_WIN
366 pop t4
367 move t4, sp
368 addp 16, sp
369 elsif ARM or ARMv7 or ARMv7_TRADITIONAL
370 pop t4
371 move t4, sp
372 addp 4, sp
373 end
374
375 popCalleeSaves
376 if X86_64 or X86_64_WIN
377 pop t2
378 pop cfr
379 elsif X86 or X86_WIN
380 pop cfr
381 elsif ARM64
382 popLRAndFP
383 elsif C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS or SH4
384 pop cfr
385 pop lr
386 end
387 end
388
389 macro moveStackPointerForCodeBlock(codeBlock, scratch)
390 loadi CodeBlock::m_numCalleeRegisters[codeBlock], scratch
391 lshiftp 3, scratch
392 addp maxFrameExtentForSlowPathCall, scratch
393 if ARMv7
394 subp cfr, scratch, scratch
395 move scratch, sp
396 else
397 subp cfr, scratch, sp
398 end
399 end
400
401 macro restoreStackPointerAfterCall()
402 loadp CodeBlock[cfr], t2
403 moveStackPointerForCodeBlock(t2, t4)
404 end
405
406 macro traceExecution()
407 if EXECUTION_TRACING
408 callSlowPath(_llint_trace)
409 end
410 end
411
412 macro callTargetFunction(callLinkInfo, calleeFramePtr)
413 move calleeFramePtr, sp
414 if C_LOOP
415 cloopCallJSFunction LLIntCallLinkInfo::machineCodeTarget[callLinkInfo]
416 else
417 call LLIntCallLinkInfo::machineCodeTarget[callLinkInfo]
418 end
419 restoreStackPointerAfterCall()
420 dispatchAfterCall()
421 end
422
423 macro slowPathForCall(slowPath)
424 callCallSlowPath(
425 slowPath,
426 macro (callee)
427 btpz t1, .dontUpdateSP
428 if ARMv7
429 addp CallerFrameAndPCSize, t1, t1
430 move t1, sp
431 else
432 addp CallerFrameAndPCSize, t1, sp
433 end
434 .dontUpdateSP:
435 if C_LOOP
436 cloopCallJSFunction callee
437 else
438 call callee
439 end
440 restoreStackPointerAfterCall()
441 dispatchAfterCall()
442 end)
443 end
444
445 macro arrayProfile(cellAndIndexingType, profile, scratch)
446 const cell = cellAndIndexingType
447 const indexingType = cellAndIndexingType
448 loadi JSCell::m_structureID[cell], scratch
449 storei scratch, ArrayProfile::m_lastSeenStructureID[profile]
450 loadb JSCell::m_indexingType[cell], indexingType
451 end
452
453 macro checkMarkByte(cell, scratch1, scratch2, continuation)
454 loadb JSCell::m_gcData[cell], scratch1
455 continuation(scratch1)
456 end
457
458 macro checkSwitchToJIT(increment, action)
459 loadp CodeBlock[cfr], t0
460 baddis increment, CodeBlock::m_llintExecuteCounter + BaselineExecutionCounter::m_counter[t0], .continue
461 action()
462 .continue:
463 end
464
465 macro checkSwitchToJITForEpilogue()
466 checkSwitchToJIT(
467 10,
468 macro ()
469 callSlowPath(_llint_replace)
470 end)
471 end
472
473 macro assertNotConstant(index)
474 assert(macro (ok) bilt index, FirstConstantRegisterIndex, ok end)
475 end
476
477 macro functionForCallCodeBlockGetter(targetRegister)
478 loadp Callee[cfr], targetRegister
479 loadp JSFunction::m_executable[targetRegister], targetRegister
480 loadp FunctionExecutable::m_codeBlockForCall[targetRegister], targetRegister
481 end
482
483 macro functionForConstructCodeBlockGetter(targetRegister)
484 loadp Callee[cfr], targetRegister
485 loadp JSFunction::m_executable[targetRegister], targetRegister
486 loadp FunctionExecutable::m_codeBlockForConstruct[targetRegister], targetRegister
487 end
488
489 macro notFunctionCodeBlockGetter(targetRegister)
490 loadp CodeBlock[cfr], targetRegister
491 end
492
493 macro functionCodeBlockSetter(sourceRegister)
494 storep sourceRegister, CodeBlock[cfr]
495 end
496
497 macro notFunctionCodeBlockSetter(sourceRegister)
498 # Nothing to do!
499 end
500
501 # Do the bare minimum required to execute code. Sets up the PC, leave the CodeBlock*
502 # in t1. May also trigger prologue entry OSR.
503 macro prologue(codeBlockGetter, codeBlockSetter, osrSlowPath, traceSlowPath)
504 # Set up the call frame and check if we should OSR.
505 preserveCallerPCAndCFR()
506
507 if EXECUTION_TRACING
508 subp maxFrameExtentForSlowPathCall, sp
509 callSlowPath(traceSlowPath)
510 addp maxFrameExtentForSlowPathCall, sp
511 end
512 codeBlockGetter(t1)
513 if C_LOOP
514 else
515 baddis 5, CodeBlock::m_llintExecuteCounter + BaselineExecutionCounter::m_counter[t1], .continue
516 if JSVALUE64
517 cCall2(osrSlowPath, cfr, PC)
518 else
519 # We are after the function prologue, but before we have set up sp from the CodeBlock.
520 # Temporarily align stack pointer for this call.
521 subp 8, sp
522 cCall2(osrSlowPath, cfr, PC)
523 addp 8, sp
524 end
525 btpz t0, .recover
526 move cfr, sp # restore the previous sp
527 # pop the callerFrame since we will jump to a function that wants to save it
528 if ARM64
529 popLRAndFP
530 elsif ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS or SH4
531 pop cfr
532 pop lr
533 else
534 pop cfr
535 end
536 jmp t0
537 .recover:
538 codeBlockGetter(t1)
539 .continue:
540 end
541
542 codeBlockSetter(t1)
543
544 moveStackPointerForCodeBlock(t1, t2)
545
546 # Set up the PC.
547 if JSVALUE64
548 loadp CodeBlock::m_instructions[t1], PB
549 move 0, PC
550 else
551 loadp CodeBlock::m_instructions[t1], PC
552 end
553 end
554
555 # Expects that CodeBlock is in t1, which is what prologue() leaves behind.
556 # Must call dispatch(0) after calling this.
557 macro functionInitialization(profileArgSkip)
558 # Profile the arguments. Unfortunately, we have no choice but to do this. This
559 # code is pretty horrendous because of the difference in ordering between
560 # arguments and value profiles, the desire to have a simple loop-down-to-zero
561 # loop, and the desire to use only three registers so as to preserve the PC and
562 # the code block. It is likely that this code should be rewritten in a more
563 # optimal way for architectures that have more than five registers available
564 # for arbitrary use in the interpreter.
565 loadi CodeBlock::m_numParameters[t1], t0
566 addp -profileArgSkip, t0 # Use addi because that's what has the peephole
567 assert(macro (ok) bpgteq t0, 0, ok end)
568 btpz t0, .argumentProfileDone
569 loadp CodeBlock::m_argumentValueProfiles + VectorBufferOffset[t1], t3
570 mulp sizeof ValueProfile, t0, t2 # Aaaaahhhh! Need strength reduction!
571 lshiftp 3, t0
572 addp t2, t3
573 .argumentProfileLoop:
574 if JSVALUE64
575 loadq ThisArgumentOffset - 8 + profileArgSkip * 8[cfr, t0], t2
576 subp sizeof ValueProfile, t3
577 storeq t2, profileArgSkip * sizeof ValueProfile + ValueProfile::m_buckets[t3]
578 else
579 loadi ThisArgumentOffset + TagOffset - 8 + profileArgSkip * 8[cfr, t0], t2
580 subp sizeof ValueProfile, t3
581 storei t2, profileArgSkip * sizeof ValueProfile + ValueProfile::m_buckets + TagOffset[t3]
582 loadi ThisArgumentOffset + PayloadOffset - 8 + profileArgSkip * 8[cfr, t0], t2
583 storei t2, profileArgSkip * sizeof ValueProfile + ValueProfile::m_buckets + PayloadOffset[t3]
584 end
585 baddpnz -8, t0, .argumentProfileLoop
586 .argumentProfileDone:
587
588 # Check stack height.
589 loadi CodeBlock::m_numCalleeRegisters[t1], t0
590 loadp CodeBlock::m_vm[t1], t2
591 lshiftp 3, t0
592 addi maxFrameExtentForSlowPathCall, t0
593 subp cfr, t0, t0
594 bpbeq VM::m_jsStackLimit[t2], t0, .stackHeightOK
595
596 # Stack height check failed - need to call a slow_path.
597 callSlowPath(_llint_stack_check)
598 bpeq t1, 0, .stackHeightOK
599 move t1, cfr
600 .stackHeightOK:
601 end
602
603 macro allocateJSObject(allocator, structure, result, scratch1, slowCase)
604 if ALWAYS_ALLOCATE_SLOW
605 jmp slowCase
606 else
607 const offsetOfFirstFreeCell =
608 MarkedAllocator::m_freeList +
609 MarkedBlock::FreeList::head
610
611 # Get the object from the free list.
612 loadp offsetOfFirstFreeCell[allocator], result
613 btpz result, slowCase
614
615 # Remove the object from the free list.
616 loadp [result], scratch1
617 storep scratch1, offsetOfFirstFreeCell[allocator]
618
619 # Initialize the object.
620 storep 0, JSObject::m_butterfly[result]
621 storeStructureWithTypeInfo(result, structure, scratch1)
622 end
623 end
624
625 macro doReturn()
626 restoreCallerPCAndCFR()
627 ret
628 end
629
630 # stub to call into JavaScript or Native functions
631 # EncodedJSValue callToJavaScript(void* code, ExecState** vmTopCallFrame, ProtoCallFrame* protoFrame)
632 # EncodedJSValue callToNativeFunction(void* code, ExecState** vmTopCallFrame, ProtoCallFrame* protoFrame)
633
634 if C_LOOP
635 _llint_call_to_javascript:
636 else
637 global _callToJavaScript
638 _callToJavaScript:
639 end
640 doCallToJavaScript(makeJavaScriptCall)
641
642
643 if C_LOOP
644 _llint_call_to_native_function:
645 else
646 global _callToNativeFunction
647 _callToNativeFunction:
648 end
649 doCallToJavaScript(makeHostFunctionCall)
650
651
652 if C_LOOP
653 else
654 # void sanitizeStackForVMImpl(VM* vm)
655 global _sanitizeStackForVMImpl
656 _sanitizeStackForVMImpl:
657 if X86_64
658 const vm = t4
659 const address = t1
660 const zeroValue = t0
661 elsif X86_64_WIN
662 const vm = t2
663 const address = t1
664 const zeroValue = t0
665 elsif X86 or X86_WIN
666 const vm = t2
667 const address = t1
668 const zeroValue = t0
669 else
670 const vm = a0
671 const address = t1
672 const zeroValue = t2
673 end
674
675 if X86 or X86_WIN
676 loadp 4[sp], vm
677 end
678
679 loadp VM::m_lastStackTop[vm], address
680 bpbeq sp, address, .zeroFillDone
681
682 move 0, zeroValue
683 .zeroFillLoop:
684 storep zeroValue, [address]
685 addp PtrSize, address
686 bpa sp, address, .zeroFillLoop
687
688 .zeroFillDone:
689 move sp, address
690 storep address, VM::m_lastStackTop[vm]
691 ret
692 end
693
694
695 if C_LOOP
696 # Dummy entry point the C Loop uses to initialize.
697 _llint_entry:
698 crash()
699 else
700 macro initPCRelative(pcBase)
701 if X86_64 or X86_64_WIN
702 call _relativePCBase
703 _relativePCBase:
704 pop pcBase
705 elsif X86 or X86_WIN
706 call _relativePCBase
707 _relativePCBase:
708 pop pcBase
709 loadp 20[sp], t4
710 elsif ARM64
711 elsif ARMv7
712 _relativePCBase:
713 move pc, pcBase
714 subp 3, pcBase # Need to back up the PC and set the Thumb2 bit
715 elsif ARM or ARMv7_TRADITIONAL
716 _relativePCBase:
717 move pc, pcBase
718 subp 8, pcBase
719 elsif MIPS
720 crash() # Need to replace with any initialization steps needed to step up PC relative address calculation
721 elsif SH4
722 mova _relativePCBase, t0
723 move t0, pcBase
724 alignformova
725 _relativePCBase:
726 end
727 end
728
729 macro setEntryAddress(index, label)
730 if X86_64
731 leap (label - _relativePCBase)[t1], t0
732 move index, t2
733 storep t0, [t4, t2, 8]
734 elsif X86_64_WIN
735 leap (label - _relativePCBase)[t1], t0
736 move index, t4
737 storep t0, [t2, t4, 8]
738 elsif X86 or X86_WIN
739 leap (label - _relativePCBase)[t1], t0
740 move index, t2
741 storep t0, [t4, t2, 4]
742 elsif ARM64
743 pcrtoaddr label, t1
744 move index, t2
745 storep t1, [a0, t2, 8]
746 elsif ARM or ARMv7 or ARMv7_TRADITIONAL
747 mvlbl (label - _relativePCBase), t2
748 addp t2, t1, t2
749 move index, t3
750 storep t2, [a0, t3, 4]
751 elsif SH4
752 move (label - _relativePCBase), t2
753 addp t2, t1, t2
754 move index, t3
755 storep t2, [a0, t3, 4]
756 flushcp # Force constant pool flush to avoid "pcrel too far" link error.
757 elsif MIPS
758 crash() # Need to replace with code to turn label into and absolute address and save at index
759 end
760 end
761
762 global _llint_entry
763 # Entry point for the llint to initialize.
764 _llint_entry:
765 functionPrologue()
766 pushCalleeSaves
767 initPCRelative(t1)
768
769 # Include generated bytecode initialization file.
770 include InitBytecodes
771
772 popCalleeSaves
773 functionEpilogue()
774 ret
775 end
776
777 _llint_program_prologue:
778 prologue(notFunctionCodeBlockGetter, notFunctionCodeBlockSetter, _llint_entry_osr, _llint_trace_prologue)
779 dispatch(0)
780
781
782 _llint_eval_prologue:
783 prologue(notFunctionCodeBlockGetter, notFunctionCodeBlockSetter, _llint_entry_osr, _llint_trace_prologue)
784 dispatch(0)
785
786
787 _llint_function_for_call_prologue:
788 prologue(functionForCallCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_call, _llint_trace_prologue_function_for_call)
789 functionInitialization(0)
790 dispatch(0)
791
792
793 _llint_function_for_construct_prologue:
794 prologue(functionForConstructCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_construct, _llint_trace_prologue_function_for_construct)
795 functionInitialization(1)
796 dispatch(0)
797
798
799 _llint_function_for_call_arity_check:
800 prologue(functionForCallCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_call_arityCheck, _llint_trace_arityCheck_for_call)
801 functionArityCheck(.functionForCallBegin, _slow_path_call_arityCheck)
802 .functionForCallBegin:
803 functionInitialization(0)
804 dispatch(0)
805
806
807 _llint_function_for_construct_arity_check:
808 prologue(functionForConstructCodeBlockGetter, functionCodeBlockSetter, _llint_entry_osr_function_for_construct_arityCheck, _llint_trace_arityCheck_for_construct)
809 functionArityCheck(.functionForConstructBegin, _slow_path_construct_arityCheck)
810 .functionForConstructBegin:
811 functionInitialization(1)
812 dispatch(0)
813
814
815 # Value-representation-specific code.
816 if JSVALUE64
817 include LowLevelInterpreter64
818 else
819 include LowLevelInterpreter32_64
820 end
821
822
823 # Value-representation-agnostic code.
824 _llint_op_touch_entry:
825 traceExecution()
826 callSlowPath(_slow_path_touch_entry)
827 dispatch(1)
828
829
830 _llint_op_new_array:
831 traceExecution()
832 callSlowPath(_llint_slow_path_new_array)
833 dispatch(5)
834
835
836 _llint_op_new_array_with_size:
837 traceExecution()
838 callSlowPath(_llint_slow_path_new_array_with_size)
839 dispatch(4)
840
841
842 _llint_op_new_array_buffer:
843 traceExecution()
844 callSlowPath(_llint_slow_path_new_array_buffer)
845 dispatch(5)
846
847
848 _llint_op_new_regexp:
849 traceExecution()
850 callSlowPath(_llint_slow_path_new_regexp)
851 dispatch(3)
852
853
854 _llint_op_less:
855 traceExecution()
856 callSlowPath(_slow_path_less)
857 dispatch(4)
858
859
860 _llint_op_lesseq:
861 traceExecution()
862 callSlowPath(_slow_path_lesseq)
863 dispatch(4)
864
865
866 _llint_op_greater:
867 traceExecution()
868 callSlowPath(_slow_path_greater)
869 dispatch(4)
870
871
872 _llint_op_greatereq:
873 traceExecution()
874 callSlowPath(_slow_path_greatereq)
875 dispatch(4)
876
877
878 _llint_op_mod:
879 traceExecution()
880 callSlowPath(_slow_path_mod)
881 dispatch(4)
882
883
884 _llint_op_typeof:
885 traceExecution()
886 callSlowPath(_slow_path_typeof)
887 dispatch(3)
888
889
890 _llint_op_is_object:
891 traceExecution()
892 callSlowPath(_slow_path_is_object)
893 dispatch(3)
894
895
896 _llint_op_is_function:
897 traceExecution()
898 callSlowPath(_slow_path_is_function)
899 dispatch(3)
900
901
902 _llint_op_in:
903 traceExecution()
904 callSlowPath(_slow_path_in)
905 dispatch(4)
906
907 macro withInlineStorage(object, propertyStorage, continuation)
908 # Indicate that the object is the property storage, and that the
909 # property storage register is unused.
910 continuation(object, propertyStorage)
911 end
912
913 macro withOutOfLineStorage(object, propertyStorage, continuation)
914 loadp JSObject::m_butterfly[object], propertyStorage
915 # Indicate that the propertyStorage register now points to the
916 # property storage, and that the object register may be reused
917 # if the object pointer is not needed anymore.
918 continuation(propertyStorage, object)
919 end
920
921
922 _llint_op_del_by_id:
923 traceExecution()
924 callSlowPath(_llint_slow_path_del_by_id)
925 dispatch(4)
926
927
928 _llint_op_del_by_val:
929 traceExecution()
930 callSlowPath(_llint_slow_path_del_by_val)
931 dispatch(4)
932
933
934 _llint_op_put_by_index:
935 traceExecution()
936 callSlowPath(_llint_slow_path_put_by_index)
937 dispatch(4)
938
939
940 _llint_op_put_getter_setter:
941 traceExecution()
942 callSlowPath(_llint_slow_path_put_getter_setter)
943 dispatch(5)
944
945
946 _llint_op_jtrue:
947 traceExecution()
948 jumpTrueOrFalse(
949 macro (value, target) btinz value, target end,
950 _llint_slow_path_jtrue)
951
952
953 _llint_op_jfalse:
954 traceExecution()
955 jumpTrueOrFalse(
956 macro (value, target) btiz value, target end,
957 _llint_slow_path_jfalse)
958
959
960 _llint_op_jless:
961 traceExecution()
962 compare(
963 macro (left, right, target) bilt left, right, target end,
964 macro (left, right, target) bdlt left, right, target end,
965 _llint_slow_path_jless)
966
967
968 _llint_op_jnless:
969 traceExecution()
970 compare(
971 macro (left, right, target) bigteq left, right, target end,
972 macro (left, right, target) bdgtequn left, right, target end,
973 _llint_slow_path_jnless)
974
975
976 _llint_op_jgreater:
977 traceExecution()
978 compare(
979 macro (left, right, target) bigt left, right, target end,
980 macro (left, right, target) bdgt left, right, target end,
981 _llint_slow_path_jgreater)
982
983
984 _llint_op_jngreater:
985 traceExecution()
986 compare(
987 macro (left, right, target) bilteq left, right, target end,
988 macro (left, right, target) bdltequn left, right, target end,
989 _llint_slow_path_jngreater)
990
991
992 _llint_op_jlesseq:
993 traceExecution()
994 compare(
995 macro (left, right, target) bilteq left, right, target end,
996 macro (left, right, target) bdlteq left, right, target end,
997 _llint_slow_path_jlesseq)
998
999
1000 _llint_op_jnlesseq:
1001 traceExecution()
1002 compare(
1003 macro (left, right, target) bigt left, right, target end,
1004 macro (left, right, target) bdgtun left, right, target end,
1005 _llint_slow_path_jnlesseq)
1006
1007
1008 _llint_op_jgreatereq:
1009 traceExecution()
1010 compare(
1011 macro (left, right, target) bigteq left, right, target end,
1012 macro (left, right, target) bdgteq left, right, target end,
1013 _llint_slow_path_jgreatereq)
1014
1015
1016 _llint_op_jngreatereq:
1017 traceExecution()
1018 compare(
1019 macro (left, right, target) bilt left, right, target end,
1020 macro (left, right, target) bdltun left, right, target end,
1021 _llint_slow_path_jngreatereq)
1022
1023
1024 _llint_op_loop_hint:
1025 traceExecution()
1026 loadp CodeBlock[cfr], t1
1027 loadp CodeBlock::m_vm[t1], t1
1028 loadb VM::watchdog+Watchdog::m_timerDidFire[t1], t0
1029 btbnz t0, .handleWatchdogTimer
1030 .afterWatchdogTimerCheck:
1031 checkSwitchToJITForLoop()
1032 dispatch(1)
1033 .handleWatchdogTimer:
1034 callWatchdogTimerHandler(.throwHandler)
1035 jmp .afterWatchdogTimerCheck
1036 .throwHandler:
1037 jmp _llint_throw_from_slow_path_trampoline
1038
1039 _llint_op_switch_string:
1040 traceExecution()
1041 callSlowPath(_llint_slow_path_switch_string)
1042 dispatch(0)
1043
1044
1045 _llint_op_new_func_exp:
1046 traceExecution()
1047 callSlowPath(_llint_slow_path_new_func_exp)
1048 dispatch(3)
1049
1050
1051 _llint_op_call:
1052 traceExecution()
1053 arrayProfileForCall()
1054 doCall(_llint_slow_path_call)
1055
1056
1057 _llint_op_construct:
1058 traceExecution()
1059 doCall(_llint_slow_path_construct)
1060
1061
1062 _llint_op_call_varargs:
1063 traceExecution()
1064 callSlowPath(_llint_slow_path_size_frame_for_varargs)
1065 branchIfException(_llint_throw_from_slow_path_trampoline)
1066 # calleeFrame in t1
1067 if JSVALUE64
1068 move t1, sp
1069 else
1070 # The calleeFrame is not stack aligned, move down by CallerFrameAndPCSize to align
1071 if ARMv7
1072 subp t1, CallerFrameAndPCSize, t2
1073 move t2, sp
1074 else
1075 subp t1, CallerFrameAndPCSize, sp
1076 end
1077 end
1078 slowPathForCall(_llint_slow_path_call_varargs)
1079
1080 _llint_op_construct_varargs:
1081 traceExecution()
1082 callSlowPath(_llint_slow_path_size_frame_for_varargs)
1083 branchIfException(_llint_throw_from_slow_path_trampoline)
1084 # calleeFrame in t1
1085 if JSVALUE64
1086 move t1, sp
1087 else
1088 # The calleeFrame is not stack aligned, move down by CallerFrameAndPCSize to align
1089 if ARMv7
1090 subp t1, CallerFrameAndPCSize, t2
1091 move t2, sp
1092 else
1093 subp t1, CallerFrameAndPCSize, sp
1094 end
1095 end
1096 slowPathForCall(_llint_slow_path_construct_varargs)
1097
1098
1099 _llint_op_call_eval:
1100 traceExecution()
1101
1102 # Eval is executed in one of two modes:
1103 #
1104 # 1) We find that we're really invoking eval() in which case the
1105 # execution is perfomed entirely inside the slow_path, and it
1106 # returns the PC of a function that just returns the return value
1107 # that the eval returned.
1108 #
1109 # 2) We find that we're invoking something called eval() that is not
1110 # the real eval. Then the slow_path returns the PC of the thing to
1111 # call, and we call it.
1112 #
1113 # This allows us to handle two cases, which would require a total of
1114 # up to four pieces of state that cannot be easily packed into two
1115 # registers (C functions can return up to two registers, easily):
1116 #
1117 # - The call frame register. This may or may not have been modified
1118 # by the slow_path, but the convention is that it returns it. It's not
1119 # totally clear if that's necessary, since the cfr is callee save.
1120 # But that's our style in this here interpreter so we stick with it.
1121 #
1122 # - A bit to say if the slow_path successfully executed the eval and has
1123 # the return value, or did not execute the eval but has a PC for us
1124 # to call.
1125 #
1126 # - Either:
1127 # - The JS return value (two registers), or
1128 #
1129 # - The PC to call.
1130 #
1131 # It turns out to be easier to just always have this return the cfr
1132 # and a PC to call, and that PC may be a dummy thunk that just
1133 # returns the JS value that the eval returned.
1134
1135 slowPathForCall(_llint_slow_path_call_eval)
1136
1137
1138 _llint_generic_return_point:
1139 dispatchAfterCall()
1140
1141
1142 _llint_op_strcat:
1143 traceExecution()
1144 callSlowPath(_slow_path_strcat)
1145 dispatch(4)
1146
1147
1148 _llint_op_get_pnames:
1149 traceExecution()
1150 callSlowPath(_llint_slow_path_get_pnames)
1151 dispatch(0) # The slow_path either advances the PC or jumps us to somewhere else.
1152
1153
1154 _llint_op_push_with_scope:
1155 traceExecution()
1156 callSlowPath(_llint_slow_path_push_with_scope)
1157 dispatch(2)
1158
1159
1160 _llint_op_pop_scope:
1161 traceExecution()
1162 callSlowPath(_llint_slow_path_pop_scope)
1163 dispatch(1)
1164
1165
1166 _llint_op_push_name_scope:
1167 traceExecution()
1168 callSlowPath(_llint_slow_path_push_name_scope)
1169 dispatch(4)
1170
1171
1172 _llint_op_throw:
1173 traceExecution()
1174 callSlowPath(_llint_slow_path_throw)
1175 dispatch(2)
1176
1177
1178 _llint_op_throw_static_error:
1179 traceExecution()
1180 callSlowPath(_llint_slow_path_throw_static_error)
1181 dispatch(3)
1182
1183
1184 _llint_op_profile_will_call:
1185 traceExecution()
1186 loadp CodeBlock[cfr], t0
1187 loadp CodeBlock::m_vm[t0], t0
1188 loadi VM::m_enabledProfiler[t0], t0
1189 btpz t0, .opProfilerWillCallDone
1190 callSlowPath(_llint_slow_path_profile_will_call)
1191 .opProfilerWillCallDone:
1192 dispatch(2)
1193
1194
1195 _llint_op_profile_did_call:
1196 traceExecution()
1197 loadp CodeBlock[cfr], t0
1198 loadp CodeBlock::m_vm[t0], t0
1199 loadi VM::m_enabledProfiler[t0], t0
1200 btpz t0, .opProfilerDidCallDone
1201 callSlowPath(_llint_slow_path_profile_did_call)
1202 .opProfilerDidCallDone:
1203 dispatch(2)
1204
1205
1206 _llint_op_debug:
1207 traceExecution()
1208 loadp CodeBlock[cfr], t0
1209 loadi CodeBlock::m_debuggerRequests[t0], t0
1210 btiz t0, .opDebugDone
1211 callSlowPath(_llint_slow_path_debug)
1212 .opDebugDone:
1213 dispatch(3)
1214
1215
1216 _llint_native_call_trampoline:
1217 nativeCallTrampoline(NativeExecutable::m_function)
1218
1219
1220 _llint_native_construct_trampoline:
1221 nativeCallTrampoline(NativeExecutable::m_constructor)
1222
1223
1224 # Lastly, make sure that we can link even though we don't support all opcodes.
1225 # These opcodes should never arise when using LLInt or either JIT. We assert
1226 # as much.
1227
1228 macro notSupported()
1229 if ASSERT_ENABLED
1230 crash()
1231 else
1232 # We should use whatever the smallest possible instruction is, just to
1233 # ensure that there is a gap between instruction labels. If multiple
1234 # smallest instructions exist, we should pick the one that is most
1235 # likely result in execution being halted. Currently that is the break
1236 # instruction on all architectures we're interested in. (Break is int3
1237 # on Intel, which is 1 byte, and bkpt on ARMv7, which is 2 bytes.)
1238 break
1239 end
1240 end
1241
1242 _llint_op_init_global_const_nop:
1243 dispatch(5)
1244