From 4f3a70283a0e20a6d4e5b8cf9d88e1105bde41cf Mon Sep 17 00:00:00 2001 From: Michael Ferris Date: Thu, 26 Jan 2017 17:05:43 -0800 Subject: [PATCH] Rebase + self code review Change the type of config flag for WasmFastArray --- lib/Backend/IRBuilderAsmJs.cpp | 2 +- lib/Backend/Lower.cpp | 4 +- lib/Backend/amd64/LowererMDArch.cpp | 4 +- lib/Backend/i386/LowererMDArch.cpp | 2 +- lib/Common/ConfigFlagsList.h | 11 ++-- lib/Runtime/Library/ArrayBuffer.cpp | 65 +++++++++-------------- lib/Runtime/Library/ArrayBuffer.h | 6 +-- lib/Runtime/Library/WebAssemblyMemory.cpp | 2 +- lib/Runtime/Library/WebAssemblyMemory.h | 2 +- test/wasm/fastarray.js | 4 ++ test/wasm/rlexe.xml | 4 +- test/wasm/wasts/fastarray.wast | 4 ++ 12 files changed, 54 insertions(+), 56 deletions(-) diff --git a/lib/Backend/IRBuilderAsmJs.cpp b/lib/Backend/IRBuilderAsmJs.cpp index 98d486bd0df..8ddb717ebef 100644 --- a/lib/Backend/IRBuilderAsmJs.cpp +++ b/lib/Backend/IRBuilderAsmJs.cpp @@ -1581,7 +1581,7 @@ IRBuilderAsmJs::BuildAsmTypedArr(Js::OpCodeAsmJs newOpcode, uint32 offset, uint3 } #if ENABLE_FAST_ARRAYBUFFER - if (isWasm && !PHASE_ON1(Js::WasmFastArrayPhase)) + if (isWasm && !CONFIG_FLAG(WasmFastArray)) #endif { instr->SetSrc2(BuildSrcOpnd(AsmJsRegSlots::LengthReg, TyUint32)); diff --git a/lib/Backend/Lower.cpp b/lib/Backend/Lower.cpp index efca7160c65..1ccedabe1d6 100644 --- a/lib/Backend/Lower.cpp +++ b/lib/Backend/Lower.cpp @@ -9165,7 +9165,7 @@ Lowerer::LowerLdArrViewElem(IR::Instr * instr) IR::Instr * Lowerer::LowerLdArrViewElemWasm(IR::Instr * instr) { -#ifdef ASMJS_PLAT +#ifdef ENABLE_WASM Assert(m_func->GetJITFunctionBody()->IsWasmFunction()); Assert(instr); Assert(instr->m_opcode == Js::OpCode::LdArrViewElemWasm); @@ -9193,7 +9193,7 @@ Lowerer::LowerLdArrViewElemWasm(IR::Instr * instr) newMove = InsertMove(dst, src1, done); } -#ifdef _WIN64 +#ifdef ENABLE_FAST_ARRAYBUFFER // We need to have an AV when accessing out of bounds memory even if the dst is not used // Make sure LinearScan doesn't dead store this instruction newMove->hasSideEffects = true; diff --git a/lib/Backend/amd64/LowererMDArch.cpp b/lib/Backend/amd64/LowererMDArch.cpp index fc3f24418de..b0254dd5a4c 100644 --- a/lib/Backend/amd64/LowererMDArch.cpp +++ b/lib/Backend/amd64/LowererMDArch.cpp @@ -1118,12 +1118,10 @@ LowererMDArch::LowerAsmJsCallI(IR::Instr * callInstr) IR::Instr * LowererMDArch::LowerWasmMemOp(IR::Instr * instr, IR::Opnd *addrOpnd) { -#if ENABLE_FAST_ARRAYBUFFER - if (PHASE_ON1(Js::WasmFastArrayPhase)) + if (CONFIG_FLAG(WasmFastArray)) { return instr; } -#endif Assert(instr->GetSrc2()); IR::LabelInstr * helperLabel = Lowerer::InsertLabel(true, instr); diff --git a/lib/Backend/i386/LowererMDArch.cpp b/lib/Backend/i386/LowererMDArch.cpp index 8ff05ce1b3c..fd39426b95b 100644 --- a/lib/Backend/i386/LowererMDArch.cpp +++ b/lib/Backend/i386/LowererMDArch.cpp @@ -988,7 +988,7 @@ LowererMDArch::LowerWasmMemOp(IR::Instr * instr, IR::Opnd *addrOpnd) lowererMD->m_lowerer->InsertCompareBranch(cmpOpnd, arrayLenOpnd, Js::OpCode::BrGe_A, true, helperLabel, helperLabel); } - lowererMD->m_lowerer->GenerateThrow(IR::IntConstOpnd::New(WASMERR_ArrayIndexOutOfRange, TyInt32, m_func), loadLabel); + lowererMD->m_lowerer->GenerateRuntimeError(loadLabel, WASMERR_ArrayIndexOutOfRange, IR::HelperOp_WebAssemblyRuntimeError); Lowerer::InsertBranch(Js::OpCode::Br, loadLabel, helperLabel); Assert(indexPair.low->IsRegOpnd()); diff --git a/lib/Common/ConfigFlagsList.h b/lib/Common/ConfigFlagsList.h index 054b5abf50d..fcdfd543401 100644 --- a/lib/Common/ConfigFlagsList.h +++ b/lib/Common/ConfigFlagsList.h @@ -40,7 +40,6 @@ PHASE(All) PHASE(WasmFunctionBody) PHASE(WasmDeferred) PHASE(WasmValidatePrejit) - PHASE(WasmFastArray) PHASE(Asmjs) PHASE(AsmjsTmpRegisterAllocation) PHASE(AsmjsEncoder) @@ -381,7 +380,12 @@ PHASE(All) #define DEFAULT_CONFIG_SIMDJS (false) #endif #define DEFAULT_CONFIG_WASM (false) -#define DEFAULT_CONFIG_WASM_I64 (false) +#define DEFAULT_CONFIG_WasmI64 (false) +#if ENABLE_FAST_ARRAYBUFFER + #define DEFAULT_CONFIG_WasmFastArray (true) +#else + #define DEFAULT_CONFIG_WasmFastArray (false) +#endif #define DEFAULT_CONFIG_BgJitDelayFgBuffer (0) #define DEFAULT_CONFIG_BgJitPendingFuncCap (31) #define DEFAULT_CONFIG_CurrentSourceInfo (true) @@ -847,7 +851,8 @@ FLAGNR(String, AsmDumpMode , "Dump the final assembly to a file witho FLAGR (Boolean, Asmjs , "Enable Asmjs", DEFAULT_CONFIG_ASMJS) FLAGNR(Boolean, AsmJsStopOnError , "Stop execution on any AsmJs validation errors", DEFAULT_CONFIG_AsmJsStopOnError) FLAGNR(Boolean, AsmJsEdge , "Enable asm.js features which may have backward incompatible changes or not validate on old demos", DEFAULT_CONFIG_AsmJsEdge) -FLAGNR(Boolean, WasmI64 , "Enable Int64 testing for WebAssembly. ArgIns can be [number,string,{low:number,high:number}]. Return values will be {low:number,high:number}", DEFAULT_CONFIG_WASM_I64) +FLAGNR(Boolean, WasmI64 , "Enable Int64 testing for WebAssembly. ArgIns can be [number,string,{low:number,high:number}]. Return values will be {low:number,high:number}", DEFAULT_CONFIG_WasmI64) +FLAGNR(Boolean, WasmFastArray , "Enable fast array implementation for WebAssembly", DEFAULT_CONFIG_WasmFastArray) #ifndef COMPILE_DISABLE_Simdjs #define COMPILE_DISABLE_Simdjs 0 diff --git a/lib/Runtime/Library/ArrayBuffer.cpp b/lib/Runtime/Library/ArrayBuffer.cpp index e15a90e2ded..5f7ddae5bf1 100644 --- a/lib/Runtime/Library/ArrayBuffer.cpp +++ b/lib/Runtime/Library/ArrayBuffer.cpp @@ -583,52 +583,37 @@ namespace Js #endif } - bool JavascriptArrayBuffer::IsValidAsmJsBufferLength(uint length, bool forceCheck) + bool JavascriptArrayBuffer::IsValidAsmJsBufferLengthAlgo(uint length, bool forceCheck) { -#if ENABLE_FAST_ARRAYBUFFER /* 1. length >= 2^16 2. length is power of 2 or (length > 2^24 and length is multiple of 2^24) 3. length is a multiple of 4K */ - return ((length >= 0x10000) && - (((length & (~length + 1)) == length) || - (length >= 0x1000000 && ((length & 0xFFFFFF) == 0)) - ) && - ((length % AutoSystemInfo::PageSize) == 0) - ); - -#else - if (forceCheck) - { - return ((length >= 0x10000) && - (((length & (~length + 1)) == length) || - (length >= 0x1000000 && ((length & 0xFFFFFF) == 0)) - ) && - ((length & 0x0FFF) == 0) - ); - } - return false; + const bool isLongEnough = length >= 0x10000; + const bool isPow2 = ::Math::IsPow2(length); + // No need to check for length > 2^24, because it already has to be non zero length + const bool isMultipleOf2e24 = (length & 0xFFFFFF) == 0; + const bool isPageSizeMultiple = (length % AutoSystemInfo::PageSize) == 0; + return ( +#ifndef ENABLE_FAST_ARRAYBUFFER + forceCheck && #endif + isLongEnough && + (isPow2 || isMultipleOf2e24) && + isPageSizeMultiple + ); + } + bool JavascriptArrayBuffer::IsValidAsmJsBufferLength(uint length, bool forceCheck) + { + return IsValidAsmJsBufferLengthAlgo(length, forceCheck); } bool JavascriptArrayBuffer::IsValidVirtualBufferLength(uint length) { #if ENABLE_FAST_ARRAYBUFFER - /* - 1. length >= 2^16 - 2. length is power of 2 or (length > 2^24 and length is multiple of 2^24) - 3. length is a multiple of 4K - */ - return ( - !PHASE_OFF1(Js::TypedArrayVirtualPhase) && - (length >= 0x10000) && - ( - ((length & (~length + 1)) == length) || - (length >= 0x1000000 && ((length & 0xFFFFFF) == 0)) - ) && - ((length % AutoSystemInfo::PageSize) == 0)); + return !PHASE_OFF1(Js::TypedArrayVirtualPhase) && IsValidAsmJsBufferLengthAlgo(length, true); #else return false; #endif @@ -841,7 +826,10 @@ namespace Js WebAssemblyArrayBuffer::WebAssemblyArrayBuffer(uint32 length, DynamicType * type) : -#if ENABLE_FAST_ARRAYBUFFER +#ifndef ENABLE_FAST_ARRAYBUFFER + // Treat as a normal JavascriptArrayBuffer + JavascriptArrayBuffer(length, type) {} +#else JavascriptArrayBuffer(length, type, WasmVirtualAllocator) { // Make sure we always have a buffer even if the length is 0 @@ -850,12 +838,12 @@ namespace Js // We want to allocate an empty buffer using virtual memory Assert(length == 0); buffer = (BYTE*)WasmVirtualAllocator(0); - // We should throw out of memory if the allocation fails - Assert(buffer != nullptr); + if (buffer == nullptr) + { + JavascriptError::ThrowOutOfMemoryError(GetScriptContext()); + } } } -#else - JavascriptArrayBuffer(length, type) {} #endif WebAssemblyArrayBuffer::WebAssemblyArrayBuffer(byte* buffer, uint32 length, DynamicType * type): @@ -1000,5 +988,4 @@ namespace Js TTD::NSSnapObjects::StdExtractSetKindSpecificInfo(objData, sabi); } #endif - } diff --git a/lib/Runtime/Library/ArrayBuffer.h b/lib/Runtime/Library/ArrayBuffer.h index cced683d263..45da28d5dd8 100644 --- a/lib/Runtime/Library/ArrayBuffer.h +++ b/lib/Runtime/Library/ArrayBuffer.h @@ -14,7 +14,7 @@ namespace Js class ArrayBufferBase : public DynamicObject { protected: -#if _WIN64 +#if ENABLE_FAST_ARRAYBUFFER #define MAX_ASMJS_ARRAYBUFFER_LENGTH 0x100000000 // 4GB #define MAX_WASM__ARRAYBUFFER_LENGTH 0x200000000 // 8GB #define AsmJsVirtualAllocator Js::ArrayBuffer::AllocWrapper @@ -51,7 +51,7 @@ namespace Js #else static void* __cdecl AllocWrapper(DECLSPEC_GUARD_OVERFLOW size_t length) { - // This allocator should only be used + // This allocator should never be used Js::Throw::FatalInternalError(); } #define AsmJsVirtualAllocator Js::ArrayBuffer::AllocWrapper @@ -254,8 +254,8 @@ namespace Js virtual void Dispose(bool isShutdown) override; virtual void Finalize(bool isShutdown) override; + static bool IsValidAsmJsBufferLengthAlgo(uint length, bool forceCheck); virtual bool IsValidAsmJsBufferLength(uint length, bool forceCheck = false) override; - virtual bool IsValidVirtualBufferLength(uint length) override; virtual ArrayBuffer * TransferInternal(DECLSPEC_GUARD_OVERFLOW uint32 newBufferLength) override; diff --git a/lib/Runtime/Library/WebAssemblyMemory.cpp b/lib/Runtime/Library/WebAssemblyMemory.cpp index 3e1100b1a78..6b0cd1c894e 100644 --- a/lib/Runtime/Library/WebAssemblyMemory.cpp +++ b/lib/Runtime/Library/WebAssemblyMemory.cpp @@ -190,7 +190,7 @@ WebAssemblyMemory::CreateMemoryObject(uint32 initial, uint32 maximum, ScriptCont uint32 byteLength = UInt32Math::Mul(initial); ArrayBuffer* buffer; #if ENABLE_FAST_ARRAYBUFFER - if (PHASE_ON1(Js::WasmFastArrayPhase)) + if (CONFIG_FLAG(WasmFastArray)) { buffer = scriptContext->GetLibrary()->CreateWebAssemblyArrayBuffer(byteLength); } diff --git a/lib/Runtime/Library/WebAssemblyMemory.h b/lib/Runtime/Library/WebAssemblyMemory.h index 3b5e8ee2614..c2272be7d11 100644 --- a/lib/Runtime/Library/WebAssemblyMemory.h +++ b/lib/Runtime/Library/WebAssemblyMemory.h @@ -12,9 +12,9 @@ namespace Js protected: DEFINE_VTABLE_CTOR( WebAssemblyMemory, DynamicObject ); DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT( WebAssemblyMemory ); + #ifdef ENABLE_WASM public: - class EntryInfo { public: diff --git a/test/wasm/fastarray.js b/test/wasm/fastarray.js index 52ebcb65064..84c0609cdb2 100644 --- a/test/wasm/fastarray.js +++ b/test/wasm/fastarray.js @@ -1,3 +1,7 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft Corporation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- function checkTrap(fn) { try { fn(); diff --git a/test/wasm/rlexe.xml b/test/wasm/rlexe.xml index 376a3d4643a..92bee7f8042 100644 --- a/test/wasm/rlexe.xml +++ b/test/wasm/rlexe.xml @@ -10,13 +10,13 @@ fastarray.js - -wasm + -wasm -WasmFastArray- fastarray.js - -wasm -on:WasmFastArray + -wasm -WasmFastArray diff --git a/test/wasm/wasts/fastarray.wast b/test/wasm/wasts/fastarray.wast index 13d54fb2f22..ac23236b11c 100644 --- a/test/wasm/wasts/fastarray.wast +++ b/test/wasm/wasts/fastarray.wast @@ -1,3 +1,7 @@ +;;------------------------------------------------------------------------------------------------------- +;; Copyright (C) Microsoft Corporation and contributors. All rights reserved. +;; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +;;------------------------------------------------------------------------------------------------------- (module (memory (export "mem") 0) (func (export "load") (param $i i32)