36d61a041484d05e1a642ee116fc0e21a21e2dc6
[WebKit-https.git] / Source / JavaScriptCore / wasm / WASMFunctionCompiler.h
1 /*
2  * Copyright (C) 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef WASMFunctionCompiler_h
27 #define WASMFunctionCompiler_h
28
29 #if ENABLE(WEBASSEMBLY)
30
31 #include "BinarySwitch.h"
32 #include "CCallHelpers.h"
33 #include "JIT.h"
34 #include "JITOperations.h"
35 #include "LinkBuffer.h"
36 #include "MaxFrameExtentForSlowPathCall.h"
37
38 #define UNUSED 0
39
40 namespace JSC {
41
42 static int32_t JIT_OPERATION operationConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
43 {
44     return JSValue::decode(value).toInt32(exec);
45 }
46
47 static double JIT_OPERATION operationConvertJSValueToDouble(ExecState* exec, EncodedJSValue value)
48 {
49     return JSValue::decode(value).toNumber(exec);
50 }
51
52 #if !CPU(X86) && !CPU(X86_64)
53 static int32_t JIT_OPERATION operationDiv(int32_t left, int32_t right)
54 {
55     return left / right;
56 }
57
58 static int32_t JIT_OPERATION operationMod(int32_t left, int32_t right)
59 {
60     return left % right;
61 }
62
63 static uint32_t JIT_OPERATION operationUnsignedDiv(uint32_t left, uint32_t right)
64 {
65     return left / right;
66 }
67
68 static uint32_t JIT_OPERATION operationUnsignedMod(uint32_t left, uint32_t right)
69 {
70     return left % right;
71 }
72 #endif
73
74 #if !USE(JSVALUE64)
75 static double JIT_OPERATION operationConvertUnsignedInt32ToDouble(uint32_t value)
76 {
77     return static_cast<double>(value);
78 }
79 #endif
80
81 class WASMFunctionCompiler : private CCallHelpers {
82 public:
83     typedef int Expression;
84     typedef int Statement;
85     typedef int ExpressionList;
86     struct JumpTarget {
87         Label label;
88         JumpList jumpList;
89     };
90     enum class JumpCondition { Zero, NonZero };
91
92     WASMFunctionCompiler(VM& vm, CodeBlock* codeBlock, JSWASMModule* module, unsigned stackHeight)
93         : CCallHelpers(&vm, codeBlock)
94         , m_module(module)
95         , m_stackHeight(stackHeight)
96     {
97     }
98
99     void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables)
100     {
101         m_calleeSaveSpace = WTF::roundUpToMultipleOf(sizeof(StackSlot), RegisterSet::webAssemblyCalleeSaveRegisters().numberOfSetRegisters() * sizeof(void*));
102         m_codeBlock->setCalleeSaveRegisters(RegisterSet::webAssemblyCalleeSaveRegisters());
103
104         emitFunctionPrologue();
105         emitPutImmediateToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
106
107         m_beginLabel = label();
108
109         addPtr(TrustedImm32(-m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, GPRInfo::regT1);
110         m_stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), GPRInfo::regT1);
111
112         move(GPRInfo::regT1, stackPointerRegister);
113         checkStackPointerAlignment();
114
115         emitSaveCalleeSaves();
116         emitMaterializeTagCheckRegisters();
117
118         m_numberOfLocals = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables;
119
120         unsigned localIndex = 0;
121         for (size_t i = 0; i < arguments.size(); ++i) {
122             // FIXME: No need to do type conversion if the caller is a WebAssembly function.
123             // https://bugs.webkit.org/show_bug.cgi?id=149310
124             Address address(GPRInfo::callFrameRegister, CallFrame::argumentOffset(i) * sizeof(Register));
125 #if USE(JSVALUE64)
126             JSValueRegs valueRegs(GPRInfo::regT0);
127 #else
128             JSValueRegs valueRegs(GPRInfo::regT1, GPRInfo::regT0);
129 #endif
130             loadValue(address, valueRegs);
131             switch (arguments[i]) {
132             case WASMType::I32:
133                 convertValueToInt32(valueRegs, GPRInfo::regT0);
134                 store32(GPRInfo::regT0, localAddress(localIndex++));
135                 break;
136             case WASMType::F32:
137             case WASMType::F64:
138 #if USE(JSVALUE64)
139                 convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::regT1);
140 #else
141                 convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::regT2, FPRInfo::fpRegT1);
142 #endif
143                 if (arguments[i] == WASMType::F32)
144                     convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
145                 storeDouble(FPRInfo::fpRegT0, localAddress(localIndex++));
146                 break;
147             default:
148                 ASSERT_NOT_REACHED();
149             }
150         }
151         for (uint32_t i = 0; i < numberOfI32LocalVariables; ++i)
152             store32(TrustedImm32(0), localAddress(localIndex++));
153         for (uint32_t i = 0; i < numberOfF32LocalVariables; ++i)
154             store32(TrustedImm32(0), localAddress(localIndex++));
155         for (uint32_t i = 0; i < numberOfF64LocalVariables; ++i) {
156 #if USE(JSVALUE64)
157             store64(TrustedImm64(0), localAddress(localIndex++));
158 #else
159             store32(TrustedImm32(0), localAddress(localIndex));
160             store32(TrustedImm32(0), localAddress(localIndex).withOffset(4));
161             localIndex++;
162 #endif
163         }
164
165         m_codeBlock->setNumParameters(1 + arguments.size());
166     }
167
168     void endFunction()
169     {
170         ASSERT(!m_tempStackTop);
171
172         // FIXME: Remove these if the last statement is a return statement.
173 #if USE(JSVALUE64)
174         JSValueRegs returnValueRegs(GPRInfo::returnValueGPR);
175 #else
176         JSValueRegs returnValueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
177 #endif
178         moveTrustedValue(jsUndefined(), returnValueRegs);
179         emitRestoreCalleeSaves();
180         emitFunctionEpilogue();
181         ret();
182
183         m_stackOverflow.link(this);
184         if (maxFrameExtentForSlowPathCall)
185             addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister);
186         setupArgumentsWithExecState(TrustedImmPtr(m_codeBlock));
187         appendCallWithExceptionCheck(operationThrowStackOverflowError);
188
189         // FIXME: Implement arity check.
190         Label arityCheck = label();
191         emitFunctionPrologue();
192         emitPutImmediateToCallFrameHeader(m_codeBlock, JSStack::CodeBlock);
193         jump(m_beginLabel);
194
195         if (!m_divideErrorJumpList.empty()) {
196             m_divideErrorJumpList.link(this);
197
198             setupArgumentsExecState();
199             appendCallWithExceptionCheck(operationThrowDivideError);
200         }
201
202         if (!m_exceptionChecks.empty()) {
203             m_exceptionChecks.link(this);
204
205             copyCalleeSavesToVMCalleeSavesBuffer();
206
207             // lookupExceptionHandler is passed two arguments, the VM and the exec (the CallFrame*).
208             move(TrustedImmPtr(vm()), GPRInfo::argumentGPR0);
209             move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
210
211 #if CPU(X86)
212             // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer!
213             poke(GPRInfo::argumentGPR0);
214             poke(GPRInfo::argumentGPR1, 1);
215 #endif
216             m_calls.append(std::make_pair(call(), FunctionPtr(lookupExceptionHandlerFromCallerFrame).value()));
217             jumpToExceptionHandler();
218         }
219
220         LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock, JITCompilationMustSucceed);
221
222         for (const auto& iterator : m_calls)
223             patchBuffer.link(iterator.first, FunctionPtr(iterator.second));
224
225         for (size_t i = 0; i < m_callCompilationInfo.size(); ++i) {
226             CallCompilationInfo& compilationInfo = m_callCompilationInfo[i];
227             CallLinkInfo& info = *compilationInfo.callLinkInfo;
228             info.setCallLocations(patchBuffer.locationOfNearCall(compilationInfo.callReturnLocation),
229                 patchBuffer.locationOf(compilationInfo.hotPathBegin),
230                 patchBuffer.locationOfNearCall(compilationInfo.hotPathOther));
231         }
232
233         MacroAssemblerCodePtr withArityCheck = patchBuffer.locationOf(arityCheck);
234         CodeRef result = FINALIZE_CODE(patchBuffer, ("Baseline JIT code for WebAssembly"));
235         m_codeBlock->setJITCode(adoptRef(new DirectJITCode(result, withArityCheck, JITCode::BaselineJIT)));
236         m_codeBlock->capabilityLevel();
237     }
238
239     void buildSetLocal(uint32_t localIndex, int, WASMType type)
240     {
241         switch (type) {
242         case WASMType::I32:
243         case WASMType::F32:
244             load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
245             m_tempStackTop--;
246             store32(GPRInfo::regT0, localAddress(localIndex));
247             break;
248         case WASMType::F64:
249             loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
250             m_tempStackTop--;
251             storeDouble(FPRInfo::fpRegT0, localAddress(localIndex));
252             break;
253         default:
254             ASSERT_NOT_REACHED();
255         }
256     }
257
258     void buildSetGlobal(uint32_t globalIndex, int, WASMType type)
259     {
260         move(TrustedImmPtr(&m_module->globalVariables()[globalIndex]), GPRInfo::regT0);
261         switch (type) {
262         case WASMType::I32:
263         case WASMType::F32:
264             load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
265             store32(GPRInfo::regT1, GPRInfo::regT0);
266             break;
267         case WASMType::F64:
268             loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
269             storeDouble(FPRInfo::fpRegT0, GPRInfo::regT0);
270             break;
271         default:
272             ASSERT_NOT_REACHED();
273         }
274         m_tempStackTop--;
275     }
276
277     void buildReturn(int, WASMExpressionType returnType)
278     {
279 #if USE(JSVALUE64)
280         JSValueRegs returnValueRegs(GPRInfo::returnValueGPR);
281 #else
282         JSValueRegs returnValueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
283 #endif
284         switch (returnType) {
285         case WASMExpressionType::I32:
286             load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::returnValueGPR);
287 #if USE(JSVALUE64)
288             or64(GPRInfo::tagTypeNumberRegister, GPRInfo::returnValueGPR);
289 #else
290             move(TrustedImm32(JSValue::Int32Tag), GPRInfo::returnValueGPR2);
291 #endif
292             m_tempStackTop--;
293             break;
294         case WASMExpressionType::F32:
295         case WASMExpressionType::F64:
296             loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
297             if (returnType == WASMExpressionType::F32)
298                 convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
299             convertDoubleToValue(FPRInfo::fpRegT0, returnValueRegs);
300             m_tempStackTop--;
301             break;
302         case WASMExpressionType::Void:
303             moveTrustedValue(jsUndefined(), returnValueRegs);
304             break;
305         default:
306             ASSERT_NOT_REACHED();
307         }
308         emitRestoreCalleeSaves();
309         emitFunctionEpilogue();
310         ret();
311     }
312
313     int buildImmediateI32(uint32_t immediate)
314     {
315         store32(Imm32(immediate), temporaryAddress(m_tempStackTop++));
316         return UNUSED;
317     }
318
319     int buildImmediateF32(float immediate)
320     {
321         store32(Imm32(bitwise_cast<int32_t>(immediate)), temporaryAddress(m_tempStackTop++));
322         return UNUSED;
323     }
324
325     int buildImmediateF64(double immediate)
326     {
327 #if USE(JSVALUE64)
328         store64(Imm64(bitwise_cast<int64_t>(immediate)), temporaryAddress(m_tempStackTop++));
329 #else
330         union {
331             double doubleValue;
332             int32_t int32Values[2];
333         } u = { immediate };
334         m_tempStackTop++;
335         store32(Imm32(u.int32Values[0]), temporaryAddress(m_tempStackTop - 1));
336         store32(Imm32(u.int32Values[1]), temporaryAddress(m_tempStackTop - 1).withOffset(4));
337 #endif
338         return UNUSED;
339     }
340
341     int buildGetLocal(uint32_t localIndex, WASMType type)
342     {
343         switch (type) {
344         case WASMType::I32:
345         case WASMType::F32:
346             load32(localAddress(localIndex), GPRInfo::regT0);
347             store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++));
348             break;
349         case WASMType::F64:
350             loadDouble(localAddress(localIndex), FPRInfo::fpRegT0);
351             storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++));
352             break;
353         default:
354             ASSERT_NOT_REACHED();
355         }
356         return UNUSED;
357     }
358
359     int buildGetGlobal(uint32_t globalIndex, WASMType type)
360     {
361         move(TrustedImmPtr(&m_module->globalVariables()[globalIndex]), GPRInfo::regT0);
362         switch (type) {
363         case WASMType::I32:
364         case WASMType::F32:
365             load32(GPRInfo::regT0, GPRInfo::regT0);
366             store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++));
367             break;
368         case WASMType::F64:
369             loadDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
370             storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++));
371             break;
372         default:
373             ASSERT_NOT_REACHED();
374         }
375         return UNUSED;
376     }
377
378     int buildConvertType(int, WASMExpressionType fromType, WASMExpressionType toType, WASMTypeConversion conversion)
379     {
380         switch (fromType) {
381         case WASMExpressionType::I32:
382             load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
383             ASSERT(toType == WASMExpressionType::F32 || toType == WASMExpressionType::F64);
384             if (conversion == WASMTypeConversion::ConvertSigned)
385                 convertInt32ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
386             else {
387                 ASSERT(conversion == WASMTypeConversion::ConvertUnsigned);
388 #if USE(JSVALUE64)
389                 convertInt64ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
390 #else
391                 callOperation(operationConvertUnsignedInt32ToDouble, GPRInfo::regT0, FPRInfo::fpRegT0);
392 #endif
393             }
394             if (toType == WASMExpressionType::F32)
395                 convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
396             storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
397             break;
398         case WASMExpressionType::F32:
399             loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
400             switch (toType) {
401             case WASMExpressionType::I32:
402                 ASSERT(conversion == WASMTypeConversion::ConvertSigned);
403                 convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
404                 truncateDoubleToInt32(FPRInfo::fpRegT0, GPRInfo::regT0);
405                 store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
406                 break;
407             case WASMExpressionType::F64:
408                 ASSERT(conversion == WASMTypeConversion::Promote);
409                 convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
410                 storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
411                 break;
412             default:
413                 ASSERT_NOT_REACHED();
414             }
415             break;
416         case WASMExpressionType::F64:
417             loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0);
418             switch (toType) {
419             case WASMExpressionType::I32:
420                 ASSERT(conversion == WASMTypeConversion::ConvertSigned);
421                 truncateDoubleToInt32(FPRInfo::fpRegT0, GPRInfo::regT0);
422                 store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
423                 break;
424             case WASMExpressionType::F32:
425                 ASSERT(conversion == WASMTypeConversion::Demote);
426                 convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
427                 storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
428                 break;
429             default:
430                 ASSERT_NOT_REACHED();
431             }
432             break;
433         default:
434             ASSERT_NOT_REACHED();
435         }
436         return UNUSED;
437     }
438
439     int buildUnaryI32(int, WASMOpExpressionI32 op)
440     {
441         load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
442         switch (op) {
443         case WASMOpExpressionI32::Negate:
444             neg32(GPRInfo::regT0);
445             break;
446         case WASMOpExpressionI32::BitNot:
447             xor32(TrustedImm32(-1), GPRInfo::regT0);
448             break;
449         case WASMOpExpressionI32::CountLeadingZeros:
450             countLeadingZeros32(GPRInfo::regT0, GPRInfo::regT0);
451             break;
452         case WASMOpExpressionI32::LogicalNot: {
453             // FIXME: Don't use branches.
454             Jump zero = branchTest32(Zero, GPRInfo::regT0);
455             move(TrustedImm32(0), GPRInfo::regT0);
456             Jump end = jump();
457             zero.link(this);
458             move(TrustedImm32(1), GPRInfo::regT0);
459             end.link(this);
460             break;
461         }
462         case WASMOpExpressionI32::Abs: {
463             // FIXME: Don't use branches.
464             Jump end = branchTest32(PositiveOrZero, GPRInfo::regT0);
465             neg32(GPRInfo::regT0);
466             end.link(this);
467             break;
468         }
469         default:
470             ASSERT_NOT_REACHED();
471         }
472         store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
473         return UNUSED;
474     }
475
476     int buildUnaryF32(int, WASMOpExpressionF32 op)
477     {
478         loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
479         switch (op) {
480         case WASMOpExpressionF32::Negate:
481             convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
482             negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
483             convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
484             break;
485         case WASMOpExpressionF32::Abs:
486             convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
487             absDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
488             convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
489             break;
490         case WASMOpExpressionF32::Ceil:
491             callOperation(ceilf, FPRInfo::fpRegT1, FPRInfo::fpRegT0);
492             break;
493         case WASMOpExpressionF32::Floor:
494             callOperation(floorf, FPRInfo::fpRegT1, FPRInfo::fpRegT0);
495             break;
496         case WASMOpExpressionF32::Sqrt:
497             convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
498             sqrtDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
499             convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
500             break;
501         default:
502             ASSERT_NOT_REACHED();
503         }
504         storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
505         return UNUSED;
506     }
507
508     int buildBinaryI32(int, int, WASMOpExpressionI32 op)
509     {
510         load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0);
511         load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
512         switch (op) {
513         case WASMOpExpressionI32::Add:
514             add32(GPRInfo::regT1, GPRInfo::regT0);
515             break;
516         case WASMOpExpressionI32::Sub:
517             sub32(GPRInfo::regT1, GPRInfo::regT0);
518             break;
519         case WASMOpExpressionI32::Mul:
520             mul32(GPRInfo::regT1, GPRInfo::regT0);
521             break;
522         case WASMOpExpressionI32::SDiv:
523         case WASMOpExpressionI32::UDiv:
524         case WASMOpExpressionI32::SMod:
525         case WASMOpExpressionI32::UMod: {
526             m_divideErrorJumpList.append(branchTest32(Zero, GPRInfo::regT1));
527             if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) {
528                 Jump denominatorNotNeg1 = branch32(NotEqual, GPRInfo::regT1, TrustedImm32(-1));
529                 m_divideErrorJumpList.append(branch32(Equal, GPRInfo::regT0, TrustedImm32(-2147483647-1)));
530                 denominatorNotNeg1.link(this);
531             }
532 #if CPU(X86) || CPU(X86_64)
533             ASSERT(GPRInfo::regT0 == X86Registers::eax);
534             move(GPRInfo::regT1, X86Registers::ecx);
535             if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) {
536                 m_assembler.cdq();
537                 m_assembler.idivl_r(X86Registers::ecx);
538             } else {
539                 ASSERT(op == WASMOpExpressionI32::UDiv || op == WASMOpExpressionI32::UMod);
540                 xor32(X86Registers::edx, X86Registers::edx);
541                 m_assembler.divl_r(X86Registers::ecx);
542             }
543             if (op == WASMOpExpressionI32::SMod || op == WASMOpExpressionI32::UMod)
544                 move(X86Registers::edx, GPRInfo::regT0);
545 #else
546             // FIXME: We should be able to do an inline div on ARMv7 and ARM64.
547             switch (op) {
548             case WASMOpExpressionI32::SDiv:
549                 callOperation(operationDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
550                 break;
551             case WASMOpExpressionI32::UDiv:
552                 callOperation(operationUnsignedDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
553                 break;
554             case WASMOpExpressionI32::SMod:
555                 callOperation(operationMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
556                 break;
557             case WASMOpExpressionI32::UMod:
558                 callOperation(operationUnsignedMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
559                 break;
560             default:
561                 ASSERT_NOT_REACHED();
562             }
563 #endif
564             break;
565         }
566         case WASMOpExpressionI32::BitOr:
567             or32(GPRInfo::regT1, GPRInfo::regT0);
568             break;
569         case WASMOpExpressionI32::BitAnd:
570             and32(GPRInfo::regT1, GPRInfo::regT0);
571             break;
572         case WASMOpExpressionI32::BitXor:
573             xor32(GPRInfo::regT1, GPRInfo::regT0);
574             break;
575         case WASMOpExpressionI32::LeftShift:
576             lshift32(GPRInfo::regT1, GPRInfo::regT0);
577             break;
578         case WASMOpExpressionI32::ArithmeticRightShift:
579             rshift32(GPRInfo::regT1, GPRInfo::regT0);
580             break;
581         case WASMOpExpressionI32::LogicalRightShift:
582             urshift32(GPRInfo::regT1, GPRInfo::regT0);
583             break;
584         default:
585             ASSERT_NOT_REACHED();
586         }
587         m_tempStackTop--;
588         store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
589         return UNUSED;
590     }
591
592     int buildBinaryF32(int, int, WASMOpExpressionF32 op)
593     {
594         loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0);
595         loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
596         convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
597         convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
598         switch (op) {
599         case WASMOpExpressionF32::Add:
600             addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
601             break;
602         case WASMOpExpressionF32::Sub:
603             subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
604             break;
605         case WASMOpExpressionF32::Mul:
606             mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
607             break;
608         case WASMOpExpressionF32::Div:
609             divDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
610             break;
611         default:
612             RELEASE_ASSERT_NOT_REACHED();
613         }
614         convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
615         m_tempStackTop--;
616         storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1));
617         return UNUSED;
618     }
619
620     int buildRelationalI32(int, int, WASMOpExpressionI32 op)
621     {
622         load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0);
623         load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
624         RelationalCondition condition;
625         switch (op) {
626         case WASMOpExpressionI32::EqualI32:
627             condition = Equal;
628             break;
629         case WASMOpExpressionI32::NotEqualI32:
630             condition = NotEqual;
631             break;
632         case WASMOpExpressionI32::SLessThanI32:
633             condition = LessThan;
634             break;
635         case WASMOpExpressionI32::ULessThanI32:
636             condition = Below;
637             break;
638         case WASMOpExpressionI32::SLessThanOrEqualI32:
639             condition = LessThanOrEqual;
640             break;
641         case WASMOpExpressionI32::ULessThanOrEqualI32:
642             condition = BelowOrEqual;
643             break;
644         case WASMOpExpressionI32::SGreaterThanI32:
645             condition = GreaterThan;
646             break;
647         case WASMOpExpressionI32::UGreaterThanI32:
648             condition = Above;
649             break;
650         case WASMOpExpressionI32::SGreaterThanOrEqualI32:
651             condition = GreaterThanOrEqual;
652             break;
653         case WASMOpExpressionI32::UGreaterThanOrEqualI32:
654             condition = AboveOrEqual;
655             break;
656         default:
657             RELEASE_ASSERT_NOT_REACHED();
658         }
659         compare32(condition, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0);
660         m_tempStackTop--;
661         store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1));
662         return UNUSED;
663     }
664
665     int buildRelationalF32(int, int, WASMOpExpressionI32 op)
666     {
667         loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0);
668         loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
669         convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
670         convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1);
671         DoubleCondition condition;
672         switch (op) {
673         case WASMOpExpressionI32::EqualF32:
674             condition = DoubleEqual;
675             break;
676         case WASMOpExpressionI32::NotEqualF32:
677             condition = DoubleNotEqual;
678             break;
679         case WASMOpExpressionI32::LessThanF32:
680             condition = DoubleLessThan;
681             break;
682         case WASMOpExpressionI32::LessThanOrEqualF32:
683             condition = DoubleLessThanOrEqual;
684             break;
685         case WASMOpExpressionI32::GreaterThanF32:
686             condition = DoubleGreaterThan;
687             break;
688         case WASMOpExpressionI32::GreaterThanOrEqualF32:
689             condition = DoubleGreaterThanOrEqual;
690             break;
691         default:
692             RELEASE_ASSERT_NOT_REACHED();
693         }
694         m_tempStackTop--;
695         Jump trueCase = branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1);
696         store32(TrustedImm32(0), temporaryAddress(m_tempStackTop - 1));
697         Jump end = jump();
698         trueCase.link(this);
699         store32(TrustedImm32(1), temporaryAddress(m_tempStackTop - 1));
700         end.link(this);
701         return UNUSED;
702     }
703
704     int buildRelationalF64(int, int, WASMOpExpressionI32 op)
705     {
706         loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0);
707         loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1);
708         DoubleCondition condition;
709         switch (op) {
710         case WASMOpExpressionI32::EqualF64:
711             condition = DoubleEqual;
712             break;
713         case WASMOpExpressionI32::NotEqualF64:
714             condition = DoubleNotEqual;
715             break;
716         case WASMOpExpressionI32::LessThanF64:
717             condition = DoubleLessThan;
718             break;
719         case WASMOpExpressionI32::LessThanOrEqualF64:
720             condition = DoubleLessThanOrEqual;
721             break;
722         case WASMOpExpressionI32::GreaterThanF64:
723             condition = DoubleGreaterThan;
724             break;
725         case WASMOpExpressionI32::GreaterThanOrEqualF64:
726             condition = DoubleGreaterThanOrEqual;
727             break;
728         default:
729             RELEASE_ASSERT_NOT_REACHED();
730         }
731         m_tempStackTop--;
732         Jump trueCase = branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1);
733         store32(TrustedImm32(0), temporaryAddress(m_tempStackTop - 1));
734         Jump end = jump();
735         trueCase.link(this);
736         store32(TrustedImm32(1), temporaryAddress(m_tempStackTop - 1));
737         end.link(this);
738         return UNUSED;
739     }
740
741     int buildCallInternal(uint32_t functionIndex, int, const WASMSignature& signature, WASMExpressionType returnType)
742     {
743         boxArgumentsAndAdjustStackPointer(signature.arguments);
744
745         JSFunction* function = m_module->functions()[functionIndex].get();
746         move(TrustedImmPtr(function), GPRInfo::regT0);
747
748         callAndUnboxResult(returnType);
749         return UNUSED;
750     }
751
752     int buildCallIndirect(uint32_t functionPointerTableIndex, int, int, const WASMSignature& signature, WASMExpressionType returnType)
753     {
754         boxArgumentsAndAdjustStackPointer(signature.arguments);
755
756         const Vector<JSFunction*>& functions = m_module->functionPointerTables()[functionPointerTableIndex].functions;
757         move(TrustedImmPtr(functions.data()), GPRInfo::regT0);
758         load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1);
759         m_tempStackTop--;
760         and32(TrustedImm32(functions.size() - 1), GPRInfo::regT1);
761         loadPtr(BaseIndex(GPRInfo::regT0, GPRInfo::regT1, timesPtr()), GPRInfo::regT0);
762
763         callAndUnboxResult(returnType);
764         return UNUSED;
765     }
766
767     int buildCallImport(uint32_t functionImportIndex, int, const WASMSignature& signature, WASMExpressionType returnType)
768     {
769         boxArgumentsAndAdjustStackPointer(signature.arguments);
770
771         JSFunction* function = m_module->importedFunctions()[functionImportIndex].get();
772         move(TrustedImmPtr(function), GPRInfo::regT0);
773
774         callAndUnboxResult(returnType);
775         return UNUSED;
776     }
777
778     void appendExpressionList(int&, int) { }
779
780     void linkTarget(JumpTarget& target)
781     {
782         target.label = label();
783         target.jumpList.link(this);
784     }
785
786     void jumpToTarget(JumpTarget& target)
787     {
788         if (target.label.isSet())
789             jump(target.label);
790         else
791             target.jumpList.append(jump());
792     }
793
794     void jumpToTargetIf(JumpCondition condition, int, JumpTarget& target)
795     {
796         load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
797         m_tempStackTop--;
798         Jump taken = branchTest32((condition == JumpCondition::Zero) ? Zero : NonZero, GPRInfo::regT0);
799         if (target.label.isSet())
800             taken.linkTo(target.label, this);
801         else
802             target.jumpList.append(taken);
803     }
804
805     void startLoop()
806     {
807         m_breakTargets.append(JumpTarget());
808         m_continueTargets.append(JumpTarget());
809     }
810
811     void endLoop()
812     {
813         m_breakTargets.removeLast();
814         m_continueTargets.removeLast();
815     }
816
817     void startSwitch()
818     {
819         m_breakTargets.append(JumpTarget());
820     }
821
822     void endSwitch()
823     {
824         m_breakTargets.removeLast();
825     }
826
827     void startLabel()
828     {
829         m_breakLabelTargets.append(JumpTarget());
830         m_continueLabelTargets.append(JumpTarget());
831
832         linkTarget(m_continueLabelTargets.last());
833     }
834
835     void endLabel()
836     {
837         linkTarget(m_breakLabelTargets.last());
838
839         m_breakLabelTargets.removeLast();
840         m_continueLabelTargets.removeLast();
841     }
842
843     JumpTarget& breakTarget()
844     {
845         return m_breakTargets.last();
846     }
847
848     JumpTarget& continueTarget()
849     {
850         return m_continueTargets.last();
851     }
852
853     JumpTarget& breakLabelTarget(uint32_t labelIndex)
854     {
855         return m_breakLabelTargets[labelIndex];
856     }
857
858     JumpTarget& continueLabelTarget(uint32_t labelIndex)
859     {
860         return m_continueLabelTargets[labelIndex];
861     }
862
863     void buildSwitch(int, const Vector<int64_t>& cases, Vector<JumpTarget>& targets, JumpTarget defaultTarget)
864     {
865         load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0);
866         m_tempStackTop--;
867         BinarySwitch binarySwitch(GPRInfo::regT0, cases, BinarySwitch::Int32);
868         while (binarySwitch.advance(*this)) {
869             unsigned index = binarySwitch.caseIndex();
870             jump(targets[index].label);
871         }
872         binarySwitch.fallThrough().linkTo(defaultTarget.label, this);
873     }
874
875 private:
876     union StackSlot {
877         int32_t intValue;
878         float floatValue;
879         double doubleValue;
880     };
881
882     enum class FloatingPointPrecision { Single, Double };
883
884     Address localAddress(unsigned localIndex) const
885     {
886         ASSERT(localIndex < m_numberOfLocals);
887         return Address(GPRInfo::callFrameRegister, -m_calleeSaveSpace - (localIndex + 1) * sizeof(StackSlot));
888     }
889
890     Address temporaryAddress(unsigned temporaryIndex) const
891     {
892         ASSERT(m_numberOfLocals + temporaryIndex < m_stackHeight);
893         return Address(GPRInfo::callFrameRegister, -m_calleeSaveSpace - (m_numberOfLocals + temporaryIndex + 1) * sizeof(StackSlot));
894     }
895
896     void appendCall(const FunctionPtr& function)
897     {
898         m_calls.append(std::make_pair(call(), function.value()));
899     }
900
901     void appendCallWithExceptionCheck(const FunctionPtr& function)
902     {
903         appendCall(function);
904         m_exceptionChecks.append(emitExceptionCheck());
905     }
906
907     Call emitNakedCall(CodePtr function)
908     {
909         Call nakedCall = nearCall();
910         m_calls.append(std::make_pair(nakedCall, function.executableAddress()));
911         return nakedCall;
912     }
913
914     void appendCallSetResult(const FunctionPtr& function, GPRReg result)
915     {
916         appendCall(function);
917         move(GPRInfo::returnValueGPR, result);
918     }
919
920 #if CPU(X86)
921     void appendCallSetResult(const FunctionPtr& function, FPRReg result, FloatingPointPrecision precision)
922     {
923         appendCall(function);
924         switch (precision) {
925         case FloatingPointPrecision::Single:
926             m_assembler.fstps(0, stackPointerRegister);
927             break;
928         case FloatingPointPrecision::Double:
929             m_assembler.fstpl(0, stackPointerRegister);
930             break;
931         }
932         loadDouble(stackPointerRegister, result);
933     }
934 #elif CPU(ARM) && !CPU(ARM_HARDFP)
935     void appendCallSetResult(const FunctionPtr& function, FPRReg result, FloatingPointPrecision)
936     {
937         appendCall(function);
938         m_assembler.vmov(result, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2);
939     }
940 #else // CPU(X86_64) || (CPU(ARM) && CPU(ARM_HARDFP)) || CPU(ARM64) || CPU(MIPS) || CPU(SH4)
941     void appendCallSetResult(const FunctionPtr& function, FPRReg result, FloatingPointPrecision)
942     {
943         appendCall(function);
944         moveDouble(FPRInfo::returnValueFPR, result);
945     }
946 #endif
947
948 #if USE(JSVALUE64)
949     void callOperation(Z_JITOperation_EJ operation, GPRReg src, GPRReg dst)
950     {
951         setupArgumentsWithExecState(src);
952         appendCallSetResult(operation, dst);
953     }
954
955     void callOperation(D_JITOperation_EJ operation, GPRReg src, FPRReg dst)
956     {
957         setupArgumentsWithExecState(src);
958         appendCallSetResult(operation, dst, FloatingPointPrecision::Double);
959     }
960 #else
961     // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]).
962     // To avoid assemblies from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary.
963 #if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS)
964 #define EABI_32BIT_DUMMY_ARG      TrustedImm32(0),
965 #else
966 #define EABI_32BIT_DUMMY_ARG
967 #endif
968
969     void callOperation(Z_JITOperation_EJ operation, GPRReg srcTag, GPRReg srcPayload, GPRReg dst)
970     {
971         setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG srcPayload, srcTag);
972         appendCallSetResult(operation, dst);
973     }
974
975     void callOperation(D_JITOperation_EJ operation, GPRReg srcTag, GPRReg srcPayload, FPRReg dst)
976     {
977         setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG srcPayload, srcTag);
978         appendCallSetResult(operation, dst, FloatingPointPrecision::Double);
979     }
980 #endif
981
982     void callOperation(float JIT_OPERATION (*operation)(float), FPRegisterID src, FPRegisterID dst)
983     {
984         setupArguments(src);
985         appendCallSetResult(operation, dst, FloatingPointPrecision::Single);
986     }
987
988     void callOperation(int32_t JIT_OPERATION (*operation)(int32_t, int32_t), GPRReg src1, GPRReg src2, GPRReg dst)
989     {
990         setupArguments(src1, src2);
991         appendCallSetResult(operation, dst);
992     }
993
994     void callOperation(uint32_t JIT_OPERATION (*operation)(uint32_t, uint32_t), GPRReg src1, GPRReg src2, GPRReg dst)
995     {
996         setupArguments(src1, src2);
997         appendCallSetResult(operation, dst);
998     }
999
1000     void callOperation(double JIT_OPERATION (*operation)(uint32_t), GPRReg src, FPRegisterID dst)
1001     {
1002         setupArguments(src);
1003         appendCallSetResult(operation, dst, FloatingPointPrecision::Double);
1004     }
1005
1006     void boxArgumentsAndAdjustStackPointer(const Vector<WASMType>& arguments)
1007     {
1008         size_t argumentCount = arguments.size();
1009         int stackOffset = -m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_numberOfLocals + m_tempStackTop + argumentCount + 1 + JSStack::CallFrameHeaderSize);
1010
1011         storeTrustedValue(jsUndefined(), Address(GPRInfo::callFrameRegister, (stackOffset + CallFrame::thisArgumentOffset()) * sizeof(Register)));
1012
1013         for (size_t i = 0; i < argumentCount; ++i) {
1014             Address address(GPRInfo::callFrameRegister, (stackOffset + CallFrame::argumentOffset(i)) * sizeof(Register));
1015 #if USE(JSVALUE64)
1016             JSValueRegs valueRegs(GPRInfo::regT0);
1017 #else
1018             JSValueRegs valueRegs(GPRInfo::regT1, GPRInfo::regT0);
1019 #endif
1020             switch (arguments[i]) {
1021             case WASMType::I32:
1022                 load32(temporaryAddress(m_tempStackTop - argumentCount + i), GPRInfo::regT0);
1023 #if USE(JSVALUE64)
1024                 or64(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
1025                 store64(GPRInfo::regT0, address);
1026 #else
1027                 store32(GPRInfo::regT0, address.withOffset(PayloadOffset));
1028                 store32(TrustedImm32(JSValue::Int32Tag), address.withOffset(TagOffset));
1029 #endif
1030                 break;
1031             case WASMType::F32:
1032             case WASMType::F64:
1033                 loadDouble(temporaryAddress(m_tempStackTop - argumentCount + i), FPRInfo::fpRegT0);
1034                 if (arguments[i] == WASMType::F32)
1035                     convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
1036                 convertDoubleToValue(FPRInfo::fpRegT0, valueRegs);
1037                 storeValue(valueRegs, address);
1038                 break;
1039             default:
1040                 ASSERT_NOT_REACHED();
1041             }
1042         }
1043         m_tempStackTop -= argumentCount;
1044
1045         addPtr(TrustedImm32(stackOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), GPRInfo::callFrameRegister, stackPointerRegister);
1046         store32(TrustedImm32(argumentCount + 1), Address(stackPointerRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
1047     }
1048
1049     void callAndUnboxResult(WASMExpressionType returnType)
1050     {
1051         // regT0 holds callee.
1052 #if USE(JSVALUE64)
1053         store64(GPRInfo::regT0, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) - sizeof(CallerFrameAndPC)));
1054 #else
1055         store32(GPRInfo::regT0, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
1056         store32(TrustedImm32(JSValue::CellTag), Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + TagOffset - sizeof(CallerFrameAndPC)));
1057 #endif
1058
1059         DataLabelPtr addressOfLinkedFunctionCheck;
1060         Jump slowCase = branchPtrWithPatch(NotEqual, GPRInfo::regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
1061
1062         CallLinkInfo* info = m_codeBlock->addCallLinkInfo();
1063         info->setUpCall(CallLinkInfo::Call, CodeOrigin(), GPRInfo::regT0);
1064         m_callCompilationInfo.append(CallCompilationInfo());
1065         m_callCompilationInfo.last().hotPathBegin = addressOfLinkedFunctionCheck;
1066         m_callCompilationInfo.last().callLinkInfo = info;
1067         m_callCompilationInfo.last().hotPathOther = nearCall();
1068         Jump end = jump();
1069
1070         slowCase.link(this);
1071         move(TrustedImmPtr(info), GPRInfo::regT2);
1072         m_callCompilationInfo.last().callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code());
1073
1074         end.link(this);
1075         addPtr(TrustedImm32(-m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, stackPointerRegister);
1076         checkStackPointerAlignment();
1077
1078         // FIXME: No need to do type conversion if the callee is a WebAssembly function.
1079         // https://bugs.webkit.org/show_bug.cgi?id=149310
1080 #if USE(JSVALUE64)
1081         JSValueRegs valueRegs(GPRInfo::returnValueGPR);
1082 #else
1083         JSValueRegs valueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR);
1084 #endif
1085         switch (returnType) {
1086         case WASMExpressionType::I32:
1087             convertValueToInt32(valueRegs, GPRInfo::regT0);
1088             store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++));
1089             break;
1090         case WASMExpressionType::F32:
1091         case WASMExpressionType::F64:
1092 #if USE(JSVALUE64)
1093             convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::nonPreservedNonReturnGPR);
1094 #else
1095             convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::nonPreservedNonReturnGPR, FPRInfo::fpRegT1);
1096 #endif
1097             if (returnType == WASMExpressionType::F32)
1098                 convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0);
1099             storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++));
1100             break;
1101         case WASMExpressionType::Void:
1102             break;
1103         default:
1104             ASSERT_NOT_REACHED();
1105         }
1106     }
1107
1108 #if USE(JSVALUE64)
1109     void convertValueToInt32(JSValueRegs valueRegs, GPRReg dst)
1110     {
1111         Jump checkJSInt32 = branchIfInt32(valueRegs);
1112
1113         callOperation(operationConvertJSValueToInt32, valueRegs.gpr(), valueRegs.gpr());
1114
1115         checkJSInt32.link(this);
1116         move(valueRegs.gpr(), dst);
1117     }
1118
1119     void convertValueToDouble(JSValueRegs valueRegs, FPRReg dst, GPRReg scratch)
1120     {
1121         Jump checkJSInt32 = branchIfInt32(valueRegs);
1122         Jump checkJSNumber = branchIfNumber(valueRegs, scratch);
1123         JumpList end;
1124
1125         callOperation(operationConvertJSValueToDouble, valueRegs.gpr(), dst);
1126         end.append(jump());
1127
1128         checkJSInt32.link(this);
1129         convertInt32ToDouble(valueRegs.gpr(), dst);
1130         end.append(jump());
1131
1132         checkJSNumber.link(this);
1133         unboxDoubleWithoutAssertions(valueRegs.gpr(), dst);
1134         end.link(this);
1135     }
1136 #else
1137     void convertValueToInt32(JSValueRegs valueRegs, GPRReg dst)
1138     {
1139         Jump checkJSInt32 = branchIfInt32(valueRegs);
1140
1141         callOperation(operationConvertJSValueToInt32, valueRegs.tagGPR(), valueRegs.payloadGPR(), valueRegs.payloadGPR());
1142
1143         checkJSInt32.link(this);
1144         move(valueRegs.payloadGPR(), dst);
1145     }
1146
1147     void convertValueToDouble(JSValueRegs valueRegs, FPRReg dst, GPRReg scratch, FPRReg fpScratch)
1148     {
1149         Jump checkJSInt32 = branchIfInt32(valueRegs);
1150         Jump checkJSNumber = branchIfNumber(valueRegs, scratch);
1151         JumpList end;
1152
1153         callOperation(operationConvertJSValueToDouble, valueRegs.tagGPR(), valueRegs.payloadGPR(), dst);
1154         end.append(jump());
1155
1156         checkJSInt32.link(this);
1157         convertInt32ToDouble(valueRegs.payloadGPR(), dst);
1158         end.append(jump());
1159
1160         checkJSNumber.link(this);
1161         unboxDouble(valueRegs.tagGPR(), valueRegs.payloadGPR(), dst, fpScratch);
1162         end.link(this);
1163     }
1164 #endif
1165
1166     void convertDoubleToValue(FPRReg fpr, JSValueRegs valueRegs)
1167     {
1168 #if USE(JSVALUE64)
1169         boxDouble(fpr, valueRegs.gpr());
1170 #else
1171         boxDouble(fpr, valueRegs.tagGPR(), valueRegs.payloadGPR());
1172 #endif
1173     }
1174
1175     JSWASMModule* m_module;
1176     unsigned m_stackHeight;
1177     unsigned m_numberOfLocals;
1178     unsigned m_tempStackTop { 0 };
1179     unsigned m_calleeSaveSpace;
1180
1181     Vector<JumpTarget> m_breakTargets;
1182     Vector<JumpTarget> m_continueTargets;
1183     Vector<JumpTarget> m_breakLabelTargets;
1184     Vector<JumpTarget> m_continueLabelTargets;
1185
1186     Label m_beginLabel;
1187     Jump m_stackOverflow;
1188     JumpList m_divideErrorJumpList;
1189     JumpList m_exceptionChecks;
1190
1191     Vector<std::pair<Call, void*>> m_calls;
1192     Vector<CallCompilationInfo> m_callCompilationInfo;
1193 };
1194
1195 } // namespace JSC
1196
1197 #endif // ENABLE(WEBASSEMBLY)
1198
1199 #endif // WASMFunctionCompiler_h