source: webkit/trunk/Source/JavaScriptCore/offlineasm/cloop.rb

Last change on this file was 288268, checked in by [email protected], 3 years ago

[JSC] Fix non-JIT Windows LLInt
https://bugs.webkit.org/show_bug.cgi?id=235388

Reviewed by Mark Lam.

We should implement cCall3 which calls llint_link_call etc. from LLInt code.
This implementation needs to work on Windows too, so it requires stack modification.
While we do not have a problem on JIT Windows build, it is required for non JIT Windows
build. (If JIT is enabled, LLInt is fine. But if JIT is entirely disabled, this change
is required.)

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::llint_link_call):
(JSC::LLInt::llint_virtual_call):

  • llint/LLIntSlowPaths.h:
  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • offlineasm/cloop.rb:
  • offlineasm/instructions.rb:
File size: 43.2 KB
Line 
1# Copyright (C) 2012-2021 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
24require "config"
25require "ast"
26require "opt"
27
28# The CLoop llint backend is initially based on the ARMv7 backend, and
29# then further enhanced with a few instructions from the x86 backend to
30# support building for X64 targets. Hence, the shape of the generated
31# code and the usage convention of registers will look a lot like the
32# ARMv7 backend's.
33
34def cloopMapType(type)
35 case type
36 when :intptr; ".i()"
37 when :uintptr; ".u()"
38 when :int32; ".i32()"
39 when :uint32; ".u32()"
40 when :int64; ".i64()"
41 when :uint64; ".u64()"
42 when :int8; ".i8()"
43 when :uint8; ".u8()"
44 when :int8Ptr; ".i8p()"
45 when :voidPtr; ".vp()"
46 when :nativeFunc; ".nativeFunc()"
47 when :double; ".d()"
48 when :bitsAsDouble; ".bitsAsDouble()"
49 when :bitsAsInt64; ".bitsAsInt64()"
50 when :opcode; ".opcode()"
51 else;
52 raise "Unsupported type"
53 end
54end
55
56
57class SpecialRegister < NoChildren
58 def clLValue(type=:intptr)
59 clDump
60 end
61 def clDump
62 @name
63 end
64 def clValue(type=:intptr)
65 @name + cloopMapType(type)
66 end
67end
68
69C_LOOP_SCRATCH_FPR = SpecialRegister.new("d6")
70
71class RegisterID
72 def clDump
73 case name
74 # The cloop is modelled on the ARM implementation. Hence, the a0-a3
75 # registers are aliases for r0-r3 i.e. t0-t3 in our case.
76 when "t0", "a0", "r0"
77 "t0"
78 when "t1", "a1", "r1"
79 "t1"
80 when "t2", "a2"
81 "t2"
82 when "t3", "a3"
83 "t3"
84 when "t4"
85 "pc"
86 when "t5"
87 "t5"
88 when "csr0"
89 "pcBase"
90 when "csr1"
91 "numberTag"
92 when "csr2"
93 "notCellMask"
94 when "csr3"
95 "metadataTable"
96 when "cfr"
97 "cfr"
98 when "lr"
99 "lr"
100 when "sp"
101 "sp"
102 else
103 raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
104 end
105 end
106 def clLValue(type=:intptr)
107 clDump
108 end
109 def clValue(type=:intptr)
110 clDump + cloopMapType(type)
111 end
112end
113
114class FPRegisterID
115 def clDump
116 case name
117 when "ft0", "fr"
118 "d0"
119 when "ft1"
120 "d1"
121 when "ft2"
122 "d2"
123 when "ft3"
124 "d3"
125 when "ft4"
126 "d4"
127 when "ft5"
128 "d5"
129 else
130 raise "Bad register #{name} for C_LOOP at #{codeOriginString}"
131 end
132 end
133 def clLValue(type=:intptr)
134 clDump
135 end
136 def clValue(type=:intptr)
137 clDump + cloopMapType(type)
138 end
139end
140
141class Immediate
142 def clDump
143 "#{value}"
144 end
145 def clLValue(type=:intptr)
146 raise "Immediate cannot be used as an LValue"
147 end
148 def clValue(type=:intptr)
149 # There is a case of a very large unsigned number (0x8000000000000000)
150 # which we wish to encode. Unfortunately, the C/C++ compiler
151 # complains if we express that number as a positive decimal integer.
152 # Hence, for positive values, we just convert the number into hex form
153 # to keep the compiler happy.
154 #
155 # However, for negative values, the to_s(16) hex conversion method does
156 # not strip the "-" sign resulting in a meaningless "0x-..." valueStr.
157 # To workaround this, we simply don't encode negative numbers as hex.
158
159 valueStr = (value < 0) ? "#{value}" : "0x#{value.to_s(16)}"
160
161 case type
162 when :int8; "int8_t(#{valueStr})"
163 when :int16; "int16_t(#{valueStr})"
164 when :int32; "int32_t(#{valueStr})"
165 when :int64; "int64_t(#{valueStr})"
166 when :intptr; "intptr_t(#{valueStr})"
167 when :uint8; "uint8_t(#{valueStr})"
168 when :uint32; "uint32_t(#{valueStr})"
169 when :uint64; "uint64_t(#{valueStr})"
170 when :uintptr; "uintptr_t(#{valueStr})"
171 else
172 raise "Not implemented immediate of type: #{type}"
173 end
174 end
175end
176
177class Address
178 def clDump
179 "[#{base.clDump}, #{offset.value}]"
180 end
181 def clLValue(type=:intptr)
182 clValue(type)
183 end
184 def clValue(type=:intptr)
185 case type
186 when :int8; int8MemRef
187 when :int16; int16MemRef
188 when :int32; int32MemRef
189 when :int64; int64MemRef
190 when :intptr; intptrMemRef
191 when :uint8; uint8MemRef
192 when :uint32; uint32MemRef
193 when :uint64; uint64MemRef
194 when :uintptr; uintptrMemRef
195 when :opcode; opcodeMemRef
196 when :nativeFunc; nativeFuncMemRef
197 else
198 raise "Unexpected Address type: #{type}"
199 end
200 end
201 def pointerExpr
202 if offset.value == 0
203 "#{base.clValue(:int8Ptr)}"
204 elsif offset.value > 0
205 "#{base.clValue(:int8Ptr)} + #{offset.value}"
206 else
207 "#{base.clValue(:int8Ptr)} - #{-offset.value}"
208 end
209 end
210 def int8MemRef
211 "*CAST<int8_t*>(#{pointerExpr})"
212 end
213 def int16MemRef
214 "*CAST<int16_t*>(#{pointerExpr})"
215 end
216 def int32MemRef
217 "*CAST<int32_t*>(#{pointerExpr})"
218 end
219 def int64MemRef
220 "*CAST<int64_t*>(#{pointerExpr})"
221 end
222 def intptrMemRef
223 "*CAST<intptr_t*>(#{pointerExpr})"
224 end
225 def uint8MemRef
226 "*CAST<uint8_t*>(#{pointerExpr})"
227 end
228 def uint16MemRef
229 "*CAST<uint16_t*>(#{pointerExpr})"
230 end
231 def uint32MemRef
232 "*CAST<uint32_t*>(#{pointerExpr})"
233 end
234 def uint64MemRef
235 "*CAST<uint64_t*>(#{pointerExpr})"
236 end
237 def uintptrMemRef
238 "*CAST<uintptr_t*>(#{pointerExpr})"
239 end
240 def nativeFuncMemRef
241 "*CAST<NativeFunction*>(#{pointerExpr})"
242 end
243 def opcodeMemRef
244 "*CAST<Opcode*>(#{pointerExpr})"
245 end
246 def dblMemRef
247 "*CAST<double*>(#{pointerExpr})"
248 end
249end
250
251class BaseIndex
252 def clDump
253 "[#{base.clDump}, #{offset.clDump}, #{index.clDump} << #{scaleShift}]"
254 end
255 def clLValue(type=:intptr)
256 clValue(type)
257 end
258 def clValue(type=:intptr)
259 case type
260 when :int8; int8MemRef
261 when :int32; int32MemRef
262 when :int16; int16MemRef
263 when :int64; int64MemRef
264 when :intptr; intptrMemRef
265 when :uint8; uint8MemRef
266 when :uint16; uint16MemRef
267 when :uint32; uint32MemRef
268 when :uint64; uint64MemRef
269 when :uintptr; uintptrMemRef
270 when :opcode; opcodeMemRef
271 else
272 raise "Unexpected BaseIndex type: #{type}"
273 end
274 end
275 def pointerExpr
276 if offset.value == 0
277 "#{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift})"
278 else
279 "#{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift}) + #{offset.clValue}"
280 end
281 end
282 def int8MemRef
283 "*CAST<int8_t*>(#{pointerExpr})"
284 end
285 def int16MemRef
286 "*CAST<int16_t*>(#{pointerExpr})"
287 end
288 def int32MemRef
289 "*CAST<int32_t*>(#{pointerExpr})"
290 end
291 def int64MemRef
292 "*CAST<int64_t*>(#{pointerExpr})"
293 end
294 def intptrMemRef
295 "*CAST<intptr_t*>(#{pointerExpr})"
296 end
297 def uint8MemRef
298 "*CAST<uint8_t*>(#{pointerExpr})"
299 end
300 def uint16MemRef
301 "*CAST<uint16_t*>(#{pointerExpr})"
302 end
303 def uint32MemRef
304 "*CAST<uint32_t*>(#{pointerExpr})"
305 end
306 def uint64MemRef
307 "*CAST<uint64_t*>(#{pointerExpr})"
308 end
309 def uintptrMemRef
310 "*CAST<uintptr_t*>(#{pointerExpr})"
311 end
312 def opcodeMemRef
313 "*CAST<Opcode*>(#{pointerExpr})"
314 end
315 def dblMemRef
316 "*CAST<double*>(#{pointerExpr})"
317 end
318end
319
320class AbsoluteAddress
321 def clDump
322 "#{codeOriginString}"
323 end
324 def clLValue(type=:intptr)
325 clValue(type)
326 end
327 def clValue
328 clDump
329 end
330end
331
332class LabelReference
333 def intptrMemRef
334 "*CAST<intptr_t*>(&#{cLabel})"
335 end
336 def cloopEmitLea(destination, type)
337 $asm.putc "#{destination.clLValue(:voidPtr)} = CAST<void*>(&#{cLabel});"
338 if offset != 0
339 $asm.putc "#{destination.clLValue(:int8Ptr)} = #{destination.clValue(:int8Ptr)} + #{offset};"
340 end
341 end
342end
343
344
345#
346# Lea support.
347#
348
349class Address
350 def cloopEmitLea(destination, type)
351 if destination == base
352 $asm.putc "#{destination.clLValue(:int8Ptr)} = #{destination.clValue(:int8Ptr)} + #{offset.clValue(type)};"
353 else
354 $asm.putc "#{destination.clLValue(:int8Ptr)} = #{base.clValue(:int8Ptr)} + #{offset.clValue(type)};"
355 end
356 end
357end
358
359class BaseIndex
360 def cloopEmitLea(destination, type)
361 raise "Malformed BaseIndex, offset should be zero at #{codeOriginString}" unless offset.value == 0
362 $asm.putc "#{destination.clLValue(:int8Ptr)} = #{base.clValue(:int8Ptr)} + (#{index.clValue} << #{scaleShift});"
363 end
364end
365
366#
367# Actual lowering code follows.
368#
369
370class Sequence
371 def getModifiedListC_LOOP
372 myList = @list
373
374 # Verify that we will only see instructions and labels.
375 myList.each {
376 | node |
377 unless node.is_a? Instruction or
378 node.is_a? Label or
379 node.is_a? LocalLabel or
380 node.is_a? Skip
381 raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
382 end
383 }
384
385 return myList
386 end
387end
388
389def clOperands(operands)
390 operands.map{|v| v.clDump}.join(", ")
391end
392
393
394def cloopEmitOperation(operands, type, operator)
395 raise unless type == :intptr || type == :uintptr || type == :int32 || type == :uint32 || \
396 type == :int64 || type == :uint64 || type == :double || type == :int16
397 if operands.size == 3
398 op1 = operands[0]
399 op2 = operands[1]
400 dst = operands[2]
401 else
402 raise unless operands.size == 2
403 op1 = operands[1]
404 op2 = operands[0]
405 dst = operands[1]
406 end
407 raise unless not dst.is_a? Immediate
408 if dst.is_a? RegisterID and (type == :int32 or type == :uint32)
409 truncationHeader = "(uint32_t)("
410 truncationFooter = ")"
411 elsif dst.is_a? RegisterID and (type == :int16)
412 truncationHeader = "(uint16_t)("
413 truncationFooter = ")"
414 else
415 truncationHeader = ""
416 truncationFooter = ""
417 end
418 $asm.putc "#{dst.clLValue(type)} = #{truncationHeader}#{op1.clValue(type)} #{operator} #{op2.clValue(type)}#{truncationFooter};"
419end
420
421def cloopEmitShiftOperation(operands, type, operator)
422 raise unless type == :intptr || type == :uintptr || type == :int32 || type == :uint32 || type == :int64 || type == :uint64
423 if operands.size == 3
424 op1 = operands[0]
425 op2 = operands[1]
426 dst = operands[2]
427 else
428 op1 = operands[1]
429 op2 = operands[0]
430 dst = operands[1]
431 end
432 if dst.is_a? RegisterID and (type == :int32 or type == :uint32)
433 truncationHeader = "(uint32_t)("
434 truncationFooter = ")"
435 else
436 truncationHeader = ""
437 truncationFooter = ""
438 end
439 shiftMask = "((sizeof(uintptr_t) == 8) ? 0x3f : 0x1f)" if type == :intptr || type == :uintptr
440 shiftMask = "0x3f" if type == :int64 || type == :uint64
441 shiftMask = "0x1f" if type == :int32 || type == :uint32
442 $asm.putc "#{dst.clLValue(type)} = #{truncationHeader}#{operands[1].clValue(type)} #{operator} (#{operands[0].clValue(:intptr)} & #{shiftMask})#{truncationFooter};"
443end
444
445def cloopEmitUnaryOperation(operands, type, operator)
446 raise unless type == :intptr || type == :uintptr || type == :int32 || type == :uint32 || type == :int64 || type == :uint64
447 raise unless operands.size == 1
448 raise unless not operands[0].is_a? Immediate
449 op = operands[0]
450 dst = operands[0]
451 if dst.is_a? RegisterID and (type == :int32 or type == :uint32)
452 truncationHeader = "(uint32_t)("
453 truncationFooter = ")"
454 else
455 truncationHeader = ""
456 truncationFooter = ""
457 end
458 $asm.putc "#{dst.clLValue(type)} = #{truncationHeader}#{operator}#{op.clValue(type)}#{truncationFooter};"
459end
460
461def cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, condition)
462 $asm.putc "if (std::isnan(#{operands[0].clValue(:double)}) || std::isnan(#{operands[1].clValue(:double)})"
463 $asm.putc " || (#{operands[0].clValue(:double)} #{condition} #{operands[1].clValue(:double)}))"
464 $asm.putc " goto #{operands[2].cLabel};"
465end
466
467
468def cloopEmitCompareAndSet(operands, type, comparator)
469 # The result is a boolean. Hence, it doesn't need to be based on the type
470 # of the arguments being compared.
471 $asm.putc "#{operands[2].clLValue(type)} = (#{operands[0].clValue(type)} #{comparator} #{operands[1].clValue(type)});"
472end
473
474
475def cloopEmitCompareAndBranch(operands, type, comparator)
476 $asm.putc "if (#{operands[0].clValue(type)} #{comparator} #{operands[1].clValue(type)})"
477 $asm.putc " goto #{operands[2].cLabel};"
478end
479
480
481# conditionTest should contain a string that provides a comparator and a RHS
482# value e.g. "< 0".
483def cloopGenerateConditionExpression(operands, type, conditionTest)
484 op1 = operands[0].clValue(type)
485
486 # The operands must consist of 2 or 3 values.
487 case operands.size
488 when 2 # Just test op1 against the conditionTest.
489 lhs = op1
490 when 3 # Mask op1 with op2 before testing against the conditionTest.
491 lhs = "(#{op1} & #{operands[1].clValue(type)})"
492 else
493 raise "Expected 2 or 3 operands but got #{operands.size} at #{codeOriginString}"
494 end
495
496 "#{lhs} #{conditionTest}"
497end
498
499# conditionTest should contain a string that provides a comparator and a RHS
500# value e.g. "< 0".
501def cloopEmitTestAndBranchIf(operands, type, conditionTest, branchTarget)
502 conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
503 $asm.putc "if (#{conditionExpr})"
504 $asm.putc " goto #{branchTarget};"
505end
506
507def cloopEmitTestSet(operands, type, conditionTest)
508 # The result is a boolean condition. Hence, the result type is always an
509 # int. The passed in type is only used for the values being tested in
510 # the condition test.
511 conditionExpr = cloopGenerateConditionExpression(operands, type, conditionTest)
512 $asm.putc "#{operands[-1].clLValue} = (#{conditionExpr});"
513end
514
515def cloopEmitOpAndBranch(operands, operator, type, conditionTest)
516 case type
517 when :intptr; tempType = "intptr_t"
518 when :int32; tempType = "int32_t"
519 when :int64; tempType = "int64_t"
520 else
521 raise "Unimplemented type"
522 end
523
524 $asm.putc "{"
525 $asm.putc " #{tempType} temp = #{operands[1].clValue(type)} #{operator} #{operands[0].clValue(type)};"
526 $asm.putc " #{operands[1].clLValue(type)} = temp;"
527 $asm.putc " if (temp #{conditionTest})"
528 $asm.putc " goto #{operands[2].cLabel};"
529 $asm.putc "}"
530end
531
532def cloopEmitOpAndBranchIfOverflow(operands, operator, type)
533 case type
534 when :int32
535 tempType = "int32_t"
536 truncationHeader = "(uint32_t)("
537 truncationFooter = ")"
538 else
539 raise "Unimplemented type"
540 end
541
542 $asm.putc "{"
543
544 # Emit the overflow test based on the operands and the type:
545 case operator
546 when "+"; operation = "add"
547 when "-"; operation = "sub"
548 when "*"; operation = "multiply"
549 else
550 raise "Unimplemented opeartor"
551 end
552
553 $asm.putc " #{tempType} result;"
554 $asm.putc " bool success = WTF::ArithmeticOperations<#{tempType}, #{tempType}, #{tempType}>::#{operation}(#{operands[1].clValue(type)}, #{operands[0].clValue(type)}, result);"
555 $asm.putc " #{operands[1].clLValue(type)} = #{truncationHeader}result#{truncationFooter};"
556 $asm.putc " if (!success)"
557 $asm.putc " goto #{operands[2].cLabel};"
558 $asm.putc "}"
559end
560
561# operands: callTarget, currentFrame, currentPC
562def cloopEmitCallSlowPath(operands)
563 $asm.putc "{"
564 $asm.putc " cloopStack.setCurrentStackPointer(sp.vp());"
565 $asm.putc " SlowPathReturnType result = #{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump});"
566 $asm.putc " decodeResult(result, t0, t1);"
567 $asm.putc "}"
568end
569
570def cloopEmitCallSlowPathVoid(operands)
571 $asm.putc "cloopStack.setCurrentStackPointer(sp.vp());"
572 $asm.putc "#{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump});"
573end
574
575def cloopEmitCallSlowPath3(operands)
576 $asm.putc "{"
577 $asm.putc " cloopStack.setCurrentStackPointer(sp.vp());"
578 $asm.putc " SlowPathReturnType result = #{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump}, #{operands[3].clDump});"
579 $asm.putc " decodeResult(result, t0, t1);"
580 $asm.putc "}"
581end
582
583def cloopEmitCallSlowPath4(operands)
584 $asm.putc "{"
585 $asm.putc " cloopStack.setCurrentStackPointer(sp.vp());"
586 $asm.putc " SlowPathReturnType result = #{operands[0].cLabel}(#{operands[1].clDump}, #{operands[2].clDump}, #{operands[3].clDump}, #{operands[4].clDump});"
587 $asm.putc " decodeResult(result, t0, t1);"
588 $asm.putc "}"
589end
590
591class Instruction
592 def lowerC_LOOP
593 case opcode
594 when "addi"
595 cloopEmitOperation(operands, :int32, "+")
596 when "addq"
597 cloopEmitOperation(operands, :int64, "+")
598 when "addp"
599 cloopEmitOperation(operands, :intptr, "+")
600
601 when "andi"
602 cloopEmitOperation(operands, :int32, "&")
603 when "andq"
604 cloopEmitOperation(operands, :int64, "&")
605 when "andp"
606 cloopEmitOperation(operands, :intptr, "&")
607
608 when "ori"
609 cloopEmitOperation(operands, :int32, "|")
610 when "orq"
611 cloopEmitOperation(operands, :int64, "|")
612 when "orp"
613 cloopEmitOperation(operands, :intptr, "|")
614 when "orh"
615 cloopEmitOperation(operands, :int16, "|")
616
617 when "xori"
618 cloopEmitOperation(operands, :int32, "^")
619 when "xorq"
620 cloopEmitOperation(operands, :int64, "^")
621 when "xorp"
622 cloopEmitOperation(operands, :intptr, "^")
623
624 when "lshifti"
625 cloopEmitShiftOperation(operands, :int32, "<<")
626 when "lshiftq"
627 cloopEmitShiftOperation(operands, :int64, "<<")
628 when "lshiftp"
629 cloopEmitShiftOperation(operands, :intptr, "<<")
630
631 when "rshifti"
632 cloopEmitShiftOperation(operands, :int32, ">>")
633 when "rshiftq"
634 cloopEmitShiftOperation(operands, :int64, ">>")
635 when "rshiftp"
636 cloopEmitShiftOperation(operands, :intptr, ">>")
637
638 when "urshifti"
639 cloopEmitShiftOperation(operands, :uint32, ">>")
640 when "urshiftq"
641 cloopEmitShiftOperation(operands, :uint64, ">>")
642 when "urshiftp"
643 cloopEmitShiftOperation(operands, :uintptr, ">>")
644
645 when "muli"
646 cloopEmitOperation(operands, :int32, "*")
647 when "mulq"
648 cloopEmitOperation(operands, :int64, "*")
649 when "mulp"
650 cloopEmitOperation(operands, :intptr, "*")
651
652 when "subi"
653 cloopEmitOperation(operands, :int32, "-")
654 when "subq"
655 cloopEmitOperation(operands, :int64, "-")
656 when "subp"
657 cloopEmitOperation(operands, :intptr, "-")
658
659 when "negi"
660 cloopEmitUnaryOperation(operands, :int32, "-")
661 when "negq"
662 cloopEmitUnaryOperation(operands, :int64, "-")
663 when "negp"
664 cloopEmitUnaryOperation(operands, :intptr, "-")
665
666 when "noti"
667 cloopEmitUnaryOperation(operands, :int32, "~")
668
669 when "loadi"
670 $asm.putc "#{operands[1].clLValue(:uint32)} = #{operands[0].uint32MemRef};"
671 # There's no need to call clearHighWord() here because the above will
672 # automatically take care of 0 extension.
673 when "loadis"
674 $asm.putc "#{operands[1].clLValue(:int32)} = #{operands[0].int32MemRef};"
675 when "loadq"
676 $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].int64MemRef};"
677 when "loadp"
678 $asm.putc "#{operands[1].clLValue} = #{operands[0].intptrMemRef};"
679 when "storei"
680 $asm.putc "#{operands[1].int32MemRef} = #{operands[0].clValue(:int32)};"
681 when "storeq"
682 $asm.putc "#{operands[1].int64MemRef} = #{operands[0].clValue(:int64)};"
683 when "storep"
684 $asm.putc "#{operands[1].intptrMemRef} = #{operands[0].clValue(:intptr)};"
685 when "loadb"
686 $asm.putc "#{operands[1].clLValue(:intptr)} = #{operands[0].uint8MemRef};"
687 when "loadbsi"
688 $asm.putc "#{operands[1].clLValue(:uint32)} = (uint32_t)((int32_t)#{operands[0].int8MemRef});"
689 when "loadbsq"
690 $asm.putc "#{operands[1].clLValue(:uint64)} = (int64_t)#{operands[0].int8MemRef};"
691 when "storeb"
692 $asm.putc "#{operands[1].uint8MemRef} = #{operands[0].clValue(:int8)};"
693 when "loadh"
694 $asm.putc "#{operands[1].clLValue(:intptr)} = #{operands[0].uint16MemRef};"
695 when "loadhsi"
696 $asm.putc "#{operands[1].clLValue(:uint32)} = (uint32_t)((int32_t)#{operands[0].int16MemRef});"
697 when "loadhsq"
698 $asm.putc "#{operands[1].clLValue(:uint64)} = (int64_t)#{operands[0].int16MemRef};"
699 when "storeh"
700 $asm.putc "*#{operands[1].uint16MemRef} = #{operands[0].clValue(:int16)};"
701 when "loadd"
702 $asm.putc "#{operands[1].clLValue(:double)} = #{operands[0].dblMemRef};"
703 when "stored"
704 $asm.putc "#{operands[1].dblMemRef} = #{operands[0].clValue(:double)};"
705
706 when "addd"
707 cloopEmitOperation(operands, :double, "+")
708 when "divd"
709 cloopEmitOperation(operands, :double, "/")
710 when "subd"
711 cloopEmitOperation(operands, :double, "-")
712 when "muld"
713 cloopEmitOperation(operands, :double, "*")
714
715 # Convert an int value to its double equivalent, and store it in a double register.
716 when "ci2ds"
717 $asm.putc "#{operands[1].clLValue(:double)} = (double)#{operands[0].clValue(:int32)}; // ci2ds"
718
719 when "bdeq"
720 cloopEmitCompareAndBranch(operands, :double, "==")
721 when "bdneq"
722 cloopEmitCompareAndBranch(operands, :double, "!=")
723 when "bdgt"
724 cloopEmitCompareAndBranch(operands, :double, ">");
725 when "bdgteq"
726 cloopEmitCompareAndBranch(operands, :double, ">=");
727 when "bdlt"
728 cloopEmitCompareAndBranch(operands, :double, "<");
729 when "bdlteq"
730 cloopEmitCompareAndBranch(operands, :double, "<=");
731
732 when "bdequn"
733 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "==")
734 when "bdnequn"
735 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "!=")
736 when "bdgtun"
737 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">")
738 when "bdgtequn"
739 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, ">=")
740 when "bdltun"
741 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<")
742 when "bdltequn"
743 cloopEmitCompareDoubleWithNaNCheckAndBranch(operands, "<=")
744
745 when "td2i"
746 $asm.putc "#{operands[1].clLValue(:intptr)} = (uint32_t)(intptr_t)#{operands[0].clValue(:double)}; // td2i"
747
748 when "bcd2i" # operands: srcDbl dstInt slowPath
749 $asm.putc "{ // bcd2i"
750 $asm.putc " double d = #{operands[0].clValue(:double)};"
751 $asm.putc " const int32_t asInt32 = int32_t(d);"
752 $asm.putc " if (asInt32 != d || (!asInt32 && std::signbit(d))) // true for -0.0"
753 $asm.putc " goto #{operands[2].cLabel};"
754 $asm.putc " #{operands[1].clLValue} = (uint32_t)asInt32;"
755 $asm.putc "}"
756
757 when "move"
758 $asm.putc "#{operands[1].clLValue(:intptr)} = #{operands[0].clValue(:intptr)};"
759 when "sxi2q"
760 $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:int32)};"
761 when "zxi2q"
762 $asm.putc "#{operands[1].clLValue(:uint64)} = #{operands[0].clValue(:uint32)};"
763 when "sxb2i"
764 $asm.putc "#{operands[1].clLValue(:int32)} = #{operands[0].clValue(:int8)};"
765 when "sxh2i"
766 $asm.putc "#{operands[1].clLValue(:int32)} = #{operands[0].clValue(:int16)};"
767 when "sxb2q"
768 $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:int8)};"
769 when "sxh2q"
770 $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:int16)};"
771 when "nop"
772 $asm.putc "// nop"
773 when "bbeq"
774 cloopEmitCompareAndBranch(operands, :int8, "==")
775 when "bieq"
776 cloopEmitCompareAndBranch(operands, :int32, "==")
777 when "bqeq"
778 cloopEmitCompareAndBranch(operands, :int64, "==")
779 when "bpeq"
780 cloopEmitCompareAndBranch(operands, :intptr, "==")
781
782 when "bbneq"
783 cloopEmitCompareAndBranch(operands, :int8, "!=")
784 when "bineq"
785 cloopEmitCompareAndBranch(operands, :int32, "!=")
786 when "bqneq"
787 cloopEmitCompareAndBranch(operands, :int64, "!=")
788 when "bpneq"
789 cloopEmitCompareAndBranch(operands, :intptr, "!=")
790
791 when "bba"
792 cloopEmitCompareAndBranch(operands, :uint8, ">")
793 when "bia"
794 cloopEmitCompareAndBranch(operands, :uint32, ">")
795 when "bqa"
796 cloopEmitCompareAndBranch(operands, :uint64, ">")
797 when "bpa"
798 cloopEmitCompareAndBranch(operands, :uintptr, ">")
799
800 when "bbaeq"
801 cloopEmitCompareAndBranch(operands, :uint8, ">=")
802 when "biaeq"
803 cloopEmitCompareAndBranch(operands, :uint32, ">=")
804 when "bqaeq"
805 cloopEmitCompareAndBranch(operands, :uint64, ">=")
806 when "bpaeq"
807 cloopEmitCompareAndBranch(operands, :uintptr, ">=")
808
809 when "bbb"
810 cloopEmitCompareAndBranch(operands, :uint8, "<")
811 when "bib"
812 cloopEmitCompareAndBranch(operands, :uint32, "<")
813 when "bqb"
814 cloopEmitCompareAndBranch(operands, :uint64, "<")
815 when "bpb"
816 cloopEmitCompareAndBranch(operands, :uintptr, "<")
817
818 when "bbbeq"
819 cloopEmitCompareAndBranch(operands, :uint8, "<=")
820 when "bibeq"
821 cloopEmitCompareAndBranch(operands, :uint32, "<=")
822 when "bqbeq"
823 cloopEmitCompareAndBranch(operands, :uint64, "<=")
824 when "bpbeq"
825 cloopEmitCompareAndBranch(operands, :uintptr, "<=")
826
827 when "bbgt"
828 cloopEmitCompareAndBranch(operands, :int8, ">")
829 when "bigt"
830 cloopEmitCompareAndBranch(operands, :int32, ">")
831 when "bqgt"
832 cloopEmitCompareAndBranch(operands, :int64, ">")
833 when "bpgt"
834 cloopEmitCompareAndBranch(operands, :intptr, ">")
835
836 when "bbgteq"
837 cloopEmitCompareAndBranch(operands, :int8, ">=")
838 when "bigteq"
839 cloopEmitCompareAndBranch(operands, :int32, ">=")
840 when "bqgteq"
841 cloopEmitCompareAndBranch(operands, :int64, ">=")
842 when "bpgteq"
843 cloopEmitCompareAndBranch(operands, :intptr, ">=")
844
845 when "bblt"
846 cloopEmitCompareAndBranch(operands, :int8, "<")
847 when "bilt"
848 cloopEmitCompareAndBranch(operands, :int32, "<")
849 when "bqlt"
850 cloopEmitCompareAndBranch(operands, :int64, "<")
851 when "bplt"
852 cloopEmitCompareAndBranch(operands, :intptr, "<")
853
854 when "bblteq"
855 cloopEmitCompareAndBranch(operands, :int8, "<=")
856 when "bilteq"
857 cloopEmitCompareAndBranch(operands, :int32, "<=")
858 when "bqlteq"
859 cloopEmitCompareAndBranch(operands, :int64, "<=")
860 when "bplteq"
861 cloopEmitCompareAndBranch(operands, :intptr, "<=")
862
863 when "btbz"
864 cloopEmitTestAndBranchIf(operands, :int8, "== 0", operands[-1].cLabel)
865 when "btiz"
866 cloopEmitTestAndBranchIf(operands, :int32, "== 0", operands[-1].cLabel)
867 when "btqz"
868 cloopEmitTestAndBranchIf(operands, :int64, "== 0", operands[-1].cLabel)
869 when "btpz"
870 cloopEmitTestAndBranchIf(operands, :intptr, "== 0", operands[-1].cLabel)
871
872 when "btbnz"
873 cloopEmitTestAndBranchIf(operands, :int8, "!= 0", operands[-1].cLabel)
874 when "btinz"
875 cloopEmitTestAndBranchIf(operands, :int32, "!= 0", operands[-1].cLabel)
876 when "btqnz"
877 cloopEmitTestAndBranchIf(operands, :int64, "!= 0", operands[-1].cLabel)
878 when "btpnz"
879 cloopEmitTestAndBranchIf(operands, :intptr, "!= 0", operands[-1].cLabel)
880
881 when "btbs"
882 cloopEmitTestAndBranchIf(operands, :int8, "< 0", operands[-1].cLabel)
883 when "btis"
884 cloopEmitTestAndBranchIf(operands, :int32, "< 0", operands[-1].cLabel)
885 when "btqs"
886 cloopEmitTestAndBranchIf(operands, :int64, "< 0", operands[-1].cLabel)
887 when "btps"
888 cloopEmitTestAndBranchIf(operands, :intptr, "< 0", operands[-1].cLabel)
889
890 # For jmp, we do not want to assume that we have COMPUTED_GOTO support.
891 # Fortunately, the only times we should ever encounter indirect jmps is
892 # when the jmp target is a CLoop opcode (by design).
893 #
894 # Hence, we check if the jmp target is a known label reference. If so,
895 # we can emit a goto directly. If it is not a known target, then we set
896 # the target in the opcode, and dispatch to it via whatever dispatch
897 # mechanism is in used.
898 when "jmp"
899 if operands[0].is_a? LocalLabelReference or operands[0].is_a? LabelReference
900 # Handles jumps local or global labels.
901 $asm.putc "goto #{operands[0].cLabel};"
902 else
903 # Handles jumps to some computed target.
904 # NOTE: must be an opcode handler or a llint glue helper.
905 $asm.putc "opcode = #{operands[0].clValue(:opcode)};"
906 $asm.putc "DISPATCH_OPCODE();"
907 end
908
909 when "call"
910 $asm.putc "CRASH(); // generic call instruction not supported by design!"
911 when "break"
912 $asm.putc "CRASH(); // break instruction not implemented."
913 when "ret"
914 $asm.putc "opcode = lr.opcode();"
915 $asm.putc "DISPATCH_OPCODE();"
916
917 when "cbeq"
918 cloopEmitCompareAndSet(operands, :uint8, "==")
919 when "cieq"
920 cloopEmitCompareAndSet(operands, :uint32, "==")
921 when "cqeq"
922 cloopEmitCompareAndSet(operands, :uint64, "==")
923 when "cpeq"
924 cloopEmitCompareAndSet(operands, :uintptr, "==")
925
926 when "cbneq"
927 cloopEmitCompareAndSet(operands, :uint8, "!=")
928 when "cineq"
929 cloopEmitCompareAndSet(operands, :uint32, "!=")
930 when "cqneq"
931 cloopEmitCompareAndSet(operands, :uint64, "!=")
932 when "cpneq"
933 cloopEmitCompareAndSet(operands, :uintptr, "!=")
934
935 when "cba"
936 cloopEmitCompareAndSet(operands, :uint8, ">")
937 when "cia"
938 cloopEmitCompareAndSet(operands, :uint32, ">")
939 when "cqa"
940 cloopEmitCompareAndSet(operands, :uint64, ">")
941 when "cpa"
942 cloopEmitCompareAndSet(operands, :uintptr, ">")
943
944 when "cbaeq"
945 cloopEmitCompareAndSet(operands, :uint8, ">=")
946 when "ciaeq"
947 cloopEmitCompareAndSet(operands, :uint32, ">=")
948 when "cqaeq"
949 cloopEmitCompareAndSet(operands, :uint64, ">=")
950 when "cpaeq"
951 cloopEmitCompareAndSet(operands, :uintptr, ">=")
952
953 when "cbb"
954 cloopEmitCompareAndSet(operands, :uint8, "<")
955 when "cib"
956 cloopEmitCompareAndSet(operands, :uint32, "<")
957 when "cqb"
958 cloopEmitCompareAndSet(operands, :uint64, "<")
959 when "cpb"
960 cloopEmitCompareAndSet(operands, :uintptr, "<")
961
962 when "cbbeq"
963 cloopEmitCompareAndSet(operands, :uint8, "<=")
964 when "cibeq"
965 cloopEmitCompareAndSet(operands, :uint32, "<=")
966 when "cqbeq"
967 cloopEmitCompareAndSet(operands, :uint64, "<=")
968 when "cpbeq"
969 cloopEmitCompareAndSet(operands, :uintptr, "<=")
970
971 when "cbgt"
972 cloopEmitCompareAndSet(operands, :int8, ">")
973 when "cigt"
974 cloopEmitCompareAndSet(operands, :int32, ">")
975 when "cqgt"
976 cloopEmitCompareAndSet(operands, :int64, ">")
977 when "cpgt"
978 cloopEmitCompareAndSet(operands, :intptr, ">")
979 when "cdgt"
980 cloopEmitCompareAndSet(operands, :double, ">")
981
982 when "cbgteq"
983 cloopEmitCompareAndSet(operands, :int8, ">=")
984 when "cigteq"
985 cloopEmitCompareAndSet(operands, :int32, ">=")
986 when "cqgteq"
987 cloopEmitCompareAndSet(operands, :int64, ">=")
988 when "cpgteq"
989 cloopEmitCompareAndSet(operands, :intptr, ">=")
990 when "cdgteq"
991 cloopEmitCompareAndSet(operands, :double, ">=")
992
993 when "cblt"
994 cloopEmitCompareAndSet(operands, :int8, "<")
995 when "cilt"
996 cloopEmitCompareAndSet(operands, :int32, "<")
997 when "cqlt"
998 cloopEmitCompareAndSet(operands, :int64, "<")
999 when "cplt"
1000 cloopEmitCompareAndSet(operands, :intptr, "<")
1001 when "cdlt"
1002 cloopEmitCompareAndSet(operands, :double, "<")
1003
1004 when "cblteq"
1005 cloopEmitCompareAndSet(operands, :int8, "<=")
1006 when "cilteq"
1007 cloopEmitCompareAndSet(operands, :int32, "<=")
1008 when "cqlteq"
1009 cloopEmitCompareAndSet(operands, :int64, "<=")
1010 when "cplteq"
1011 cloopEmitCompareAndSet(operands, :intptr, "<=")
1012 when "cdlteq"
1013 cloopEmitCompareAndSet(operands, :double, "<=")
1014
1015 when "tbs"
1016 cloopEmitTestSet(operands, :int8, "< 0")
1017 when "tis"
1018 cloopEmitTestSet(operands, :int32, "< 0")
1019 when "tqs"
1020 cloopEmitTestSet(operands, :int64, "< 0")
1021 when "tps"
1022 cloopEmitTestSet(operands, :intptr, "< 0")
1023
1024 when "tbz"
1025 cloopEmitTestSet(operands, :int8, "== 0")
1026 when "tiz"
1027 cloopEmitTestSet(operands, :int32, "== 0")
1028 when "tqz"
1029 cloopEmitTestSet(operands, :int64, "== 0")
1030 when "tpz"
1031 cloopEmitTestSet(operands, :intptr, "== 0")
1032
1033 when "tbnz"
1034 cloopEmitTestSet(operands, :int8, "!= 0")
1035 when "tinz"
1036 cloopEmitTestSet(operands, :int32, "!= 0")
1037 when "tqnz"
1038 cloopEmitTestSet(operands, :int64, "!= 0")
1039 when "tpnz"
1040 cloopEmitTestSet(operands, :intptr, "!= 0")
1041
1042 # 64-bit instruction: cdqi (based on X64)
1043 # Sign extends the lower 32 bits of t0, but put the sign extension into
1044 # the lower 32 bits of t1. Leave the upper 32 bits of t0 and t1 unchanged.
1045 when "cdqi"
1046 $asm.putc "{ // cdqi"
1047 $asm.putc " int64_t temp = t0.i32(); // sign extend the low 32bit"
1048 $asm.putc " t0 = (uint32_t)temp; // low word"
1049 $asm.putc " t1 = (uint32_t)(temp >> 32); // high word"
1050 $asm.putc "}"
1051
1052 # 64-bit instruction: idivi op1 (based on X64)
1053 # Divide a 64-bit integer numerator by the specified denominator.
1054 # The numerator is specified in t0 and t1 as follows:
1055 # 1. low 32 bits of the numerator is in the low 32 bits of t0.
1056 # 2. high 32 bits of the numerator is in the low 32 bits of t1.
1057 #
1058 # The resultant quotient is a signed 32-bit int, and is to be stored
1059 # in the lower 32 bits of t0.
1060 # The resultant remainder is a signed 32-bit int, and is to be stored
1061 # in the lower 32 bits of t1.
1062 when "idivi"
1063 # Divide t1,t0 (EDX,EAX) by the specified arg, and store the remainder in t1,
1064 # and quotient in t0:
1065 $asm.putc "{ // idivi"
1066 $asm.putc " int64_t dividend = (int64_t(t1.u32()) << 32) | t0.u32();"
1067 $asm.putc " int64_t divisor = #{operands[0].clValue(:intptr)};"
1068 $asm.putc " t1 = (uint32_t)(dividend % divisor); // remainder"
1069 $asm.putc " t0 = (uint32_t)(dividend / divisor); // quotient"
1070 $asm.putc "}"
1071
1072 # 32-bit instruction: fii2d int32LoOp int32HiOp dblOp (based on ARMv7)
1073 # Decode 2 32-bit ints (low and high) into a 64-bit double.
1074 when "fii2d"
1075 $asm.putc "#{operands[2].clLValue(:double)} = ints2Double(#{operands[0].clValue(:uint32)}, #{operands[1].clValue(:uint32)}); // fii2d"
1076
1077 # 32-bit instruction: f2dii dblOp int32LoOp int32HiOp (based on ARMv7)
1078 # Encode a 64-bit double into 2 32-bit ints (low and high).
1079 when "fd2ii"
1080 $asm.putc "double2Ints(#{operands[0].clValue(:double)}, #{operands[1].clDump}, #{operands[2].clDump}); // fd2ii"
1081
1082 # 64-bit instruction: fq2d int64Op dblOp (based on X64)
1083 # Copy a bit-encoded double in a 64-bit int register to a double register.
1084 when "fq2d"
1085 $asm.putc "#{operands[1].clLValue(:double)} = #{operands[0].clValue(:bitsAsDouble)}; // fq2d"
1086
1087 # 64-bit instruction: fd2q dblOp int64Op (based on X64 instruction set)
1088 # Copy a double as a bit-encoded double into a 64-bit int register.
1089 when "fd2q"
1090 $asm.putc "#{operands[1].clLValue(:int64)} = #{operands[0].clValue(:bitsAsInt64)}; // fd2q"
1091
1092 when "leai"
1093 operands[0].cloopEmitLea(operands[1], :int32)
1094 when "leap"
1095 operands[0].cloopEmitLea(operands[1], :intptr)
1096
1097 when "baddio"
1098 cloopEmitOpAndBranchIfOverflow(operands, "+", :int32)
1099 when "bsubio"
1100 cloopEmitOpAndBranchIfOverflow(operands, "-", :int32)
1101 when "bmulio"
1102 cloopEmitOpAndBranchIfOverflow(operands, "*", :int32)
1103
1104 when "baddis"
1105 cloopEmitOpAndBranch(operands, "+", :int32, "< 0")
1106 when "baddiz"
1107 cloopEmitOpAndBranch(operands, "+", :int32, "== 0")
1108 when "baddinz"
1109 cloopEmitOpAndBranch(operands, "+", :int32, "!= 0")
1110
1111 when "baddqs"
1112 cloopEmitOpAndBranch(operands, "+", :int64, "< 0")
1113 when "baddqz"
1114 cloopEmitOpAndBranch(operands, "+", :int64, "== 0")
1115 when "baddqnz"
1116 cloopEmitOpAndBranch(operands, "+", :int64, "!= 0")
1117
1118 when "baddps"
1119 cloopEmitOpAndBranch(operands, "+", :intptr, "< 0")
1120 when "baddpz"
1121 cloopEmitOpAndBranch(operands, "+", :intptr, "== 0")
1122 when "baddpnz"
1123 cloopEmitOpAndBranch(operands, "+", :intptr, "!= 0")
1124
1125 when "bsubis"
1126 cloopEmitOpAndBranch(operands, "-", :int32, "< 0")
1127 when "bsubiz"
1128 cloopEmitOpAndBranch(operands, "-", :int32, "== 0")
1129 when "bsubinz"
1130 cloopEmitOpAndBranch(operands, "-", :int32, "!= 0")
1131
1132 when "borris"
1133 cloopEmitOpAndBranch(operands, "|", :int32, "< 0")
1134 when "borriz"
1135 cloopEmitOpAndBranch(operands, "|", :int32, "== 0")
1136 when "borrinz"
1137 cloopEmitOpAndBranch(operands, "|", :int32, "!= 0")
1138
1139 when "memfence"
1140
1141 when "push"
1142 operands.each {
1143 | op |
1144 $asm.putc "PUSH(#{op.clDump});"
1145 }
1146 when "pop"
1147 operands.each {
1148 | op |
1149 $asm.putc "POP(#{op.clDump});"
1150 }
1151
1152
1153 # A convenience and compact call to crash because we don't want to use
1154 # the generic llint crash mechanism which relies on the availability
1155 # of the call instruction (which cannot be implemented in a generic
1156 # way, and can be abused if we made it just work for this special case).
1157 # Using a special cloopCrash instruction is cleaner.
1158 when "cloopCrash"
1159 $asm.putc "CRASH();"
1160
1161 # We can't rely on the llint JS call mechanism which actually makes
1162 # use of the call instruction. Instead, we just implement JS calls
1163 # as an opcode dispatch.
1164 when "cloopCallJSFunction"
1165 uid = $asm.newUID
1166 $asm.putc "lr = getOpcode(llint_cloop_did_return_from_js_#{uid});"
1167 $asm.putc "opcode = #{operands[0].clValue(:opcode)};"
1168 $asm.putc "DISPATCH_OPCODE();"
1169 $asm.putsLabel("llint_cloop_did_return_from_js_#{uid}", false)
1170
1171 # We can't do generic function calls with an arbitrary set of args, but
1172 # fortunately we don't have to here. All native function calls always
1173 # have a fixed prototype of 2 args: the passed JSGlobalObject* and CallFrame*.
1174 when "cloopCallNative"
1175 $asm.putc "cloopStack.setCurrentStackPointer(sp.vp());"
1176 $asm.putc "nativeFunc = #{operands[0].clValue(:nativeFunc)};"
1177 $asm.putc "functionReturnValue = JSValue::decode(nativeFunc(jsCast<JSGlobalObject*>(t0.cell()), t1.callFrame()));"
1178 $asm.putc "#if USE(JSVALUE32_64)"
1179 $asm.putc " t1 = functionReturnValue.tag();"
1180 $asm.putc " t0 = functionReturnValue.payload();"
1181 $asm.putc "#else // USE_JSVALUE64)"
1182 $asm.putc " t0 = JSValue::encode(functionReturnValue);"
1183 $asm.putc "#endif // USE_JSVALUE64)"
1184
1185 # We can't do generic function calls with an arbitrary set of args, but
1186 # fortunately we don't have to here. All slow path function calls always
1187 # have a fixed prototype too. See cloopEmitCallSlowPath() for details.
1188 when "cloopCallSlowPath"
1189 cloopEmitCallSlowPath(operands)
1190
1191 when "cloopCallSlowPathVoid"
1192 cloopEmitCallSlowPathVoid(operands)
1193
1194 when "cloopCallSlowPath3"
1195 cloopEmitCallSlowPath3(operands)
1196
1197 when "cloopCallSlowPath4"
1198 cloopEmitCallSlowPath4(operands)
1199
1200 # For debugging only. This is used to insert instrumentation into the
1201 # generated LLIntAssembly.h during llint development only. Do not use
1202 # for production code.
1203 when "cloopDo"
1204 $asm.putc "#{annotation}"
1205
1206 else
1207 lowerDefault
1208 end
1209 end
1210
1211 def lowerC_LOOP_WIN
1212 lowerC_LOOP
1213 end
1214
1215 def recordMetaDataC_LOOP
1216 $asm.codeOrigin codeOriginString if $enableCodeOriginComments
1217 $asm.annotation annotation if $enableInstrAnnotations && (opcode != "cloopDo")
1218 end
1219end
Note: See TracBrowser for help on using the repository browser.