Bladeren bron

Always create a WebAssemblyArrayBuffer for WebAssemblyMemory.
Only GrowMemory is allowed to detach WebAssemblyMemory.

Michael Ferris 8 jaren geleden
bovenliggende
commit
8cf7fffdb1

+ 7 - 5
lib/Parser/rterrors.h

@@ -365,6 +365,9 @@ RT_ERROR_MSG(JSERR_CantDeleteNonConfigProp, 5666, "Cannot delete non-configurabl
 RT_ERROR_MSG(JSERR_CantRedefineProp, 5667, "Cannot redefine property '%s'", "Cannot redefine property", kjstTypeError, 0)
 RT_ERROR_MSG(JSERR_FunctionArgument_NeedArrayLike, 5668, "%s: argument is not an array or array-like object", "Array or array-like object expected", kjstTypeError, 0)
 RT_ERROR_MSG(JSERR_FatalMemoryExhaustion, 5669, "", "Encountered a non-recoverable OOM", kjstError, 0)
+RT_ERROR_MSG(JSERR_OutOfBoundString, 5670, "", "String length is out of bound", kjstRangeError, 0)
+RT_ERROR_MSG(JSERR_InvalidIterableObject, 5671, "%s : Invalid iterable object", "Invalid iterable object", kjstTypeError, 0)
+RT_ERROR_MSG(JSERR_InvalidIteratorObject, 5672, "%s : Invalid iterator object", "Invalid iterator object", kjstTypeError, 0)
 
 // WebAssembly Errors
 RT_ERROR_MSG(WASMERR_WasmCompileError, 7000, "%s", "Compilation failed.", kjstWebAssemblyCompileError, 0)
@@ -387,11 +390,10 @@ RT_ERROR_MSG(WASMERR_TableIndexOutOfRange, 7016, "", "Table index is out of rang
 RT_ERROR_MSG(WASMERR_ArrayIndexOutOfRange, 7017, "", "Memory index is out of range", kjstWebAssemblyRuntimeError, 0)
 RT_ERROR_MSG(WASMERR_InvalidInstantiateArgument, 7018, "", "Invalid arguments to instantiate", kjstTypeError, 0)
 RT_ERROR_MSG(WASMERR_WasmLinkError, 7019, "%s", "Linking failed.", kjstWebAssemblyLinkError, 0)
-RT_ERROR_MSG(JSERR_OutOfBoundString, 7020, "", "String length is out of bound", kjstRangeError, 0)
-RT_ERROR_MSG(JSERR_InvalidIterableObject, 7021, "%s : Invalid iterable object", "Invalid iterable object", kjstTypeError, 0)
-RT_ERROR_MSG(JSERR_InvalidIteratorObject, 7022, "%s : Invalid iterator object", "Invalid iterator object", kjstTypeError, 0)
-RT_ERROR_MSG(WASMERR_NeedResponse, 7023, "%s is not a Reponse", "Response expected", kjstTypeError, 0)
-RT_ERROR_MSG(WASMERR_LinkSignatureMismatch, 7024, "Cannot link import %s in link table due to a signature mismatch", "Function called with invalid signature", kjstWebAssemblyRuntimeError, 0)
+RT_ERROR_MSG(WASMERR_NeedResponse, 7020, "%s is not a Reponse", "Response expected", kjstTypeError, 0)
+RT_ERROR_MSG(WASMERR_CantDetach, 7021, "", "Not allowed to detach WebAssembly.Memory buffer", kjstTypeError, 0)
+RT_ERROR_MSG(WASMERR_BufferGrowOnly, 7022, "", "WebAssembly.Memory can only grow", kjstTypeError, 0)
+RT_ERROR_MSG(WASMERR_LinkSignatureMismatch, 7023, "Cannot link import %s in link table due to a signature mismatch", "Function called with invalid signature", kjstWebAssemblyRuntimeError, 0)
 
 // Wabt Errors
 RT_ERROR_MSG(WABTERR_WabtError, 7200, "%s", "Wabt Error.", kjstTypeError, 0)

+ 74 - 23
lib/Runtime/Library/ArrayBuffer.cpp

@@ -950,32 +950,42 @@ namespace Js
 #endif
 
 
-
-    WebAssemblyArrayBuffer::WebAssemblyArrayBuffer(uint32 length, DynamicType * type) :
-#ifndef ENABLE_FAST_ARRAYBUFFER
-        // Treat as a normal JavascriptArrayBuffer
-        JavascriptArrayBuffer(length, type) {}
-#else
-        JavascriptArrayBuffer(length, type, WasmVirtualAllocator)
+    template<typename Allocator>
+    Js::WebAssemblyArrayBuffer::WebAssemblyArrayBuffer(uint32 length, DynamicType * type, Allocator allocator):
+        JavascriptArrayBuffer(length, type, allocator)
     {
+#ifndef ENABLE_FAST_ARRAYBUFFER
+        CompileAssert(UNREACHED);
+#endif
+        Assert(allocator == WasmVirtualAllocator);
         // Make sure we always have a buffer even if the length is 0
         if (buffer == nullptr)
         {
             // We want to allocate an empty buffer using virtual memory
             Assert(length == 0);
-            buffer = (BYTE*)WasmVirtualAllocator(0);
+            buffer = (BYTE*)allocator(0);
             if (buffer == nullptr)
             {
                 JavascriptError::ThrowOutOfMemoryError(GetScriptContext());
             }
         }
     }
-#endif
+
+    // Treat as a normal JavascriptArrayBuffer
+    WebAssemblyArrayBuffer::WebAssemblyArrayBuffer(uint32 length, DynamicType * type) :
+        JavascriptArrayBuffer(length, type, malloc)
+    {
+    }
 
     WebAssemblyArrayBuffer::WebAssemblyArrayBuffer(byte* buffer, uint32 length, DynamicType * type):
         JavascriptArrayBuffer(buffer, length, type)
     {
-
+#if ENABLE_FAST_ARRAYBUFFER
+        if (CONFIG_FLAG(WasmFastArray) && buffer == nullptr)
+        {
+            JavascriptError::ThrowOutOfMemoryError(GetScriptContext());
+        }
+#endif
     }
 
     WebAssemblyArrayBuffer* WebAssemblyArrayBuffer::Create(byte* buffer, uint32 length, DynamicType * type)
@@ -988,7 +998,16 @@ namespace Js
         }
         else
         {
-            result = RecyclerNewFinalized(recycler, WebAssemblyArrayBuffer, length, type);
+#if ENABLE_FAST_ARRAYBUFFER
+            if (CONFIG_FLAG(WasmFastArray))
+            {
+                result = RecyclerNewFinalized(recycler, WebAssemblyArrayBuffer, length, type, WasmVirtualAllocator);
+            }
+            else
+#endif
+            {
+                result = RecyclerNewFinalized(recycler, WebAssemblyArrayBuffer, length, type);
+            }
         }
         Assert(result);
         recycler->AddExternalMemoryUsage(length);
@@ -998,21 +1017,26 @@ namespace Js
     bool WebAssemblyArrayBuffer::IsValidVirtualBufferLength(uint length) const
     {
 #if ENABLE_FAST_ARRAYBUFFER
-        return true;
+        return CONFIG_FLAG(WasmFastArray);
 #else
         return false;
 #endif
     }
 
-    ArrayBuffer * WebAssemblyArrayBuffer::TransferInternal(uint32 newBufferLength)
+    WebAssemblyArrayBuffer* WebAssemblyArrayBuffer::GrowMemory(uint32 newBufferLength)
     {
-#if ENABLE_FAST_ARRAYBUFFER
-        ReportDifferentialAllocation(newBufferLength);
-        Assert(this->buffer);
+        if (newBufferLength <= this->bufferLength)
+        {
+            JavascriptError::ThrowTypeError(GetScriptContext(), WASMERR_BufferGrowOnly);
+        }
 
-        AssertMsg(newBufferLength > this->bufferLength, "The only supported scenario in WebAssembly is to grow the memory");
-        if (newBufferLength > this->bufferLength)
+        WebAssemblyArrayBuffer* newArrayBuffer = nullptr;
+#if ENABLE_FAST_ARRAYBUFFER
+        if (CONFIG_FLAG(WasmFastArray))
         {
+            ReportDifferentialAllocation(newBufferLength);
+            AssertOrFailFast(this->buffer);
+
             LPVOID newMem = VirtualAlloc(this->buffer + this->bufferLength, newBufferLength - this->bufferLength, MEM_COMMIT, PAGE_READWRITE);
             if (!newMem)
             {
@@ -1020,16 +1044,43 @@ namespace Js
                 recycler->ReportExternalMemoryFailure(newBufferLength);
                 JavascriptError::ThrowOutOfMemoryError(GetScriptContext());
             }
+            newArrayBuffer = GetLibrary()->CreateWebAssemblyArrayBuffer(this->buffer, newBufferLength);
+        }
+        else
+#endif
+        if (this->GetByteLength() == 0)
+        {
+            newArrayBuffer = GetLibrary()->CreateWebAssemblyArrayBuffer(newBufferLength);
+            if (!newArrayBuffer->GetByteLength())
+            {
+                JavascriptError::ThrowOutOfMemoryError(GetScriptContext());
+            }
+        }
+        else
+        {
+            ReportDifferentialAllocation(newBufferLength);
+            byte* newBuffer = ReallocZero(this->buffer, this->bufferLength, newBufferLength);
+            if (!newBuffer)
+            {
+                this->GetRecycler()->ReportExternalMemoryFailure(newBufferLength - this->bufferLength);
+                JavascriptError::ThrowOutOfMemoryError(GetScriptContext());
+            }
+            newArrayBuffer = GetLibrary()->CreateWebAssemblyArrayBuffer(newBuffer, newBufferLength);
+        }
+
+        if (!newArrayBuffer)
+        {
+            JavascriptError::ThrowOutOfMemoryError(GetScriptContext());
         }
-        ArrayBuffer* newArrayBuffer = GetLibrary()->CreateWebAssemblyArrayBuffer(this->buffer, newBufferLength);
 
         AutoDiscardPTR<Js::ArrayBufferDetachedStateBase> state(DetachAndGetState());
         state->MarkAsClaimed();
-
         return newArrayBuffer;
-#else
-        return JavascriptArrayBuffer::TransferInternal(newBufferLength);
-#endif
+    }
+
+    ArrayBuffer * WebAssemblyArrayBuffer::TransferInternal(uint32 newBufferLength)
+    {
+        JavascriptError::ThrowTypeError(GetScriptContext(), WASMERR_CantDetach);
     }
 
     ProjectionArrayBuffer::ProjectionArrayBuffer(uint32 length, DynamicType * type) :

+ 6 - 0
lib/Runtime/Library/ArrayBuffer.h

@@ -72,6 +72,7 @@ namespace Js
 
         virtual bool IsArrayBuffer() = 0;
         virtual bool IsSharedArrayBuffer() = 0;
+        virtual bool IsWebAssemblyArrayBuffer() { return false; }
         virtual ArrayBuffer * GetAsArrayBuffer() = 0;
         virtual SharedArrayBuffer * GetAsSharedArrayBuffer() { return nullptr; }
         virtual void AddParent(ArrayBufferParent* parent) { }
@@ -279,6 +280,8 @@ namespace Js
 
     class WebAssemblyArrayBuffer : public JavascriptArrayBuffer
     {
+        template<typename Allocator>
+        WebAssemblyArrayBuffer(uint32 length, DynamicType * type, Allocator allocator);
         WebAssemblyArrayBuffer(uint32 length, DynamicType * type);
         WebAssemblyArrayBuffer(byte* buffer, uint32 length, DynamicType * type);
     protected:
@@ -286,8 +289,11 @@ namespace Js
         DEFINE_MARSHAL_OBJECT_TO_SCRIPT_CONTEXT(WebAssemblyArrayBuffer);
     public:
         static WebAssemblyArrayBuffer* Create(byte* buffer, DECLSPEC_GUARD_OVERFLOW uint32 length, DynamicType * type);
+        WebAssemblyArrayBuffer* GrowMemory(DECLSPEC_GUARD_OVERFLOW uint32 newBufferLength);
+
         virtual bool IsValidVirtualBufferLength(uint length) const override;
         virtual ArrayBuffer * TransferInternal(DECLSPEC_GUARD_OVERFLOW uint32 newBufferLength) override;
+        virtual bool IsWebAssemblyArrayBuffer() override { return true; }
     };
 
     // the memory must be allocated via CoTaskMemAlloc.

+ 2 - 2
lib/Runtime/Library/JavascriptLibrary.cpp

@@ -6185,12 +6185,12 @@ namespace Js
         return arr;
     }
 
-    Js::ArrayBuffer* JavascriptLibrary::CreateWebAssemblyArrayBuffer(uint32 length)
+    Js::WebAssemblyArrayBuffer* JavascriptLibrary::CreateWebAssemblyArrayBuffer(uint32 length)
     {
         return WebAssemblyArrayBuffer::Create(nullptr, length, arrayBufferType);
     }
 
-    Js::ArrayBuffer* JavascriptLibrary::CreateWebAssemblyArrayBuffer(byte* buffer, uint32 length)
+    Js::WebAssemblyArrayBuffer* JavascriptLibrary::CreateWebAssemblyArrayBuffer(byte* buffer, uint32 length)
     {
         return WebAssemblyArrayBuffer::Create(buffer, length, arrayBufferType);
     }

+ 2 - 2
lib/Runtime/Library/JavascriptLibrary.h

@@ -949,8 +949,8 @@ namespace Js
         JavascriptArray* CreateArray(uint32 length, uint32 size);
         ArrayBuffer* CreateArrayBuffer(uint32 length);
         ArrayBuffer* CreateArrayBuffer(byte* buffer, uint32 length);
-        ArrayBuffer* CreateWebAssemblyArrayBuffer(uint32 length);
-        ArrayBuffer* CreateWebAssemblyArrayBuffer(byte* buffer, uint32 length);
+        class WebAssemblyArrayBuffer* CreateWebAssemblyArrayBuffer(uint32 length);
+        class WebAssemblyArrayBuffer* CreateWebAssemblyArrayBuffer(byte* buffer, uint32 length);
         SharedArrayBuffer* CreateSharedArrayBuffer(uint32 length);
         SharedArrayBuffer* CreateSharedArrayBuffer(SharedContents *contents);
         ArrayBuffer* CreateProjectionArraybuffer(uint32 length);

+ 6 - 16
lib/Runtime/Library/WebAssemblyMemory.cpp

@@ -10,7 +10,7 @@
 namespace Js
 {
 
-WebAssemblyMemory::WebAssemblyMemory(ArrayBuffer * buffer, uint32 initial, uint32 maximum, DynamicType * type) :
+WebAssemblyMemory::WebAssemblyMemory(WebAssemblyArrayBuffer* buffer, uint32 initial, uint32 maximum, DynamicType * type) :
     DynamicObject(type),
     m_buffer(buffer),
     m_initial(initial),
@@ -144,11 +144,11 @@ WebAssemblyMemory::GrowInternal(uint32 deltaPages)
         return -1;
     }
 
-    ArrayBuffer * newBuffer = nullptr;
+    WebAssemblyArrayBuffer * newBuffer = nullptr;
     JavascriptExceptionObject* caughtExceptionObject = nullptr;
     try
     {
-        newBuffer = m_buffer->TransferInternal(newBytes);
+        newBuffer = m_buffer->GrowMemory(newBytes);
     }
     catch (const JavascriptException& err)
     {
@@ -157,7 +157,7 @@ WebAssemblyMemory::GrowInternal(uint32 deltaPages)
         return -1;
     }
 
-    Assert(newBuffer);
+    AssertOrFailFast(newBuffer);
     m_buffer = newBuffer;
     CompileAssert(ArrayBuffer::MaxArrayBufferLength / WebAssembly::PageSize <= INT32_MAX);
     return (int32)oldPageCount;
@@ -193,21 +193,11 @@ WebAssemblyMemory *
 WebAssemblyMemory::CreateMemoryObject(uint32 initial, uint32 maximum, ScriptContext * scriptContext)
 {
     uint32 byteLength = UInt32Math::Mul<WebAssembly::PageSize>(initial);
-    ArrayBuffer* buffer;
-#if ENABLE_FAST_ARRAYBUFFER
-    if (CONFIG_FLAG(WasmFastArray))
-    {
-        buffer = scriptContext->GetLibrary()->CreateWebAssemblyArrayBuffer(byteLength);
-    }
-    else
-#endif
-    {
-        buffer = scriptContext->GetLibrary()->CreateArrayBuffer(byteLength);
-    }
+    WebAssemblyArrayBuffer* buffer = scriptContext->GetLibrary()->CreateWebAssemblyArrayBuffer(byteLength);
     return RecyclerNewFinalized(scriptContext->GetRecycler(), WebAssemblyMemory, buffer, initial, maximum, scriptContext->GetLibrary()->GetWebAssemblyMemoryType());
 }
 
-ArrayBuffer *
+WebAssemblyArrayBuffer*
 WebAssemblyMemory::GetBuffer() const
 {
     return m_buffer;

+ 3 - 3
lib/Runtime/Library/WebAssemblyMemory.h

@@ -32,7 +32,7 @@ namespace Js
 
         static WebAssemblyMemory * CreateMemoryObject(uint32 initial, uint32 maximum, ScriptContext * scriptContext);
 
-        ArrayBuffer * GetBuffer() const;
+        WebAssemblyArrayBuffer * GetBuffer() const;
         uint GetInitialLength() const;
         uint GetMaximumLength() const;
 
@@ -41,9 +41,9 @@ namespace Js
 
         static int GetOffsetOfArrayBuffer() { return offsetof(WebAssemblyMemory, m_buffer); }
     private:
-        WebAssemblyMemory(ArrayBuffer * buffer, uint32 initial, uint32 maximum, DynamicType * type);
+        WebAssemblyMemory(WebAssemblyArrayBuffer * buffer, uint32 initial, uint32 maximum, DynamicType * type);
 
-        Field(ArrayBuffer *) m_buffer;
+        Field(WebAssemblyArrayBuffer *) m_buffer;
 
         Field(uint) m_initial;
         Field(uint) m_maximum;