diff options
Diffstat (limited to 'Source/JavaScriptCore/wasm/WASMFunctionCompiler.h')
| -rw-r--r-- | Source/JavaScriptCore/wasm/WASMFunctionCompiler.h | 1541 |
1 files changed, 0 insertions, 1541 deletions
diff --git a/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h b/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h deleted file mode 100644 index de439ba07..000000000 --- a/Source/JavaScriptCore/wasm/WASMFunctionCompiler.h +++ /dev/null @@ -1,1541 +0,0 @@ -/* - * Copyright (C) 2015 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WASMFunctionCompiler_h -#define WASMFunctionCompiler_h - -#if ENABLE(WEBASSEMBLY) - -#include "BinarySwitch.h" -#include "CCallHelpers.h" -#include "JIT.h" -#include "JITOperations.h" -#include "JSArrayBuffer.h" -#include "LinkBuffer.h" -#include "MaxFrameExtentForSlowPathCall.h" - -#define UNUSED 0 - -namespace JSC { - -static int32_t JIT_OPERATION operationConvertJSValueToInt32(ExecState* exec, EncodedJSValue value) -{ - return JSValue::decode(value).toInt32(exec); -} - -static double JIT_OPERATION operationConvertJSValueToDouble(ExecState* exec, EncodedJSValue value) -{ - return JSValue::decode(value).toNumber(exec); -} - -#if !CPU(X86) && !CPU(X86_64) -static int32_t JIT_OPERATION operationDiv(int32_t left, int32_t right) -{ - return left / right; -} - -static int32_t JIT_OPERATION operationMod(int32_t left, int32_t right) -{ - return left % right; -} - -static uint32_t JIT_OPERATION operationUnsignedDiv(uint32_t left, uint32_t right) -{ - return left / right; -} - -static uint32_t JIT_OPERATION operationUnsignedMod(uint32_t left, uint32_t right) -{ - return left % right; -} -#endif - -#if !USE(JSVALUE64) -static double JIT_OPERATION operationConvertUnsignedInt32ToDouble(uint32_t value) -{ - return static_cast<double>(value); -} -#endif - -static size_t sizeOfMemoryType(WASMMemoryType memoryType) -{ - switch (memoryType) { - case WASMMemoryType::I8: - return 1; - case WASMMemoryType::I16: - return 2; - case WASMMemoryType::I32: - case WASMMemoryType::F32: - return 4; - case WASMMemoryType::F64: - return 8; - default: - ASSERT_NOT_REACHED(); - } - RELEASE_ASSERT_NOT_REACHED(); - return 0; -} - -class WASMFunctionCompiler : private CCallHelpers { -public: - typedef int Expression; - typedef int Statement; - typedef int ExpressionList; - struct MemoryAddress { - MemoryAddress(void*) { } - MemoryAddress(int, uint32_t offset) - : offset(offset) - { - } - uint32_t offset; - }; - struct JumpTarget { - Label label; - JumpList jumpList; - }; - enum class JumpCondition { Zero, NonZero }; - - WASMFunctionCompiler(VM& vm, CodeBlock* codeBlock, JSWASMModule* module, unsigned stackHeight) - : CCallHelpers(&vm, codeBlock) - , m_module(module) - , m_stackHeight(stackHeight) - { - } - - void startFunction(const Vector<WASMType>& arguments, uint32_t numberOfI32LocalVariables, uint32_t numberOfF32LocalVariables, uint32_t numberOfF64LocalVariables) - { - m_calleeSaveSpace = WTF::roundUpToMultipleOf(sizeof(StackSlot), RegisterSet::webAssemblyCalleeSaveRegisters().numberOfSetRegisters() * sizeof(void*)); - m_codeBlock->setCalleeSaveRegisters(RegisterSet::webAssemblyCalleeSaveRegisters()); - - emitFunctionPrologue(); - emitPutToCallFrameHeader(m_codeBlock, JSStack::CodeBlock); - - m_beginLabel = label(); - - addPtr(TrustedImm32(-m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, GPRInfo::regT1); - m_stackOverflow = branchPtr(Above, AbsoluteAddress(m_vm->addressOfStackLimit()), GPRInfo::regT1); - - move(GPRInfo::regT1, stackPointerRegister); - checkStackPointerAlignment(); - - emitSaveCalleeSaves(); - emitMaterializeTagCheckRegisters(); - - m_numberOfLocals = arguments.size() + numberOfI32LocalVariables + numberOfF32LocalVariables + numberOfF64LocalVariables; - - unsigned localIndex = 0; - for (size_t i = 0; i < arguments.size(); ++i) { - // FIXME: No need to do type conversion if the caller is a WebAssembly function. - // https://bugs.webkit.org/show_bug.cgi?id=149310 - Address address(GPRInfo::callFrameRegister, CallFrame::argumentOffset(i) * sizeof(Register)); -#if USE(JSVALUE64) - JSValueRegs valueRegs(GPRInfo::regT0); -#else - JSValueRegs valueRegs(GPRInfo::regT1, GPRInfo::regT0); -#endif - loadValue(address, valueRegs); - switch (arguments[i]) { - case WASMType::I32: - convertValueToInt32(valueRegs, GPRInfo::regT0); - store32(GPRInfo::regT0, localAddress(localIndex++)); - break; - case WASMType::F32: - case WASMType::F64: -#if USE(JSVALUE64) - convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::regT1); -#else - convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::regT2, FPRInfo::fpRegT1); -#endif - if (arguments[i] == WASMType::F32) - convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, localAddress(localIndex++)); - break; - default: - ASSERT_NOT_REACHED(); - } - } - for (uint32_t i = 0; i < numberOfI32LocalVariables; ++i) - store32(TrustedImm32(0), localAddress(localIndex++)); - for (uint32_t i = 0; i < numberOfF32LocalVariables; ++i) - store32(TrustedImm32(0), localAddress(localIndex++)); - for (uint32_t i = 0; i < numberOfF64LocalVariables; ++i) { -#if USE(JSVALUE64) - store64(TrustedImm64(0), localAddress(localIndex++)); -#else - store32(TrustedImm32(0), localAddress(localIndex)); - store32(TrustedImm32(0), localAddress(localIndex).withOffset(4)); - localIndex++; -#endif - } - - m_codeBlock->setNumParameters(1 + arguments.size()); - } - - void endFunction() - { - ASSERT(!m_tempStackTop); - - // FIXME: Remove these if the last statement is a return statement. -#if USE(JSVALUE64) - JSValueRegs returnValueRegs(GPRInfo::returnValueGPR); -#else - JSValueRegs returnValueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR); -#endif - moveTrustedValue(jsUndefined(), returnValueRegs); - emitRestoreCalleeSaves(); - emitFunctionEpilogue(); - ret(); - - m_stackOverflow.link(this); - if (maxFrameExtentForSlowPathCall) - addPtr(TrustedImm32(-maxFrameExtentForSlowPathCall), stackPointerRegister); - setupArgumentsWithExecState(TrustedImmPtr(m_codeBlock)); - appendCallWithExceptionCheck(operationThrowStackOverflowError); - - // FIXME: Implement arity check. - Label arityCheck = label(); - emitFunctionPrologue(); - emitPutToCallFrameHeader(m_codeBlock, JSStack::CodeBlock); - jump(m_beginLabel); - - if (!m_divideErrorJumpList.empty()) { - m_divideErrorJumpList.link(this); - - setupArgumentsExecState(); - appendCallWithExceptionCheck(operationThrowDivideError); - } - - if (!m_outOfBoundsErrorJumpList.empty()) { - m_outOfBoundsErrorJumpList.link(this); - - setupArgumentsExecState(); - appendCallWithExceptionCheck(operationThrowOutOfBoundsAccessError); - } - - if (!m_exceptionChecks.empty()) { - m_exceptionChecks.link(this); - - copyCalleeSavesToVMCalleeSavesBuffer(); - - // lookupExceptionHandler is passed two arguments, the VM and the exec (the CallFrame*). - move(TrustedImmPtr(vm()), GPRInfo::argumentGPR0); - move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1); - -#if CPU(X86) - // FIXME: should use the call abstraction, but this is currently in the SpeculativeJIT layer! - poke(GPRInfo::argumentGPR0); - poke(GPRInfo::argumentGPR1, 1); -#endif - m_calls.append(std::make_pair(call(), FunctionPtr(lookupExceptionHandlerFromCallerFrame).value())); - jumpToExceptionHandler(); - } - - LinkBuffer patchBuffer(*m_vm, *this, m_codeBlock, JITCompilationMustSucceed); - - for (const auto& iterator : m_calls) - patchBuffer.link(iterator.first, FunctionPtr(iterator.second)); - - for (size_t i = 0; i < m_callCompilationInfo.size(); ++i) { - CallCompilationInfo& compilationInfo = m_callCompilationInfo[i]; - CallLinkInfo& info = *compilationInfo.callLinkInfo; - info.setCallLocations(patchBuffer.locationOfNearCall(compilationInfo.callReturnLocation), - patchBuffer.locationOf(compilationInfo.hotPathBegin), - patchBuffer.locationOfNearCall(compilationInfo.hotPathOther)); - } - - MacroAssemblerCodePtr withArityCheck = patchBuffer.locationOf(arityCheck); - CodeRef result = FINALIZE_CODE(patchBuffer, ("Baseline JIT code for WebAssembly")); - m_codeBlock->setJITCode(adoptRef(new DirectJITCode(result, withArityCheck, JITCode::BaselineJIT))); - m_codeBlock->capabilityLevel(); - } - - int buildSetLocal(WASMOpKind opKind, uint32_t localIndex, int, WASMType type) - { - switch (type) { - case WASMType::I32: - case WASMType::F32: - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0); - store32(GPRInfo::regT0, localAddress(localIndex)); - break; - case WASMType::F64: - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, localAddress(localIndex)); - break; - default: - ASSERT_NOT_REACHED(); - } - if (opKind == WASMOpKind::Statement) - m_tempStackTop--; - return UNUSED; - } - - int buildSetGlobal(WASMOpKind opKind, uint32_t globalIndex, int, WASMType type) - { - move(TrustedImmPtr(&m_module->globalVariables()[globalIndex]), GPRInfo::regT0); - switch (type) { - case WASMType::I32: - case WASMType::F32: - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1); - store32(GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMType::F64: - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, GPRInfo::regT0); - break; - default: - ASSERT_NOT_REACHED(); - } - if (opKind == WASMOpKind::Statement) - m_tempStackTop--; - return UNUSED; - } - - void buildReturn(int, WASMExpressionType returnType) - { -#if USE(JSVALUE64) - JSValueRegs returnValueRegs(GPRInfo::returnValueGPR); -#else - JSValueRegs returnValueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR); -#endif - switch (returnType) { - case WASMExpressionType::I32: - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::returnValueGPR); -#if USE(JSVALUE64) - or64(GPRInfo::tagTypeNumberRegister, GPRInfo::returnValueGPR); -#else - move(TrustedImm32(JSValue::Int32Tag), GPRInfo::returnValueGPR2); -#endif - m_tempStackTop--; - break; - case WASMExpressionType::F32: - case WASMExpressionType::F64: - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0); - if (returnType == WASMExpressionType::F32) - convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - convertDoubleToValue(FPRInfo::fpRegT0, returnValueRegs); - m_tempStackTop--; - break; - case WASMExpressionType::Void: - moveTrustedValue(jsUndefined(), returnValueRegs); - break; - default: - ASSERT_NOT_REACHED(); - } - emitRestoreCalleeSaves(); - emitFunctionEpilogue(); - ret(); - } - - int buildImmediateI32(uint32_t immediate) - { - store32(Imm32(immediate), temporaryAddress(m_tempStackTop++)); - return UNUSED; - } - - int buildImmediateF32(float immediate) - { - store32(Imm32(bitwise_cast<int32_t>(immediate)), temporaryAddress(m_tempStackTop++)); - return UNUSED; - } - - int buildImmediateF64(double immediate) - { -#if USE(JSVALUE64) - store64(Imm64(bitwise_cast<int64_t>(immediate)), temporaryAddress(m_tempStackTop++)); -#else - union { - double doubleValue; - int32_t int32Values[2]; - } u = { immediate }; - m_tempStackTop++; - store32(Imm32(u.int32Values[0]), temporaryAddress(m_tempStackTop - 1)); - store32(Imm32(u.int32Values[1]), temporaryAddress(m_tempStackTop - 1).withOffset(4)); -#endif - return UNUSED; - } - - int buildGetLocal(uint32_t localIndex, WASMType type) - { - switch (type) { - case WASMType::I32: - case WASMType::F32: - load32(localAddress(localIndex), GPRInfo::regT0); - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++)); - break; - case WASMType::F64: - loadDouble(localAddress(localIndex), FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++)); - break; - default: - ASSERT_NOT_REACHED(); - } - return UNUSED; - } - - int buildGetGlobal(uint32_t globalIndex, WASMType type) - { - move(TrustedImmPtr(&m_module->globalVariables()[globalIndex]), GPRInfo::regT0); - switch (type) { - case WASMType::I32: - case WASMType::F32: - load32(GPRInfo::regT0, GPRInfo::regT0); - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++)); - break; - case WASMType::F64: - loadDouble(GPRInfo::regT0, FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++)); - break; - default: - ASSERT_NOT_REACHED(); - } - return UNUSED; - } - - int buildConvertType(int, WASMExpressionType fromType, WASMExpressionType toType, WASMTypeConversion conversion) - { - switch (fromType) { - case WASMExpressionType::I32: - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0); - ASSERT(toType == WASMExpressionType::F32 || toType == WASMExpressionType::F64); - if (conversion == WASMTypeConversion::ConvertSigned) - convertInt32ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0); - else { - ASSERT(conversion == WASMTypeConversion::ConvertUnsigned); -#if USE(JSVALUE64) - convertInt64ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0); -#else - callOperation(operationConvertUnsignedInt32ToDouble, GPRInfo::regT0, FPRInfo::fpRegT0); -#endif - } - if (toType == WASMExpressionType::F32) - convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1)); - break; - case WASMExpressionType::F32: - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0); - switch (toType) { - case WASMExpressionType::I32: - ASSERT(conversion == WASMTypeConversion::ConvertSigned); - convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - truncateDoubleToInt32(FPRInfo::fpRegT0, GPRInfo::regT0); - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1)); - break; - case WASMExpressionType::F64: - ASSERT(conversion == WASMTypeConversion::Promote); - convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1)); - break; - default: - ASSERT_NOT_REACHED(); - } - break; - case WASMExpressionType::F64: - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0); - switch (toType) { - case WASMExpressionType::I32: - ASSERT(conversion == WASMTypeConversion::ConvertSigned); - truncateDoubleToInt32(FPRInfo::fpRegT0, GPRInfo::regT0); - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1)); - break; - case WASMExpressionType::F32: - ASSERT(conversion == WASMTypeConversion::Demote); - convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1)); - break; - default: - ASSERT_NOT_REACHED(); - } - break; - default: - ASSERT_NOT_REACHED(); - } - return UNUSED; - } - - int buildLoad(const MemoryAddress& memoryAddress, WASMExpressionType expressionType, WASMMemoryType memoryType, MemoryAccessConversion conversion) - { - const ArrayBuffer* arrayBuffer = m_module->arrayBuffer()->impl(); - move(TrustedImmPtr(arrayBuffer->data()), GPRInfo::regT0); - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1); - if (memoryAddress.offset) - add32(TrustedImm32(memoryAddress.offset), GPRInfo::regT1, GPRInfo::regT1); - and32(TrustedImm32(~(sizeOfMemoryType(memoryType) - 1)), GPRInfo::regT1); - - ASSERT(arrayBuffer->byteLength() < (unsigned)(1 << 31)); - if (arrayBuffer->byteLength() >= sizeOfMemoryType(memoryType)) - m_outOfBoundsErrorJumpList.append(branch32(Above, GPRInfo::regT1, TrustedImm32(arrayBuffer->byteLength() - sizeOfMemoryType(memoryType)))); - else - m_outOfBoundsErrorJumpList.append(jump()); - - BaseIndex address = BaseIndex(GPRInfo::regT0, GPRInfo::regT1, TimesOne); - - switch (expressionType) { - case WASMExpressionType::I32: - switch (memoryType) { - case WASMMemoryType::I8: - if (conversion == MemoryAccessConversion::SignExtend) - load8SignedExtendTo32(address, GPRInfo::regT0); - else { - ASSERT(conversion == MemoryAccessConversion::ZeroExtend); - load8(address, GPRInfo::regT0); - } - break; - case WASMMemoryType::I16: - if (conversion == MemoryAccessConversion::SignExtend) - load16SignedExtendTo32(address, GPRInfo::regT0); - else { - ASSERT(conversion == MemoryAccessConversion::ZeroExtend); - load16(address, GPRInfo::regT0); - } - break; - case WASMMemoryType::I32: - load32(address, GPRInfo::regT0); - break; - default: - ASSERT_NOT_REACHED(); - } - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1)); - break; - case WASMExpressionType::F32: - ASSERT(memoryType == WASMMemoryType::F32 && conversion == MemoryAccessConversion::NoConversion); - load32(address, GPRInfo::regT0); - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1)); - break; - case WASMExpressionType::F64: - ASSERT(memoryType == WASMMemoryType::F64 && conversion == MemoryAccessConversion::NoConversion); - loadDouble(address, FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1)); - break; - default: - ASSERT_NOT_REACHED(); - } - return UNUSED; - } - - int buildStore(WASMOpKind opKind, const MemoryAddress& memoryAddress, WASMExpressionType expressionType, WASMMemoryType memoryType, int) - { - const ArrayBuffer* arrayBuffer = m_module->arrayBuffer()->impl(); - move(TrustedImmPtr(arrayBuffer->data()), GPRInfo::regT0); - load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT1); - if (memoryAddress.offset) - add32(TrustedImm32(memoryAddress.offset), GPRInfo::regT1, GPRInfo::regT1); - and32(TrustedImm32(~(sizeOfMemoryType(memoryType) - 1)), GPRInfo::regT1); - - ASSERT(arrayBuffer->byteLength() < (1u << 31)); - if (arrayBuffer->byteLength() >= sizeOfMemoryType(memoryType)) - m_outOfBoundsErrorJumpList.append(branch32(Above, GPRInfo::regT1, TrustedImm32(arrayBuffer->byteLength() - sizeOfMemoryType(memoryType)))); - else - m_outOfBoundsErrorJumpList.append(jump()); - - BaseIndex address = BaseIndex(GPRInfo::regT0, GPRInfo::regT1, TimesOne); - - switch (expressionType) { - case WASMExpressionType::I32: - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT2); - switch (memoryType) { - case WASMMemoryType::I8: - store8(GPRInfo::regT2, address); - break; - case WASMMemoryType::I16: - store16(GPRInfo::regT2, address); - break; - case WASMMemoryType::I32: - store32(GPRInfo::regT2, address); - break; - default: - ASSERT_NOT_REACHED(); - } - break; - case WASMExpressionType::F32: - ASSERT(memoryType == WASMMemoryType::F32); - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT2); - store32(GPRInfo::regT2, address); - break; - case WASMExpressionType::F64: - ASSERT(memoryType == WASMMemoryType::F64); - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, address); - break; - default: - ASSERT_NOT_REACHED(); - } - m_tempStackTop -= 2; - - if (opKind == WASMOpKind::Expression) { - switch (expressionType) { - case WASMExpressionType::I32: - case WASMExpressionType::F32: - store32(GPRInfo::regT2, temporaryAddress(m_tempStackTop++)); - break; - case WASMExpressionType::F64: - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++)); - break; - default: - ASSERT_NOT_REACHED(); - } - } - return UNUSED; - } - - int buildUnaryI32(int, WASMOpExpressionI32 op) - { - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0); - switch (op) { - case WASMOpExpressionI32::Negate: - neg32(GPRInfo::regT0); - break; - case WASMOpExpressionI32::BitNot: - xor32(TrustedImm32(-1), GPRInfo::regT0); - break; - case WASMOpExpressionI32::CountLeadingZeros: - countLeadingZeros32(GPRInfo::regT0, GPRInfo::regT0); - break; - case WASMOpExpressionI32::LogicalNot: { - // FIXME: Don't use branches. - Jump zero = branchTest32(Zero, GPRInfo::regT0); - move(TrustedImm32(0), GPRInfo::regT0); - Jump end = jump(); - zero.link(this); - move(TrustedImm32(1), GPRInfo::regT0); - end.link(this); - break; - } - case WASMOpExpressionI32::Abs: { - // FIXME: Don't use branches. - Jump end = branchTest32(PositiveOrZero, GPRInfo::regT0); - neg32(GPRInfo::regT0); - end.link(this); - break; - } - default: - ASSERT_NOT_REACHED(); - } - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1)); - return UNUSED; - } - - int buildUnaryF32(int, WASMOpExpressionF32 op) - { - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1); - switch (op) { - case WASMOpExpressionF32::Negate: - convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1); - negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF32::Abs: - convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1); - absDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF32::Ceil: - callOperation(ceilf, FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF32::Floor: - callOperation(floorf, FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF32::Sqrt: - convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1); - sqrtDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - break; - default: - ASSERT_NOT_REACHED(); - } - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1)); - return UNUSED; - } - - int buildUnaryF64(int, WASMOpExpressionF64 op) - { - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1); - switch (op) { - case WASMOpExpressionF64::Negate: - negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF64::Abs: - absDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF64::Sqrt: - sqrtDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF64::Ceil: - case WASMOpExpressionF64::Floor: - case WASMOpExpressionF64::Cos: - case WASMOpExpressionF64::Sin: - case WASMOpExpressionF64::Tan: - case WASMOpExpressionF64::ACos: - case WASMOpExpressionF64::ASin: - case WASMOpExpressionF64::ATan: - case WASMOpExpressionF64::Exp: - case WASMOpExpressionF64::Ln: - D_JITOperation_D operation; - switch (op) { - case WASMOpExpressionF64::Ceil: - operation = ceil; - break; - case WASMOpExpressionF64::Floor: - operation = floor; - break; - case WASMOpExpressionF64::Cos: - operation = cos; - break; - case WASMOpExpressionF64::Sin: - operation = sin; - break; - case WASMOpExpressionF64::Tan: - operation = tan; - break; - case WASMOpExpressionF64::ACos: - operation = acos; - break; - case WASMOpExpressionF64::ASin: - operation = asin; - break; - case WASMOpExpressionF64::ATan: - operation = atan; - break; - case WASMOpExpressionF64::Exp: - operation = exp; - break; - case WASMOpExpressionF64::Ln: - operation = log; - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - callOperation(operation, FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - default: - ASSERT_NOT_REACHED(); - } - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1)); - return UNUSED; - } - - int buildBinaryI32(int, int, WASMOpExpressionI32 op) - { - load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0); - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1); - switch (op) { - case WASMOpExpressionI32::Add: - add32(GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::Sub: - sub32(GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::Mul: - mul32(GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::SDiv: - case WASMOpExpressionI32::UDiv: - case WASMOpExpressionI32::SMod: - case WASMOpExpressionI32::UMod: { - m_divideErrorJumpList.append(branchTest32(Zero, GPRInfo::regT1)); - if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) { - Jump denominatorNotNeg1 = branch32(NotEqual, GPRInfo::regT1, TrustedImm32(-1)); - m_divideErrorJumpList.append(branch32(Equal, GPRInfo::regT0, TrustedImm32(-2147483647-1))); - denominatorNotNeg1.link(this); - } -#if CPU(X86) || CPU(X86_64) - ASSERT(GPRInfo::regT0 == X86Registers::eax); - move(GPRInfo::regT1, X86Registers::ecx); - if (op == WASMOpExpressionI32::SDiv || op == WASMOpExpressionI32::SMod) { - x86ConvertToDoubleWord32(); - x86Div32(X86Registers::ecx); - } else { - ASSERT(op == WASMOpExpressionI32::UDiv || op == WASMOpExpressionI32::UMod); - xor32(X86Registers::edx, X86Registers::edx); - m_assembler.divl_r(X86Registers::ecx); - } - if (op == WASMOpExpressionI32::SMod || op == WASMOpExpressionI32::UMod) - move(X86Registers::edx, GPRInfo::regT0); -#else - // FIXME: We should be able to do an inline div on ARMv7 and ARM64. - switch (op) { - case WASMOpExpressionI32::SDiv: - callOperation(operationDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::UDiv: - callOperation(operationUnsignedDiv, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::SMod: - callOperation(operationMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::UMod: - callOperation(operationUnsignedMod, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); - break; - default: - ASSERT_NOT_REACHED(); - } -#endif - break; - } - case WASMOpExpressionI32::BitOr: - or32(GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::BitAnd: - and32(GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::BitXor: - xor32(GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::LeftShift: - lshift32(GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::ArithmeticRightShift: - rshift32(GPRInfo::regT1, GPRInfo::regT0); - break; - case WASMOpExpressionI32::LogicalRightShift: - urshift32(GPRInfo::regT1, GPRInfo::regT0); - break; - default: - ASSERT_NOT_REACHED(); - } - m_tempStackTop--; - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1)); - return UNUSED; - } - - int buildBinaryF32(int, int, WASMOpExpressionF32 op) - { - loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0); - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1); - convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1); - switch (op) { - case WASMOpExpressionF32::Add: - addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF32::Sub: - subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF32::Mul: - mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF32::Div: - divDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - m_tempStackTop--; - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1)); - return UNUSED; - } - - int buildBinaryF64(int, int, WASMOpExpressionF64 op) - { - loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0); - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1); - switch (op) { - case WASMOpExpressionF64::Add: - addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF64::Sub: - subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF64::Mul: - mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF64::Div: - divDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - case WASMOpExpressionF64::Mod: - case WASMOpExpressionF64::ATan2: - case WASMOpExpressionF64::Pow: - D_JITOperation_DD operation; - switch (op) { - case WASMOpExpressionF64::Mod: - operation = fmod; - break; - case WASMOpExpressionF64::ATan2: - operation = atan2; - break; - case WASMOpExpressionF64::Pow: - operation = pow; - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - callOperation(operation, FPRInfo::fpRegT0, FPRInfo::fpRegT1, FPRInfo::fpRegT0); - break; - default: - ASSERT_NOT_REACHED(); - } - m_tempStackTop--; - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop - 1)); - return UNUSED; - } - - int buildRelationalI32(int, int, WASMOpExpressionI32 op) - { - load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0); - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1); - RelationalCondition condition; - switch (op) { - case WASMOpExpressionI32::EqualI32: - condition = Equal; - break; - case WASMOpExpressionI32::NotEqualI32: - condition = NotEqual; - break; - case WASMOpExpressionI32::SLessThanI32: - condition = LessThan; - break; - case WASMOpExpressionI32::ULessThanI32: - condition = Below; - break; - case WASMOpExpressionI32::SLessThanOrEqualI32: - condition = LessThanOrEqual; - break; - case WASMOpExpressionI32::ULessThanOrEqualI32: - condition = BelowOrEqual; - break; - case WASMOpExpressionI32::SGreaterThanI32: - condition = GreaterThan; - break; - case WASMOpExpressionI32::UGreaterThanI32: - condition = Above; - break; - case WASMOpExpressionI32::SGreaterThanOrEqualI32: - condition = GreaterThanOrEqual; - break; - case WASMOpExpressionI32::UGreaterThanOrEqualI32: - condition = AboveOrEqual; - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - compare32(condition, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT0); - m_tempStackTop--; - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop - 1)); - return UNUSED; - } - - int buildRelationalF32(int, int, WASMOpExpressionI32 op) - { - loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0); - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1); - convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - convertFloatToDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT1); - DoubleCondition condition; - switch (op) { - case WASMOpExpressionI32::EqualF32: - condition = DoubleEqual; - break; - case WASMOpExpressionI32::NotEqualF32: - condition = DoubleNotEqual; - break; - case WASMOpExpressionI32::LessThanF32: - condition = DoubleLessThan; - break; - case WASMOpExpressionI32::LessThanOrEqualF32: - condition = DoubleLessThanOrEqual; - break; - case WASMOpExpressionI32::GreaterThanF32: - condition = DoubleGreaterThan; - break; - case WASMOpExpressionI32::GreaterThanOrEqualF32: - condition = DoubleGreaterThanOrEqual; - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - m_tempStackTop--; - Jump trueCase = branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1); - store32(TrustedImm32(0), temporaryAddress(m_tempStackTop - 1)); - Jump end = jump(); - trueCase.link(this); - store32(TrustedImm32(1), temporaryAddress(m_tempStackTop - 1)); - end.link(this); - return UNUSED; - } - - int buildRelationalF64(int, int, WASMOpExpressionI32 op) - { - loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0); - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1); - DoubleCondition condition; - switch (op) { - case WASMOpExpressionI32::EqualF64: - condition = DoubleEqual; - break; - case WASMOpExpressionI32::NotEqualF64: - condition = DoubleNotEqual; - break; - case WASMOpExpressionI32::LessThanF64: - condition = DoubleLessThan; - break; - case WASMOpExpressionI32::LessThanOrEqualF64: - condition = DoubleLessThanOrEqual; - break; - case WASMOpExpressionI32::GreaterThanF64: - condition = DoubleGreaterThan; - break; - case WASMOpExpressionI32::GreaterThanOrEqualF64: - condition = DoubleGreaterThanOrEqual; - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - m_tempStackTop--; - Jump trueCase = branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1); - store32(TrustedImm32(0), temporaryAddress(m_tempStackTop - 1)); - Jump end = jump(); - trueCase.link(this); - store32(TrustedImm32(1), temporaryAddress(m_tempStackTop - 1)); - end.link(this); - return UNUSED; - } - - int buildMinOrMaxI32(int, int, WASMOpExpressionI32 op) - { - load32(temporaryAddress(m_tempStackTop - 2), GPRInfo::regT0); - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1); - RelationalCondition condition; - switch (op) { - case WASMOpExpressionI32::SMin: - condition = LessThanOrEqual; - break; - case WASMOpExpressionI32::UMin: - condition = BelowOrEqual; - break; - case WASMOpExpressionI32::SMax: - condition = GreaterThanOrEqual; - break; - case WASMOpExpressionI32::UMax: - condition = AboveOrEqual; - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - Jump useLeft = branch32(condition, GPRInfo::regT0, GPRInfo::regT1); - store32(GPRInfo::regT1, temporaryAddress(m_tempStackTop - 2)); - useLeft.link(this); - m_tempStackTop--; - return UNUSED; - } - - int buildMinOrMaxF64(int, int, WASMOpExpressionF64 op) - { - loadDouble(temporaryAddress(m_tempStackTop - 2), FPRInfo::fpRegT0); - loadDouble(temporaryAddress(m_tempStackTop - 1), FPRInfo::fpRegT1); - DoubleCondition condition; - switch (op) { - case WASMOpExpressionF64::Min: - condition = DoubleLessThanOrEqual; - break; - case WASMOpExpressionF64::Max: - condition = DoubleGreaterThanOrEqual; - break; - default: - RELEASE_ASSERT_NOT_REACHED(); - } - Jump useLeft = branchDouble(condition, FPRInfo::fpRegT0, FPRInfo::fpRegT1); - storeDouble(FPRInfo::fpRegT1, temporaryAddress(m_tempStackTop - 2)); - useLeft.link(this); - m_tempStackTop--; - return UNUSED; - } - - int buildCallInternal(uint32_t functionIndex, int, const WASMSignature& signature, WASMExpressionType returnType) - { - boxArgumentsAndAdjustStackPointer(signature.arguments); - - JSFunction* function = m_module->functions()[functionIndex].get(); - move(TrustedImmPtr(function), GPRInfo::regT0); - - callAndUnboxResult(returnType); - return UNUSED; - } - - int buildCallIndirect(uint32_t functionPointerTableIndex, int, int, const WASMSignature& signature, WASMExpressionType returnType) - { - boxArgumentsAndAdjustStackPointer(signature.arguments); - - const Vector<JSFunction*>& functions = m_module->functionPointerTables()[functionPointerTableIndex].functions; - move(TrustedImmPtr(functions.data()), GPRInfo::regT0); - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT1); - m_tempStackTop--; - and32(TrustedImm32(functions.size() - 1), GPRInfo::regT1); - loadPtr(BaseIndex(GPRInfo::regT0, GPRInfo::regT1, timesPtr()), GPRInfo::regT0); - - callAndUnboxResult(returnType); - return UNUSED; - } - - int buildCallImport(uint32_t functionImportIndex, int, const WASMSignature& signature, WASMExpressionType returnType) - { - boxArgumentsAndAdjustStackPointer(signature.arguments); - - JSFunction* function = m_module->importedFunctions()[functionImportIndex].get(); - move(TrustedImmPtr(function), GPRInfo::regT0); - - callAndUnboxResult(returnType); - return UNUSED; - } - - void appendExpressionList(int&, int) { } - - void discard(int) - { - m_tempStackTop--; - } - - void linkTarget(JumpTarget& target) - { - target.label = label(); - target.jumpList.link(this); - } - - void jumpToTarget(JumpTarget& target) - { - if (target.label.isSet()) - jump(target.label); - else - target.jumpList.append(jump()); - } - - void jumpToTargetIf(JumpCondition condition, int, JumpTarget& target) - { - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0); - m_tempStackTop--; - Jump taken = branchTest32((condition == JumpCondition::Zero) ? Zero : NonZero, GPRInfo::regT0); - if (target.label.isSet()) - taken.linkTo(target.label, this); - else - target.jumpList.append(taken); - } - - void startLoop() - { - m_breakTargets.append(JumpTarget()); - m_continueTargets.append(JumpTarget()); - } - - void endLoop() - { - m_breakTargets.removeLast(); - m_continueTargets.removeLast(); - } - - void startSwitch() - { - m_breakTargets.append(JumpTarget()); - } - - void endSwitch() - { - m_breakTargets.removeLast(); - } - - void startLabel() - { - m_breakLabelTargets.append(JumpTarget()); - m_continueLabelTargets.append(JumpTarget()); - - linkTarget(m_continueLabelTargets.last()); - } - - void endLabel() - { - linkTarget(m_breakLabelTargets.last()); - - m_breakLabelTargets.removeLast(); - m_continueLabelTargets.removeLast(); - } - - JumpTarget& breakTarget() - { - return m_breakTargets.last(); - } - - JumpTarget& continueTarget() - { - return m_continueTargets.last(); - } - - JumpTarget& breakLabelTarget(uint32_t labelIndex) - { - return m_breakLabelTargets[labelIndex]; - } - - JumpTarget& continueLabelTarget(uint32_t labelIndex) - { - return m_continueLabelTargets[labelIndex]; - } - - void buildSwitch(int, const Vector<int64_t>& cases, Vector<JumpTarget>& targets, JumpTarget defaultTarget) - { - load32(temporaryAddress(m_tempStackTop - 1), GPRInfo::regT0); - m_tempStackTop--; - BinarySwitch binarySwitch(GPRInfo::regT0, cases, BinarySwitch::Int32); - while (binarySwitch.advance(*this)) { - unsigned index = binarySwitch.caseIndex(); - jump(targets[index].label); - } - binarySwitch.fallThrough().linkTo(defaultTarget.label, this); - } - -private: - union StackSlot { - int32_t intValue; - float floatValue; - double doubleValue; - }; - - enum class FloatingPointPrecision { Single, Double }; - - Address localAddress(unsigned localIndex) const - { - ASSERT(localIndex < m_numberOfLocals); - return Address(GPRInfo::callFrameRegister, -m_calleeSaveSpace - (localIndex + 1) * sizeof(StackSlot)); - } - - Address temporaryAddress(unsigned temporaryIndex) const - { - ASSERT(m_numberOfLocals + temporaryIndex < m_stackHeight); - return Address(GPRInfo::callFrameRegister, -m_calleeSaveSpace - (m_numberOfLocals + temporaryIndex + 1) * sizeof(StackSlot)); - } - - void appendCall(const FunctionPtr& function) - { - m_calls.append(std::make_pair(call(), function.value())); - } - - void appendCallWithExceptionCheck(const FunctionPtr& function) - { - appendCall(function); - m_exceptionChecks.append(emitExceptionCheck()); - } - - Call emitNakedCall(CodePtr function) - { - Call nakedCall = nearCall(); - m_calls.append(std::make_pair(nakedCall, function.executableAddress())); - return nakedCall; - } - - void appendCallSetResult(const FunctionPtr& function, GPRReg result) - { - appendCall(function); - move(GPRInfo::returnValueGPR, result); - } - -#if CPU(X86) - void appendCallSetResult(const FunctionPtr& function, FPRReg result, FloatingPointPrecision precision) - { - appendCall(function); - switch (precision) { - case FloatingPointPrecision::Single: - m_assembler.fstps(0, stackPointerRegister); - break; - case FloatingPointPrecision::Double: - m_assembler.fstpl(0, stackPointerRegister); - break; - } - loadDouble(stackPointerRegister, result); - } -#elif CPU(ARM) && !CPU(ARM_HARDFP) - void appendCallSetResult(const FunctionPtr& function, FPRReg result, FloatingPointPrecision) - { - appendCall(function); - m_assembler.vmov(result, GPRInfo::returnValueGPR, GPRInfo::returnValueGPR2); - } -#else // CPU(X86_64) || (CPU(ARM) && CPU(ARM_HARDFP)) || CPU(ARM64) || CPU(MIPS) || CPU(SH4) - void appendCallSetResult(const FunctionPtr& function, FPRReg result, FloatingPointPrecision) - { - appendCall(function); - moveDouble(FPRInfo::returnValueFPR, result); - } -#endif - -#if USE(JSVALUE64) - void callOperation(Z_JITOperation_EJ operation, GPRReg src, GPRReg dst) - { - setupArgumentsWithExecState(src); - appendCallSetResult(operation, dst); - } - - void callOperation(D_JITOperation_EJ operation, GPRReg src, FPRReg dst) - { - setupArgumentsWithExecState(src); - appendCallSetResult(operation, dst, FloatingPointPrecision::Double); - } -#else -// EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned on an even-numbered register (r0, r2 or [sp]). -// To prevent the assembler from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary. -#if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS) -#define EABI_32BIT_DUMMY_ARG TrustedImm32(0), -#else -#define EABI_32BIT_DUMMY_ARG -#endif - - void callOperation(Z_JITOperation_EJ operation, GPRReg srcTag, GPRReg srcPayload, GPRReg dst) - { - setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG srcPayload, srcTag); - appendCallSetResult(operation, dst); - } - - void callOperation(D_JITOperation_EJ operation, GPRReg srcTag, GPRReg srcPayload, FPRReg dst) - { - setupArgumentsWithExecState(EABI_32BIT_DUMMY_ARG srcPayload, srcTag); - appendCallSetResult(operation, dst, FloatingPointPrecision::Double); - } -#endif - - void callOperation(float JIT_OPERATION (*operation)(float), FPRegisterID src, FPRegisterID dst) - { - setupArguments(src); - appendCallSetResult(operation, dst, FloatingPointPrecision::Single); - } - - void callOperation(D_JITOperation_D operation, FPRegisterID src, FPRegisterID dst) - { - setupArguments(src); - appendCallSetResult(operation, dst, FloatingPointPrecision::Double); - } - - void callOperation(int32_t JIT_OPERATION (*operation)(int32_t, int32_t), GPRReg src1, GPRReg src2, GPRReg dst) - { - setupArguments(src1, src2); - appendCallSetResult(operation, dst); - } - - void callOperation(uint32_t JIT_OPERATION (*operation)(uint32_t, uint32_t), GPRReg src1, GPRReg src2, GPRReg dst) - { - setupArguments(src1, src2); - appendCallSetResult(operation, dst); - } - - void callOperation(D_JITOperation_DD operation, FPRegisterID src1, FPRegisterID src2, FPRegisterID dst) - { - setupArguments(src1, src2); - appendCallSetResult(operation, dst, FloatingPointPrecision::Double); - } - - void callOperation(double JIT_OPERATION (*operation)(uint32_t), GPRReg src, FPRegisterID dst) - { - setupArguments(src); - appendCallSetResult(operation, dst, FloatingPointPrecision::Double); - } - - void boxArgumentsAndAdjustStackPointer(const Vector<WASMType>& arguments) - { - size_t argumentCount = arguments.size(); - int stackOffset = -m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_numberOfLocals + m_tempStackTop + argumentCount + 1 + JSStack::CallFrameHeaderSize); - - storeTrustedValue(jsUndefined(), Address(GPRInfo::callFrameRegister, (stackOffset + CallFrame::thisArgumentOffset()) * sizeof(Register))); - - for (size_t i = 0; i < argumentCount; ++i) { - Address address(GPRInfo::callFrameRegister, (stackOffset + CallFrame::argumentOffset(i)) * sizeof(Register)); -#if USE(JSVALUE64) - JSValueRegs valueRegs(GPRInfo::regT0); -#else - JSValueRegs valueRegs(GPRInfo::regT1, GPRInfo::regT0); -#endif - switch (arguments[i]) { - case WASMType::I32: - load32(temporaryAddress(m_tempStackTop - argumentCount + i), GPRInfo::regT0); -#if USE(JSVALUE64) - or64(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0); - store64(GPRInfo::regT0, address); -#else - store32(GPRInfo::regT0, address.withOffset(PayloadOffset)); - store32(TrustedImm32(JSValue::Int32Tag), address.withOffset(TagOffset)); -#endif - break; - case WASMType::F32: - case WASMType::F64: - loadDouble(temporaryAddress(m_tempStackTop - argumentCount + i), FPRInfo::fpRegT0); - if (arguments[i] == WASMType::F32) - convertFloatToDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - convertDoubleToValue(FPRInfo::fpRegT0, valueRegs); - storeValue(valueRegs, address); - break; - default: - ASSERT_NOT_REACHED(); - } - } - m_tempStackTop -= argumentCount; - - addPtr(TrustedImm32(stackOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), GPRInfo::callFrameRegister, stackPointerRegister); - store32(TrustedImm32(argumentCount + 1), Address(stackPointerRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC))); - } - - void callAndUnboxResult(WASMExpressionType returnType) - { - // regT0 holds callee. -#if USE(JSVALUE64) - store64(GPRInfo::regT0, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) - sizeof(CallerFrameAndPC))); -#else - store32(GPRInfo::regT0, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC))); - store32(TrustedImm32(JSValue::CellTag), Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + TagOffset - sizeof(CallerFrameAndPC))); -#endif - - DataLabelPtr addressOfLinkedFunctionCheck; - Jump slowCase = branchPtrWithPatch(NotEqual, GPRInfo::regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0)); - - CallLinkInfo* info = m_codeBlock->addCallLinkInfo(); - info->setUpCall(CallLinkInfo::Call, CodeOrigin(), GPRInfo::regT0); - m_callCompilationInfo.append(CallCompilationInfo()); - m_callCompilationInfo.last().hotPathBegin = addressOfLinkedFunctionCheck; - m_callCompilationInfo.last().callLinkInfo = info; - m_callCompilationInfo.last().hotPathOther = nearCall(); - Jump end = jump(); - - slowCase.link(this); - move(TrustedImmPtr(info), GPRInfo::regT2); - m_callCompilationInfo.last().callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code()); - - end.link(this); - addPtr(TrustedImm32(-m_calleeSaveSpace - WTF::roundUpToMultipleOf(stackAlignmentRegisters(), m_stackHeight) * sizeof(StackSlot) - maxFrameExtentForSlowPathCall), GPRInfo::callFrameRegister, stackPointerRegister); - checkStackPointerAlignment(); - - // FIXME: No need to do type conversion if the callee is a WebAssembly function. - // https://bugs.webkit.org/show_bug.cgi?id=149310 -#if USE(JSVALUE64) - JSValueRegs valueRegs(GPRInfo::returnValueGPR); -#else - JSValueRegs valueRegs(GPRInfo::returnValueGPR2, GPRInfo::returnValueGPR); -#endif - switch (returnType) { - case WASMExpressionType::I32: - convertValueToInt32(valueRegs, GPRInfo::regT0); - store32(GPRInfo::regT0, temporaryAddress(m_tempStackTop++)); - break; - case WASMExpressionType::F32: - case WASMExpressionType::F64: -#if USE(JSVALUE64) - convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::nonPreservedNonReturnGPR); -#else - convertValueToDouble(valueRegs, FPRInfo::fpRegT0, GPRInfo::nonPreservedNonReturnGPR, FPRInfo::fpRegT1); -#endif - if (returnType == WASMExpressionType::F32) - convertDoubleToFloat(FPRInfo::fpRegT0, FPRInfo::fpRegT0); - storeDouble(FPRInfo::fpRegT0, temporaryAddress(m_tempStackTop++)); - break; - case WASMExpressionType::Void: - break; - default: - ASSERT_NOT_REACHED(); - } - } - -#if USE(JSVALUE64) - void convertValueToInt32(JSValueRegs valueRegs, GPRReg dst) - { - Jump checkJSInt32 = branchIfInt32(valueRegs); - - callOperation(operationConvertJSValueToInt32, valueRegs.gpr(), valueRegs.gpr()); - - checkJSInt32.link(this); - move(valueRegs.gpr(), dst); - } - - void convertValueToDouble(JSValueRegs valueRegs, FPRReg dst, GPRReg scratch) - { - Jump checkJSInt32 = branchIfInt32(valueRegs); - Jump checkJSNumber = branchIfNumber(valueRegs, scratch); - JumpList end; - - callOperation(operationConvertJSValueToDouble, valueRegs.gpr(), dst); - end.append(jump()); - - checkJSInt32.link(this); - convertInt32ToDouble(valueRegs.gpr(), dst); - end.append(jump()); - - checkJSNumber.link(this); - unboxDoubleWithoutAssertions(valueRegs.gpr(), dst); - end.link(this); - } -#else - void convertValueToInt32(JSValueRegs valueRegs, GPRReg dst) - { - Jump checkJSInt32 = branchIfInt32(valueRegs); - - callOperation(operationConvertJSValueToInt32, valueRegs.tagGPR(), valueRegs.payloadGPR(), valueRegs.payloadGPR()); - - checkJSInt32.link(this); - move(valueRegs.payloadGPR(), dst); - } - - void convertValueToDouble(JSValueRegs valueRegs, FPRReg dst, GPRReg scratch, FPRReg fpScratch) - { - Jump checkJSInt32 = branchIfInt32(valueRegs); - Jump checkJSNumber = branchIfNumber(valueRegs, scratch); - JumpList end; - - callOperation(operationConvertJSValueToDouble, valueRegs.tagGPR(), valueRegs.payloadGPR(), dst); - end.append(jump()); - - checkJSInt32.link(this); - convertInt32ToDouble(valueRegs.payloadGPR(), dst); - end.append(jump()); - - checkJSNumber.link(this); - unboxDouble(valueRegs.tagGPR(), valueRegs.payloadGPR(), dst, fpScratch); - end.link(this); - } -#endif - - void convertDoubleToValue(FPRReg fpr, JSValueRegs valueRegs) - { -#if USE(JSVALUE64) - boxDouble(fpr, valueRegs.gpr()); -#else - boxDouble(fpr, valueRegs.tagGPR(), valueRegs.payloadGPR()); -#endif - } - - JSWASMModule* m_module; - unsigned m_stackHeight; - unsigned m_numberOfLocals; - unsigned m_tempStackTop { 0 }; - unsigned m_calleeSaveSpace; - - Vector<JumpTarget> m_breakTargets; - Vector<JumpTarget> m_continueTargets; - Vector<JumpTarget> m_breakLabelTargets; - Vector<JumpTarget> m_continueLabelTargets; - - Label m_beginLabel; - Jump m_stackOverflow; - JumpList m_divideErrorJumpList; - JumpList m_outOfBoundsErrorJumpList; - JumpList m_exceptionChecks; - - Vector<std::pair<Call, void*>> m_calls; - Vector<CallCompilationInfo> m_callCompilationInfo; -}; - -} // namespace JSC - -#endif // ENABLE(WEBASSEMBLY) - -#endif // WASMFunctionCompiler_h |
