Преглед изворни кода

[MERGE #3128 @Cellule] Fix some WebAssembly spec bugs

Merge pull request #3128 from Cellule:users/micfer/wasm/spec_bug

- Fix string tags for WebAssembly Types
- Detach Wasm array buffer on `.grow(0)`
- Set wasm export prototype to `null`
- Prevent extensions on the exports object
- Check that WebAssembly.Memory maximum > initial
- Check that WebAssembly.Table maximum > initial
- Throw exception on `new wasmFunction()`
- WebAssembly.Module.customSections sectionName argument is optional
Michael Ferris пре 8 година
родитељ
комит
e265ab14c1

+ 2 - 0
lib/Common/ConfigFlagsList.h

@@ -397,6 +397,7 @@ PHASE(All)
 #define DEFAULT_CONFIG_WasmCheckVersion     (true)
 #define DEFAULT_CONFIG_WasmFold             (true)
 #define DEFAULT_CONFIG_WasmIgnoreResponse   (false)
+#define DEFAULT_CONFIG_WasmMaxTableSize     (10000000)
 #define DEFAULT_CONFIG_BgJitDelayFgBuffer   (0)
 #define DEFAULT_CONFIG_BgJitPendingFuncCap  (31)
 #define DEFAULT_CONFIG_CurrentSourceInfo    (true)
@@ -865,6 +866,7 @@ FLAGNR(Boolean, WasmFastArray         , "Enable fast array implementation for We
 FLAGNR(Boolean, WasmCheckVersion      , "Check the binary version for WebAssembly", DEFAULT_CONFIG_WasmCheckVersion)
 FLAGNR(Boolean, WasmFold              , "Enable i32/i64 const folding", DEFAULT_CONFIG_WasmFold)
 FLAGNR(Boolean, WasmIgnoreResponse    , "Ignore the type of the Response object", DEFAULT_CONFIG_WasmIgnoreResponse)
+FLAGNR(Number,  WasmMaxTableSize      , "Maximum size allowed to the WebAssembly.Table", DEFAULT_CONFIG_WasmMaxTableSize)
 
 #ifndef COMPILE_DISABLE_Simdjs
     #define COMPILE_DISABLE_Simdjs 0

+ 1 - 0
lib/Parser/rterrors.h

@@ -395,6 +395,7 @@ RT_ERROR_MSG(WASMERR_CantDetach, 7021, "", "Not allowed to detach WebAssembly.Me
 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)
 RT_ERROR_MSG(WASMERR_MemoryCreateFailed, 7024, "", "Failed to create WebAssembly.Memory", kjstTypeError, 0)
+RT_ERROR_MSG(WASMERR_NeedInstanceObject, 7025, "%s is not a WebAssembly.Instance", "WebAssembly.Instance object expected", kjstWebAssemblyRuntimeError, 0)
 
 // Wabt Errors
 RT_ERROR_MSG(WABTERR_WabtError, 7200, "%s", "Wabt Error.", kjstTypeError, 0)

+ 19 - 8
lib/Runtime/Library/ArrayBuffer.cpp

@@ -1035,11 +1035,12 @@ namespace Js
 
     WebAssemblyArrayBuffer* WebAssemblyArrayBuffer::GrowMemory(uint32 newBufferLength)
     {
-        if (newBufferLength <= this->bufferLength)
+        if (newBufferLength < this->bufferLength)
         {
             Assert(UNREACHED);
             JavascriptError::ThrowTypeError(GetScriptContext(), WASMERR_BufferGrowOnly);
         }
+        uint32 growSize = newBufferLength - this->bufferLength;
 
         bool failedReport = false;
         const auto reportFailedFn = [&failedReport] { failedReport = true; };
@@ -1055,12 +1056,15 @@ namespace Js
                 return nullptr;
             }
 
-            LPVOID newMem = VirtualAlloc(this->buffer + this->bufferLength, newBufferLength - this->bufferLength, MEM_COMMIT, PAGE_READWRITE);
-            if (!newMem)
+            if (growSize > 0)
             {
-                Recycler* recycler = this->GetRecycler();
-                recycler->ReportExternalMemoryFailure(newBufferLength);
-                return nullptr;
+                LPVOID newMem = VirtualAlloc(this->buffer + this->bufferLength, growSize, MEM_COMMIT, PAGE_READWRITE);
+                if (!newMem)
+                {
+                    Recycler* recycler = this->GetRecycler();
+                    recycler->ReportExternalMemoryFailure(newBufferLength);
+                    return nullptr;
+                }
             }
             newArrayBuffer = GetLibrary()->CreateWebAssemblyArrayBuffer(this->buffer, newBufferLength);
         }
@@ -1068,7 +1072,14 @@ namespace Js
 #endif
         if (this->GetByteLength() == 0)
         {
-            newArrayBuffer = GetLibrary()->CreateWebAssemblyArrayBuffer(newBufferLength);
+            if (growSize > 0)
+            {
+                newArrayBuffer = GetLibrary()->CreateWebAssemblyArrayBuffer(newBufferLength);
+            }
+            else
+            {
+                newArrayBuffer = GetLibrary()->CreateWebAssemblyArrayBuffer(this->buffer, 0);
+            }
         }
         else
         {
@@ -1086,7 +1097,7 @@ namespace Js
             newArrayBuffer = GetLibrary()->CreateWebAssemblyArrayBuffer(newBuffer, newBufferLength);
         }
 
-        if (!newArrayBuffer || !newArrayBuffer->GetByteLength())
+        if (!newArrayBuffer || newArrayBuffer->GetByteLength() != newBufferLength)
         {
             return nullptr;
         }

+ 1 - 0
lib/Runtime/Library/JavascriptBuiltInFunctionList.h

@@ -317,6 +317,7 @@ BUILTIN(WebAssemblyModule, Exports, EntryExports, FunctionInfo::ErrorOnNew)
 BUILTIN(WebAssemblyModule, Imports, EntryImports, FunctionInfo::ErrorOnNew)
 BUILTIN(WebAssemblyModule, CustomSections, EntryCustomSections, FunctionInfo::ErrorOnNew)
 BUILTIN(WebAssemblyInstance, NewInstance, NewInstance, FunctionInfo::SkipDefaultNewObject)
+BUILTIN(WebAssemblyInstance, GetterExports, GetterExports, FunctionInfo::ErrorOnNew | FunctionInfo::HasNoSideEffect)
 BUILTIN(WebAssemblyMemory, NewInstance, NewInstance, FunctionInfo::SkipDefaultNewObject)
 BUILTIN(WebAssemblyMemory, Grow, EntryGrow, FunctionInfo::ErrorOnNew)
 BUILTIN(WebAssemblyMemory, GetterBuffer, EntryGetterBuffer, FunctionInfo::ErrorOnNew | FunctionInfo::HasNoSideEffect)

+ 32 - 24
lib/Runtime/Library/JavascriptLibrary.cpp

@@ -2142,7 +2142,7 @@ namespace Js
         prototype->SetHasNoEnumerableProperties(hasNoEnumerableProperties);
     }
 
-#define INIT_ERROR(error) \
+#define INIT_ERROR_IMPL(error, errorName) \
     void JavascriptLibrary::Initialize##error##Constructor(DynamicObject* constructor, DeferredTypeHandlerBase* typeHandler, DeferredInitializeMode mode) \
     { \
         typeHandler->Convert(constructor, mode, 3); \
@@ -2153,7 +2153,7 @@ namespace Js
         if (scriptContext->GetConfig()->IsES6FunctionNameEnabled()) \
         { \
             PropertyAttributes prototypeNameMessageAttributes = PropertyConfigurable; \
-            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u(#error)), prototypeNameMessageAttributes); \
+            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u(#errorName)), prototypeNameMessageAttributes); \
         } \
         constructor->SetHasNoEnumerableProperties(true); \
     } \
@@ -2164,21 +2164,22 @@ namespace Js
         library->AddMember(prototype, PropertyIds::constructor, library->Get##error##Constructor()); \
         bool hasNoEnumerableProperties = true; \
         PropertyAttributes prototypeNameMessageAttributes = PropertyConfigurable | PropertyWritable; \
-        library->AddMember(prototype, PropertyIds::name, library->CreateStringFromCppLiteral(_u(#error)), prototypeNameMessageAttributes); \
+        library->AddMember(prototype, PropertyIds::name, library->CreateStringFromCppLiteral(_u(#errorName)), prototypeNameMessageAttributes); \
         library->AddMember(prototype, PropertyIds::message, library->GetEmptyString(), prototypeNameMessageAttributes); \
         library->AddFunctionToLibraryObject(prototype, PropertyIds::toString, &JavascriptError::EntryInfo::ToString, 0); \
         prototype->SetHasNoEnumerableProperties(hasNoEnumerableProperties); \
     }
 
+#define INIT_ERROR(error) INIT_ERROR_IMPL(error, error)
     INIT_ERROR(EvalError);
     INIT_ERROR(RangeError);
     INIT_ERROR(ReferenceError);
     INIT_ERROR(SyntaxError);
     INIT_ERROR(TypeError);
     INIT_ERROR(URIError);
-    INIT_ERROR(WebAssemblyCompileError);
-    INIT_ERROR(WebAssemblyRuntimeError);
-    INIT_ERROR(WebAssemblyLinkError);
+    INIT_ERROR_IMPL(WebAssemblyCompileError, CompileError);
+    INIT_ERROR_IMPL(WebAssemblyRuntimeError, RuntimeError);
+    INIT_ERROR_IMPL(WebAssemblyLinkError, LinkError);
 
 #undef INIT_ERROR
 
@@ -2470,7 +2471,7 @@ namespace Js
         {
             library->AddMember(proxyConstructor, PropertyIds::name, scriptContext->GetPropertyString(PropertyIds::Proxy), PropertyConfigurable);
         }
-        library->AddFunctionToLibraryObject(proxyConstructor, PropertyIds::revocable, &JavascriptProxy::EntryInfo::Revocable, PropertyNone);
+        library->AddFunctionToLibraryObject(proxyConstructor, PropertyIds::revocable, &JavascriptProxy::EntryInfo::Revocable, 2, PropertyConfigurable);
 
         proxyConstructor->SetHasNoEnumerableProperties(true);
     }
@@ -2790,16 +2791,16 @@ namespace Js
         library->AddMember(prototype, PropertyIds::constructor, library->webAssemblyTableConstructor);
         if (scriptContext->GetConfig()->IsES6ToStringTagEnabled())
         {
-            library->AddMember(prototype, PropertyIds::_symbolToStringTag, library->CreateStringFromCppLiteral(_u("WebAssemblyTable")), PropertyConfigurable);
+            library->AddMember(prototype, PropertyIds::_symbolToStringTag, library->CreateStringFromCppLiteral(_u("WebAssembly.Table")), PropertyConfigurable);
         }
         scriptContext->SetBuiltInLibraryFunction(WebAssemblyTable::EntryInfo::Grow.GetOriginalEntryPoint(),
-            library->AddFunctionToLibraryObject(prototype, PropertyIds::grow, &WebAssemblyTable::EntryInfo::Grow, PropertyEnumerable));
+            library->AddFunctionToLibraryObject(prototype, PropertyIds::grow, &WebAssemblyTable::EntryInfo::Grow, 1));
 
         scriptContext->SetBuiltInLibraryFunction(WebAssemblyTable::EntryInfo::Get.GetOriginalEntryPoint(),
-            library->AddFunctionToLibraryObject(prototype, PropertyIds::get, &WebAssemblyTable::EntryInfo::Get, PropertyEnumerable));
+            library->AddFunctionToLibraryObject(prototype, PropertyIds::get, &WebAssemblyTable::EntryInfo::Get, 1));
 
         scriptContext->SetBuiltInLibraryFunction(WebAssemblyTable::EntryInfo::Set.GetOriginalEntryPoint(),
-            library->AddFunctionToLibraryObject(prototype, PropertyIds::set, &WebAssemblyTable::EntryInfo::Set, PropertyEnumerable));
+            library->AddFunctionToLibraryObject(prototype, PropertyIds::set, &WebAssemblyTable::EntryInfo::Set, 2));
 
         library->AddAccessorsToLibraryObject(prototype, PropertyIds::length, &WebAssemblyTable::EntryInfo::GetterLength, nullptr);
 
@@ -2815,7 +2816,7 @@ namespace Js
         library->AddMember(constructor, PropertyIds::prototype, library->webAssemblyTablePrototype, PropertyNone);
         if (scriptContext->GetConfig()->IsES6FunctionNameEnabled())
         {
-            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u("WebAssemblyTable")), PropertyConfigurable);
+            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u("Table")), PropertyConfigurable);
         }
         constructor->SetHasNoEnumerableProperties(true);
     }
@@ -2830,10 +2831,10 @@ namespace Js
         library->AddMember(prototype, PropertyIds::constructor, library->webAssemblyMemoryConstructor);
         if (scriptContext->GetConfig()->IsES6ToStringTagEnabled())
         {
-            library->AddMember(prototype, PropertyIds::_symbolToStringTag, library->CreateStringFromCppLiteral(_u("WebAssemblyMemory")), PropertyConfigurable);
+            library->AddMember(prototype, PropertyIds::_symbolToStringTag, library->CreateStringFromCppLiteral(_u("WebAssembly.Memory")), PropertyConfigurable);
         }
         scriptContext->SetBuiltInLibraryFunction(WebAssemblyMemory::EntryInfo::Grow.GetOriginalEntryPoint(),
-            library->AddFunctionToLibraryObject(prototype, PropertyIds::grow, &WebAssemblyMemory::EntryInfo::Grow, PropertyEnumerable));
+            library->AddFunctionToLibraryObject(prototype, PropertyIds::grow, &WebAssemblyMemory::EntryInfo::Grow, 1));
 
         library->AddAccessorsToLibraryObject(prototype, PropertyIds::buffer, &WebAssemblyMemory::EntryInfo::GetterBuffer, nullptr);
 
@@ -2849,22 +2850,23 @@ namespace Js
         library->AddMember(constructor, PropertyIds::prototype, library->webAssemblyMemoryPrototype, PropertyNone);
         if (scriptContext->GetConfig()->IsES6FunctionNameEnabled())
         {
-            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u("WebAssemblyMemory")), PropertyConfigurable);
+            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u("Memory")), PropertyConfigurable);
         }
         constructor->SetHasNoEnumerableProperties(true);
     }
 
     void JavascriptLibrary::InitializeWebAssemblyInstancePrototype(DynamicObject* prototype, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
     {
-        typeHandler->Convert(prototype, mode, 2);
+        typeHandler->Convert(prototype, mode, 3);
 
         JavascriptLibrary* library = prototype->GetLibrary();
         ScriptContext* scriptContext = prototype->GetScriptContext();
 
         library->AddMember(prototype, PropertyIds::constructor, library->webAssemblyInstanceConstructor);
+        library->AddAccessorsToLibraryObject(prototype, PropertyIds::exports, &WebAssemblyInstance::EntryInfo::GetterExports, nullptr);
         if (scriptContext->GetConfig()->IsES6ToStringTagEnabled())
         {
-            library->AddMember(prototype, PropertyIds::_symbolToStringTag, library->CreateStringFromCppLiteral(_u("WebAssemblyInstance")), PropertyConfigurable);
+            library->AddMember(prototype, PropertyIds::_symbolToStringTag, library->CreateStringFromCppLiteral(_u("WebAssembly.Instance")), PropertyConfigurable);
         }
         prototype->SetHasNoEnumerableProperties(true);
     }
@@ -2878,7 +2880,7 @@ namespace Js
         library->AddMember(constructor, PropertyIds::prototype, library->webAssemblyInstancePrototype, PropertyNone);
         if (scriptContext->GetConfig()->IsES6FunctionNameEnabled())
         {
-            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u("WebAssemblyInstance")), PropertyConfigurable);
+            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u("Instance")), PropertyConfigurable);
         }
         constructor->SetHasNoEnumerableProperties(true);
     }
@@ -2893,7 +2895,7 @@ namespace Js
         library->AddMember(prototype, PropertyIds::constructor, library->webAssemblyModuleConstructor);
         if (scriptContext->GetConfig()->IsES6ToStringTagEnabled())
         {
-            library->AddMember(prototype, PropertyIds::_symbolToStringTag, library->CreateStringFromCppLiteral(_u("WebAssemblyModule")), PropertyConfigurable);
+            library->AddMember(prototype, PropertyIds::_symbolToStringTag, library->CreateStringFromCppLiteral(_u("WebAssembly.Module")), PropertyConfigurable);
         }
         prototype->SetHasNoEnumerableProperties(true);
     }
@@ -2906,13 +2908,13 @@ namespace Js
         library->AddMember(constructor, PropertyIds::length, TaggedInt::ToVarUnchecked(1), PropertyConfigurable);
         library->AddMember(constructor, PropertyIds::prototype, library->webAssemblyModulePrototype, PropertyNone);
 
-        library->AddFunctionToLibraryObject(constructor, PropertyIds::exports, &WebAssemblyModule::EntryInfo::Exports, 2);
-        library->AddFunctionToLibraryObject(constructor, PropertyIds::imports, &WebAssemblyModule::EntryInfo::Imports, 2);
+        library->AddFunctionToLibraryObject(constructor, PropertyIds::exports, &WebAssemblyModule::EntryInfo::Exports, 1);
+        library->AddFunctionToLibraryObject(constructor, PropertyIds::imports, &WebAssemblyModule::EntryInfo::Imports, 1);
         library->AddFunctionToLibraryObject(constructor, PropertyIds::customSections, &WebAssemblyModule::EntryInfo::CustomSections, 2);
 
         if (scriptContext->GetConfig()->IsES6FunctionNameEnabled())
         {
-            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u("WebAssemblyModule")), PropertyConfigurable);
+            library->AddMember(constructor, PropertyIds::name, library->CreateStringFromCppLiteral(_u("Module")), PropertyConfigurable);
         }
         constructor->SetHasNoEnumerableProperties(true);
     }
@@ -2920,7 +2922,7 @@ namespace Js
     void JavascriptLibrary::InitializeWebAssemblyObject(DynamicObject* webAssemblyObject, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
     {
         JavascriptLibrary* library = webAssemblyObject->GetLibrary();
-        int slots = 8;
+        int slots = 9;
 #ifdef ENABLE_WABT
         // Attaching wabt for testing
         ++slots;
@@ -2949,6 +2951,12 @@ namespace Js
         library->AddFunction(webAssemblyObject, PropertyIds::LinkError, library->webAssemblyLinkErrorConstructor);
         library->AddFunction(webAssemblyObject, PropertyIds::Memory, library->webAssemblyMemoryConstructor);
         library->AddFunction(webAssemblyObject, PropertyIds::Table, library->webAssemblyTableConstructor);
+
+        ScriptContext* scriptContext = webAssemblyObject->GetScriptContext();
+        if (scriptContext->GetConfig()->IsES6FunctionNameEnabled())
+        {
+            library->AddMember(webAssemblyObject, PropertyIds::_symbolToStringTag, library->CreateStringFromCppLiteral(_u("WebAssembly")), PropertyConfigurable);
+        }
     }
 #endif
 
@@ -6769,7 +6777,7 @@ namespace Js
 
     DynamicObject* JavascriptLibrary::CreateObject(RecyclableObject* prototype, uint16 requestedInlineSlotCapacity)
     {
-        Assert(JavascriptOperators::IsObject(prototype));
+        Assert(JavascriptOperators::IsObjectOrNull(prototype));
 
         DynamicType* dynamicType = CreateObjectType(prototype, requestedInlineSlotCapacity);
         return DynamicObject::New(this->GetRecycler(), dynamicType);

+ 40 - 6
lib/Runtime/Library/WebAssemblyInstance.cpp

@@ -32,7 +32,8 @@ Var GetImportVariable(Wasm::WasmImport* wi, ScriptContext* ctx, Var ffi)
 
 WebAssemblyInstance::WebAssemblyInstance(WebAssemblyModule * wasmModule, DynamicType * type) :
     DynamicObject(type),
-    m_module(wasmModule)
+    m_module(wasmModule),
+    m_exports(nullptr)
 {
 }
 
@@ -87,6 +88,31 @@ WebAssemblyInstance::NewInstance(RecyclableObject* function, CallInfo callInfo,
     return CreateInstance(module, importObject);
 }
 
+Var
+WebAssemblyInstance::GetterExports(RecyclableObject* function, CallInfo callInfo, ...)
+{
+    PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
+
+    ARGUMENTS(args, callInfo);
+    ScriptContext* scriptContext = function->GetScriptContext();
+
+    Assert(!(callInfo.Flags & CallFlags_New));
+
+    if (args.Info.Count == 0 || !WebAssemblyInstance::Is(args[0]))
+    {
+        JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedInstanceObject);
+    }
+
+    WebAssemblyInstance* instance = WebAssemblyInstance::FromVar(args[0]);
+    Js::Var exports = instance->m_exports;
+    if (!exports || !DynamicObject::Is(exports))
+    {
+        Assert(UNREACHED);
+        exports = scriptContext->GetLibrary()->GetUndefined();
+    }
+    return exports;
+}
+
 WebAssemblyInstance *
 WebAssemblyInstance::CreateInstance(WebAssemblyModule * module, Var importObject)
 {
@@ -119,8 +145,7 @@ WebAssemblyInstance::CreateInstance(WebAssemblyModule * module, Var importObject
             AssertMsg(UNREACHED, "By spec, we should not have any exceptions possible here");
             throw;
         }
-        Js::Var exportsNamespace = BuildObject(module, scriptContext, &environment);
-        JavascriptOperators::OP_SetProperty(newInstance, PropertyIds::exports, exportsNamespace, scriptContext);
+        newInstance->m_exports = BuildObject(module, scriptContext, &environment);
     }
     catch (Wasm::WasmCompilationException& e)
     {
@@ -150,11 +175,19 @@ void WebAssemblyInstance::LoadFunctions(WebAssemblyModule * wasmModule, ScriptCo
         {
             continue;
         }
-        AsmJsScriptFunction * funcObj = ctx->GetLibrary()->CreateAsmJsScriptFunction(wasmModule->GetWasmFunctionInfo(i)->GetBody());
-        FunctionBody* body = funcObj->GetFunctionBody();
+        Wasm::WasmFunctionInfo* wasmFuncInfo = wasmModule->GetWasmFunctionInfo(i);
+        FunctionBody* body = wasmFuncInfo->GetBody();
+        AsmJsScriptFunction * funcObj = ctx->GetLibrary()->CreateAsmJsScriptFunction(body);
         funcObj->SetModuleMemory((Field(Var)*)env->GetStartPtr());
         funcObj->SetSignature(body->GetAsmJsFunctionInfo()->GetWasmSignature());
         funcObj->SetEnvironment(frameDisplay);
+
+        // Todo:: need to fix issue #2452 before we can do this,
+        // otherwise we'll change the type of the functions and cause multiple instance to not share jitted code
+        //Wasm::WasmSignature* sig = wasmFuncInfo->GetSignature();
+        //funcObj->SetPropertyWithAttributes(PropertyIds::length, JavascriptNumber::ToVar(sig->GetParamCount(), ctx), PropertyNone, nullptr);
+        //funcObj->SetPropertyWithAttributes(PropertyIds::name, JavascriptConversion::ToString(JavascriptNumber::ToVar(i, ctx), ctx), PropertyNone, nullptr);
+
         env->SetWasmFunction(i, funcObj);
 
         if (!PHASE_OFF(WasmDeferredPhase, body))
@@ -200,7 +233,7 @@ void WebAssemblyInstance::LoadDataSegs(WebAssemblyModule * wasmModule, ScriptCon
 
 Var WebAssemblyInstance::BuildObject(WebAssemblyModule * wasmModule, ScriptContext* scriptContext, WebAssemblyEnvironment* env)
 {
-    Js::Var exportsNamespace = JavascriptOperators::NewJavascriptObjectNoArg(scriptContext);
+    Js::Var exportsNamespace = scriptContext->GetLibrary()->CreateObject(scriptContext->GetLibrary()->GetNull());
     for (uint32 iExport = 0; iExport < wasmModule->GetExportCount(); ++iExport)
     {
         Wasm::WasmExport* wasmExport = wasmModule->GetExport(iExport);
@@ -250,6 +283,7 @@ Var WebAssemblyInstance::BuildObject(WebAssemblyModule * wasmModule, ScriptConte
             JavascriptOperators::OP_SetProperty(exportsNamespace, propertyRecord->GetPropertyId(), obj, scriptContext);
         }
     }
+    DynamicObject::FromVar(exportsNamespace)->PreventExtensions();
     return exportsNamespace;
 }
 

+ 3 - 0
lib/Runtime/Library/WebAssemblyInstance.h

@@ -14,9 +14,11 @@ namespace Js
         {
         public:
             static FunctionInfo NewInstance;
+            static FunctionInfo GetterExports;
         };
 
         static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
+        static Var GetterExports(RecyclableObject* function, CallInfo callInfo, ...);
 
         static bool Is(Var aValue);
         static WebAssemblyInstance * FromVar(Var aValue);
@@ -34,6 +36,7 @@ namespace Js
         static void ValidateTableAndMemory(WebAssemblyModule * wasmModule, ScriptContext* ctx, WebAssemblyEnvironment* env);
 
         Field(WebAssemblyModule *) m_module;
+        Field(Js::Var) m_exports;
     };
 
 } // namespace Js

+ 2 - 7
lib/Runtime/Library/WebAssemblyMemory.cpp

@@ -136,11 +136,6 @@ WebAssemblyMemory::GrowInternal(uint32 deltaPages)
     const uint32 oldPageCount = oldBytes / WebAssembly::PageSize;
     Assert(oldBytes % WebAssembly::PageSize == 0);
 
-    if (deltaBytes == 0)
-    {
-        return (int32)oldPageCount;
-    }
-
     const uint32 newPageCount = oldPageCount + deltaPages;
     if (newPageCount > m_maximum)
     {
@@ -198,9 +193,9 @@ WebAssemblyMemory::EntryGetterBuffer(RecyclableObject* function, CallInfo callIn
 WebAssemblyMemory *
 WebAssemblyMemory::CreateMemoryObject(uint32 initial, uint32 maximum, ScriptContext * scriptContext)
 {
-    if (initial > Wasm::Limits::GetMaxMemoryInitialPages() || maximum > Wasm::Limits::GetMaxMemoryMaximumPages())
+    if (initial > maximum || initial > Wasm::Limits::GetMaxMemoryInitialPages() || maximum > Wasm::Limits::GetMaxMemoryMaximumPages())
     {
-        JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_Invalid);
+        JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange);
     }
     // This shouldn't overflow since we checked in the module, but just to be safe
     uint32 byteLength = UInt32Math::Mul<WebAssembly::PageSize>(initial);

+ 2 - 5
lib/Runtime/Library/WebAssemblyModule.cpp

@@ -171,13 +171,10 @@ Var WebAssemblyModule::EntryCustomSections(RecyclableObject* function, CallInfo
     {
         JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedModule);
     }
-    if (args.Info.Count < 3)
-    {
-        JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedString, _u("sectionName"));
-    }
+    Var sectionNameVar = args.Info.Count > 2 ? args[2] : scriptContext->GetLibrary()->GetUndefined();
 
     WebAssemblyModule * module = WebAssemblyModule::FromVar(args[1]);
-    JavascriptString * sectionName = JavascriptConversion::ToString(args[2], scriptContext);
+    JavascriptString * sectionName = JavascriptConversion::ToString(sectionNameVar, scriptContext);
     const char16* sectionNameBuf = sectionName->GetString();
     charcount_t sectionNameLength = sectionName->GetLength();
 

+ 4 - 3
lib/Runtime/Library/WebAssemblyTable.cpp

@@ -127,10 +127,11 @@ WebAssemblyTable::EntryGrow(RecyclableObject* function, CallInfo callInfo, ...)
     Field(Var) * newValues = RecyclerNewArrayZ(scriptContext->GetRecycler(), Field(Var), newLength);
     CopyArray(newValues, newLength, table->m_values, table->m_currentLength);
 
+    uint32 oldLength = table->m_currentLength;
     table->m_values = newValues;
     table->m_currentLength = newLength;
 
-    return scriptContext->GetLibrary()->GetUndefined();
+    return JavascriptNumber::ToVar(oldLength, scriptContext);
 }
 
 Var
@@ -213,9 +214,9 @@ WebAssemblyTable::EntrySet(RecyclableObject* function, CallInfo callInfo, ...)
 WebAssemblyTable *
 WebAssemblyTable::Create(uint32 initial, uint32 maximum, ScriptContext * scriptContext)
 {
-    if (initial > Wasm::Limits::GetMaxTableSize() || maximum > Wasm::Limits::GetMaxTableSize())
+    if (initial > maximum || initial > Wasm::Limits::GetMaxTableSize() || maximum > Wasm::Limits::GetMaxTableSize())
     {
-        JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_Invalid);
+        JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange);
     }
     Field(Var) * values = nullptr;
     if (initial > 0)

+ 1 - 1
lib/WasmReader/WasmByteCodeGenerator.cpp

@@ -295,7 +295,7 @@ void WasmModuleGenerator::GenerateFunctionHeader(uint32 index)
         m_sourceInfo->GetSrcInfo()->sourceContextInfo->sourceContextId,
         wasmInfo->GetNumber(),
         nullptr,
-        Js::FunctionInfo::Attributes::None,
+        Js::FunctionInfo::Attributes::ErrorOnNew,
         Js::FunctionBody::Flags_None
 #ifdef PERF_COUNTERS
         , false /* is function from deferred deserialized proxy */

+ 2 - 2
lib/WasmReader/WasmLimits.h

@@ -16,7 +16,7 @@ namespace Wasm {
         static const uint32 MaxGlobals = 1000000;
         static const uint32 MaxDataSegments = 100000;
         static const uint32 MaxElementSegments = 10000000;
-        static const uint32 MaxTableSize = 10000000;
+        static const uint32 MaxTableSize = DEFAULT_CONFIG_WasmMaxTableSize;
 
         static const uint32 MaxStringSize = 100000;
         static const uint32 MaxFunctionLocals = 50000;
@@ -36,7 +36,7 @@ namespace Wasm {
         static uint32 GetMaxGlobals() { return MaxGlobals; }
         static uint32 GetMaxDataSegments() { return MaxDataSegments; }
         static uint32 GetMaxElementSegments() { return MaxElementSegments; }
-        static uint32 GetMaxTableSize() { return MaxTableSize; }
+        static uint32 GetMaxTableSize() { return CONFIG_FLAG(WasmMaxTableSize); }
         static uint32 GetMaxStringSize() { return MaxStringSize; }
         static uint32 GetMaxFunctionLocals() { return MaxFunctionLocals; }
         static uint32 GetMaxFunctionParams() { return MaxFunctionParams; }

+ 23 - 23
test/WasmSpec/baselines/jsapi.baseline

@@ -1,51 +1,51 @@
 Harness Status: OK
-Found 89 tests: Pass = 67 Fail = 22
+Found 89 tests: Pass = 88 Fail = 1
 Pass 'WebAssembly' data property on global object  
-Fail 'WebAssembly' object  assert_equals: expected "[object WebAssembly]" but got "[object Object]"
+Pass 'WebAssembly' object  
 Pass 'WebAssembly.(Compile|Link|Runtime)Error' data property  
-Fail 'WebAssembly.(Compile|Runtime)Error' constructor function  assert_equals: expected "CompileError" but got "WebAssemblyCompileError"
+Pass 'WebAssembly.(Compile|Runtime)Error' constructor function  
 Pass 'WebAssembly.(Compile|Runtime)Error' instance objects  
 Pass 'WebAssembly.Module' data property  
-Fail 'WebAssembly.Module' constructor function  assert_equals: expected "Module" but got "WebAssemblyModule"
+Pass 'WebAssembly.Module' constructor function  
 Pass 'WebAssembly.Module.prototype' data property  
-Fail 'WebAssembly.Module.prototype' object  assert_equals: expected "[object WebAssembly.Module]" but got "[object WebAssemblyModule]"
-Fail 'WebAssembly.Module' instance objects  assert_equals: expected "[object WebAssembly.Module]" but got "[object WebAssemblyModule]"
+Pass 'WebAssembly.Module.prototype' object  
+Pass 'WebAssembly.Module' instance objects  
 Pass 'WebAssembly.Module.imports' data property  
-Fail 'WebAssembly.Module.imports' method  assert_equals: expected 1 but got 2
+Pass 'WebAssembly.Module.imports' method  
 Pass 'WebAssembly.Module.exports' data property  
-Fail 'WebAssembly.Module.exports' method  assert_equals: expected 1 but got 2
+Pass 'WebAssembly.Module.exports' method  
 Pass 'WebAssembly.Module.customSections' data property  
-Fail 'WebAssembly.Module.customSections' method  'sectionName' is not a string
+Pass 'WebAssembly.Module.customSections' method  
 Pass 'WebAssembly.Instance' data property  
-Fail 'WebAssembly.Instance' constructor function  assert_equals: expected "Instance" but got "WebAssemblyInstance"
+Pass 'WebAssembly.Instance' constructor function  
 Pass 'WebAssembly.Instance.prototype' data property  
-Fail 'WebAssembly.Instance.prototype' object  assert_equals: expected "[object WebAssembly.Instance]" but got "[object WebAssemblyInstance]"
-Fail 'WebAssembly.Instance' instance objects  assert_equals: expected "[object WebAssembly.Instance]" but got "[object WebAssemblyInstance]"
-Pass 'WebAssembly.Instance' 'exports' data property  
-Fail 'WebAssembly.Instance' 'exports' object  assert_equals: expected false but got true
+Pass 'WebAssembly.Instance.prototype' object  
+Pass 'WebAssembly.Instance' instance objects  
+Pass 'WebAssembly.Instance.prototype.exports' accessor property  
+Pass exports object  
 Fail Exported WebAssembly functions  assert_equals: expected 0 but got -1
 Pass 'WebAssembly.Memory' data property  
-Fail 'WebAssembly.Memory' constructor function  assert_equals: expected "Memory" but got "WebAssemblyMemory"
+Pass 'WebAssembly.Memory' constructor function  
 Pass 'WebAssembly.Memory.prototype' data property  
-Fail 'WebAssembly.Memory.prototype' object  assert_equals: expected "[object WebAssembly.Memory]" but got "[object WebAssemblyMemory]"
-Fail 'WebAssembly.Memory' instance objects  assert_equals: expected "[object WebAssembly.Memory]" but got "[object WebAssemblyMemory]"
+Pass 'WebAssembly.Memory.prototype' object  
+Pass 'WebAssembly.Memory' instance objects  
 Pass 'WebAssembly.Memory.prototype.buffer' accessor property  
 Pass 'WebAssembly.Memory.prototype.buffer' getter  
 Pass 'WebAssembly.Memory.prototype.grow' data property  
-Fail 'WebAssembly.Memory.prototype.grow' method  assert_equals: expected true but got false
+Pass 'WebAssembly.Memory.prototype.grow' method  
 Pass 'WebAssembly.Table' data property  
-Fail 'WebAssembly.Table' constructor function  assert_equals: expected "Table" but got "WebAssemblyTable"
+Pass 'WebAssembly.Table' constructor function  
 Pass 'WebAssembly.Table.prototype' data property  
-Fail 'WebAssembly.Table.prototype' object  assert_equals: expected "[object WebAssembly.Table]" but got "[object WebAssemblyTable]"
-Fail 'WebAssembly.Table' instance objects  assert_equals: expected "[object WebAssembly.Table]" but got "[object WebAssemblyTable]"
+Pass 'WebAssembly.Table.prototype' object  
+Pass 'WebAssembly.Table' instance objects  
 Pass 'WebAssembly.Table.prototype.length' accessor data property  
 Pass 'WebAssembly.Table.prototype.length' getter  
 Pass 'WebAssembly.Table.prototype.get' data property  
 Pass 'WebAssembly.Table.prototype.get' method  
 Pass 'WebAssembly.Table.prototype.set' data property  
-Fail 'WebAssembly.Table.prototype.set' method  assert_equals: expected 2 but got 1
+Pass 'WebAssembly.Table.prototype.set' method  
 Pass 'WebAssembly.Table.prototype.grow' data property  
-Fail 'WebAssembly.Table.prototype.grow' method  assert_equals: expected (number) 1 but got (undefined) undefined
+Pass 'WebAssembly.Table.prototype.grow' method  
 Pass 'WebAssembly.validate' method  
 Pass 'WebAssembly.compile' data property  
 Pass 'WebAssembly.compile' function  

+ 4 - 1
test/WasmSpec/jsapi.js

@@ -12,6 +12,9 @@ const verbose = options.indexOf("-verbose") !== -1;
 const self = this;
 const setTimeout = WScript.SetTimeout;
 const clearTimeout = WScript.ClearTimeout;
+
+WScript.Flag(`-wasmMaxTableSize:${(Math.pow(2,32)-1)|0}`);
+
 self.addEventListener = function() {};
 
 class ConsoleTestEnvironment {
@@ -82,7 +85,7 @@ function reportResult(tests, harness_status) {
   }
   const testsReport = tests.map(test => {
     const stack = verbose ? test.stack : "";
-    return `${status_text[test.status]} ${test.name} ${get_assertion(test)} ${test.message || ""}${stack}`;
+    return `${status_text[test.status]} ${test.name} ${get_assertion(test)} ${test.message || ""}${stack ? "\n" + stack : stack}`;
   });
   console.log(`Harness Status: ${status_text_harness[harness_status.status]}
 Found ${tests.length} tests: ${Object.keys(status_number).map(key => `${key} = ${status_number[key]}`).join(" ")}

+ 31 - 28
test/WasmSpec/testsuite/harness/wasm-constants.js

@@ -21,7 +21,7 @@ var kWasmH1 = 0x61;
 var kWasmH2 = 0x73;
 var kWasmH3 = 0x6d;
 
-var kWasmV0 = 1;
+var kWasmV0 = 0x1;
 var kWasmV1 = 0;
 var kWasmV2 = 0;
 var kWasmV3 = 0;
@@ -65,6 +65,11 @@ let kCodeSectionCode = 10;      // Function code
 let kDataSectionCode = 11;     // Data segments
 let kNameSectionCode = 12;     // Name section (encoded as string)
 
+// Name section types
+let kModuleNameCode = 0;
+let kFunctionNamesCode = 1;
+let kLocalNamesCode = 2;
+
 let kWasmFunctionTypeForm = 0x60;
 let kWasmAnyFunctionTypeForm = 0x70;
 
@@ -339,36 +344,34 @@ let kTrapMsgs = [
 ];
 
 function assertTraps(trap, code) {
-    var threwException = true;
-    try {
-      if (typeof code === 'function') {
-        code();
-      } else {
-        eval(code);
-      }
-      threwException = false;
-    } catch (e) {
-      assertEquals("object", typeof e);
-      assertEquals(kTrapMsgs[trap], e.message);
-      // Success.
-      return;
+  try {
+    if (typeof code === 'function') {
+      code();
+    } else {
+      eval(code);
     }
-    throw new MjsUnitAssertionError("Did not trap, expected: " + kTrapMsgs[trap]);
+  } catch (e) {
+    assertEquals('object', typeof e);
+    assertEquals(kTrapMsgs[trap], e.message);
+    // Success.
+    return;
+  }
+  throw new MjsUnitAssertionError('Did not trap, expected: ' + kTrapMsgs[trap]);
 }
 
 function assertWasmThrows(value, code) {
-    assertEquals("number", typeof(value));
-    try {
-      if (typeof code === 'function') {
-        code();
-      } else {
-        eval(code);
-      }
-    } catch (e) {
-      assertEquals("number", typeof e);
-      assertEquals(value, e);
-      // Success.
-      return;
+  assertEquals('number', typeof value);
+  try {
+    if (typeof code === 'function') {
+      code();
+    } else {
+      eval(code);
     }
-    throw new MjsUnitAssertionError("Did not throw at all, expected: " + value);
+  } catch (e) {
+    assertEquals('number', typeof e);
+    assertEquals(value, e);
+    // Success.
+    return;
+  }
+  throw new MjsUnitAssertionError('Did not throw, expected: ' + value);
 }

+ 54 - 30
test/WasmSpec/testsuite/harness/wasm-module-builder.js

@@ -74,8 +74,8 @@ class Binary extends Array {
     // Emit section length.
     this.emit_u32v(section.length);
     // Copy the temporary buffer.
-    for (let i = 0; i < section.length; ++i) {
-      this.push(section[i]);
+    for (const sectionByte of section) {
+      this.push(sectionByte);
     }
   }
 }
@@ -99,7 +99,13 @@ class WasmFunctionBuilder {
   }
 
   addBody(body) {
-    this.body = body;
+    for (let b of body) {
+      if (typeof b != 'number')
+        throw new Error('invalid body (entries have to be numbers): ' + body);
+    }
+    this.body = body.slice();
+    // Automatically add the end for the function block to the body.
+    this.body.push(kExprEnd);
     return this;
   }
 
@@ -161,6 +167,22 @@ class WasmModuleBuilder {
     return this;
   }
 
+  stringToBytes(name) {
+    var result = new Binary();
+    result.emit_u32v(name.length);
+    for (var i = 0; i < name.length; i++) {
+      result.emit_u8(name.charCodeAt(i));
+    }
+    return result;
+  }
+
+  addCustomSection(name, bytes) {
+    name = this.stringToBytes(name);
+    var length = new Binary();
+    length.emit_u32v(name.length + bytes.length);
+    this.explicit.push([0, ...length, ...name, ...bytes]);
+  }
+
   addType(type) {
     // TODO: canonicalize types?
     this.types.push(type);
@@ -228,12 +250,12 @@ class WasmModuleBuilder {
     this.exports.push({name: name, kind: kExternalMemory, index: 0});
   }
 
-  addFunctionTableInit(base, is_global, array) {
+  addFunctionTableInit(base, is_global, array, is_import = false) {
     this.function_table_inits.push({base: base, is_global: is_global,
                                     array: array});
     if (!is_global) {
       var length = base + array.length;
-      if (length > this.function_table_length) {
+      if (length > this.function_table_length && !is_import) {
         this.function_table_length = length;
       }
     }
@@ -241,6 +263,10 @@ class WasmModuleBuilder {
   }
 
   appendToTable(array) {
+    for (let n of array) {
+      if (typeof n != 'number')
+        throw new Error('invalid table (entries have to be numbers): ' + array);
+    }
     return this.addFunctionTableInit(this.function_table.length, false, array);
   }
 
@@ -308,15 +334,16 @@ class WasmModuleBuilder {
     }
 
     // Add functions declarations
-    let has_names = false;
+    let num_function_names = 0;
     let names = false;
     if (wasm.functions.length > 0) {
       if (debug) print("emitting function decls @ " + binary.length);
       binary.emit_section(kFunctionSectionCode, section => {
         section.emit_u32v(wasm.functions.length);
         for (let func of wasm.functions) {
-          has_names = has_names || (func.name != undefined &&
-                                   func.name.length > 0);
+          if (func.name !== undefined) {
+            ++num_function_names;
+          }
           section.emit_u32v(func.type_index);
         }
       });
@@ -335,7 +362,7 @@ class WasmModuleBuilder {
     }
 
     // Add memory section
-    if (wasm.memory != undefined) {
+    if (wasm.memory !== undefined) {
       if (debug) print("emitting memory @ " + binary.length);
       binary.emit_section(kMemorySectionCode, section => {
         section.emit_u8(1);  // one memory entry
@@ -363,7 +390,7 @@ class WasmModuleBuilder {
               break;
             case kWasmI64:
               section.emit_u8(kExprI64Const);
-              section.emit_u8(global.init);
+              section.emit_u32v(global.init);
               break;
             case kWasmF32:
               section.emit_u8(kExprF32Const);
@@ -397,7 +424,7 @@ class WasmModuleBuilder {
     }
 
     // Add export table.
-    var mem_export = (wasm.memory != undefined && wasm.memory.exp);
+    var mem_export = (wasm.memory !== undefined && wasm.memory.exp);
     var exports_count = wasm.exports.length + (mem_export ? 1 : 0);
     if (exports_count > 0) {
       if (debug) print("emitting exports @ " + binary.length);
@@ -417,7 +444,7 @@ class WasmModuleBuilder {
     }
 
     // Add start function section.
-    if (wasm.start_index != undefined) {
+    if (wasm.start_index !== undefined) {
       if (debug) print("emitting start function @ " + binary.length);
       binary.emit_section(kStartSectionCode, section => {
         section.emit_u32v(wasm.start_index);
@@ -458,7 +485,7 @@ class WasmModuleBuilder {
           // Function body length will be patched later.
           let local_decls = [];
           let l = func.locals;
-          if (l != undefined) {
+          if (l !== undefined) {
             let local_decls_count = 0;
             if (l.i32_count > 0) {
               local_decls.push({count: l.i32_count, type: kWasmI32});
@@ -518,21 +545,18 @@ class WasmModuleBuilder {
     }
 
     // Add function names.
-    if (has_names) {
-      if (debug) print("emitting names @ " + binary.length);
+    if (num_function_names > 0) {
+      if (debug) print('emitting names @ ' + binary.length);
       binary.emit_section(kUnknownSectionCode, section => {
-        section.emit_string("name");
-        var count = wasm.functions.length + wasm.num_imported_funcs;
-        section.emit_u32v(count);
-        for (var i = 0; i < wasm.num_imported_funcs; i++) {
-          section.emit_u8(0); // empty string
-          section.emit_u8(0); // local names count == 0
-        }
-        for (let func of wasm.functions) {
-          var name = func.name == undefined ? "" : func.name;
-          section.emit_string(name);
-          section.emit_u8(0);  // local names count == 0
-        }
+        section.emit_string('name');
+        section.emit_section(kFunctionNamesCode, name_section => {
+          name_section.emit_u32v(num_function_names);
+          for (let func of wasm.functions) {
+            if (func.name === undefined) continue;
+            name_section.emit_u32v(func.index);
+            name_section.emit_string(func.name);
+          }
+        });
       });
     }
 
@@ -548,12 +572,12 @@ class WasmModuleBuilder {
       if ((typeof val) == "string") val = val.charCodeAt(0);
       view[i] = val | 0;
     }
-    return new Uint8Array(buffer);
+    return buffer;
   }
 
-  instantiate(...args) {
+  instantiate(ffi) {
     let module = new WebAssembly.Module(this.toBuffer());
-    let instance = new WebAssembly.Instance(module, ...args);
+    let instance = new WebAssembly.Instance(module, ffi);
     return instance;
   }
 }

+ 27 - 18
test/WasmSpec/testsuite/js-api/jsapi.js

@@ -46,8 +46,7 @@ const exportingModuleBinary = (() => {
         .addFunction('f', kSig_i_v)
         .addBody([
             kExprI32Const,
-            42,
-            kExprEnd
+            42
         ])
         .exportFunc();
 
@@ -59,9 +58,7 @@ const complexExportingModuleBinary = (() => {
 
     builder
         .addFunction('a', kSig_v_v)
-        .addBody([
-            kExprEnd
-        ])
+        .addBody([])
         .exportFunc();
 
     builder.addMemory(1, 1, /* exported */ false);
@@ -97,6 +94,7 @@ let CompileError;
 let LinkError;
 let RuntimeError;
 let Memory;
+let instanceProto;
 let memoryProto;
 let mem1;
 let Table;
@@ -199,7 +197,7 @@ test(() => {
     assertThrows(() => new Module(new Uint8Array()), CompileError);
     assertThrows(() => new Module(new ArrayBuffer()), CompileError);
     assert_equals(new Module(emptyModuleBinary) instanceof Module, true);
-    assert_equals(new Module(emptyModuleBinary.buffer) instanceof Module, true);
+    assert_equals(new Module(new Uint8Array(emptyModuleBinary)) instanceof Module, true);
 }, "'WebAssembly.Module' constructor function");
 
 test(() => {
@@ -350,7 +348,7 @@ test(() => {
 }, "'WebAssembly.Instance.prototype' data property");
 
 test(() => {
-    const instanceProto = Instance.prototype;
+    instanceProto = Instance.prototype;
     const instanceProtoDesc = Object.getOwnPropertyDescriptor(Instance, 'prototype');
     assert_equals(instanceProto, instanceProtoDesc.value);
     assert_equals(String(instanceProto), "[object WebAssembly.Instance]");
@@ -366,12 +364,16 @@ test(() => {
 }, "'WebAssembly.Instance' instance objects");
 
 test(() => {
-    const instanceExportsDesc = Object.getOwnPropertyDescriptor(exportingInstance, 'exports');
-    assert_equals(typeof instanceExportsDesc.value, "object");
-    assert_equals(instanceExportsDesc.writable, true);
-    assert_equals(instanceExportsDesc.enumerable, true);
-    assert_equals(instanceExportsDesc.configurable, true);
-}, "'WebAssembly.Instance' 'exports' data property");
+    const exportsDesc = Object.getOwnPropertyDescriptor(instanceProto, 'exports');
+    assert_equals(typeof exportsDesc.get, "function");
+    assert_equals(exportsDesc.set, undefined);
+    assert_equals(exportsDesc.enumerable, false);
+    assert_equals(exportsDesc.configurable, true);
+    const exportsGetter = exportsDesc.get;
+    assertThrows(() => exportsGetter.call(), TypeError);
+    assertThrows(() => exportsGetter.call({}), TypeError);
+    assert_equals(typeof exportsGetter.call(exportingInstance), "object");
+}, "'WebAssembly.Instance.prototype.exports' accessor property");
 
 test(() => {
     exportsObj = exportingInstance.exports;
@@ -385,7 +387,7 @@ test(() => {
     assert_equals(Object.getPrototypeOf(exportsObj), null);
     assertThrows(() => Object.defineProperty(exportsObj, 'g', {}), TypeError);
     assert_equals(Object.keys(exportsObj).join(), "f");
-}, "'WebAssembly.Instance' 'exports' object");
+}, "exports object");
 
 test(() => {
     const f = exportsObj.f;
@@ -492,6 +494,14 @@ test(() => {
     assert_equals(buf.byteLength, 2 * WasmPage);
     assertThrows(() => mem.grow(1), Error);
     assert_equals(buf, mem.buffer);
+
+    mem = new Memory({initial:0, maximum:1});
+    buf = mem.buffer;
+    assert_equals(buf.byteLength, 0);
+    assert_equals(mem.grow(0), 0);
+    assert_equals(buf !== mem.buffer, true);
+    assert_equals(buf.byteLength, 0);
+    assert_equals(mem.buffer.byteLength, 0);
 }, "'WebAssembly.Memory.prototype.grow' method");
 
 test(() => {
@@ -698,7 +708,7 @@ function assertCompileSuccess(bytes) {
 }
 
 assertCompileSuccess(emptyModuleBinary);
-assertCompileSuccess(emptyModuleBinary.buffer);
+assertCompileSuccess(new Uint8Array(emptyModuleBinary));
 
 test(() => {
     const instantiateDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'instantiate');
@@ -722,7 +732,6 @@ test(() => {
                 })
                 .catch(error => {
                     assert_equals(error instanceof err, true);
-                    assert_equals(Boolean(error.stack.match("jsapi.js")), true);
                 })
         }, 'unexpected success in assertInstantiateError');
     }
@@ -772,10 +781,10 @@ test(() => {
     }
     assertInstantiateSuccess(emptyModule);
     assertInstantiateSuccess(emptyModuleBinary);
-    assertInstantiateSuccess(emptyModuleBinary.buffer);
+    assertInstantiateSuccess(new Uint8Array(emptyModuleBinary));
     assertInstantiateSuccess(importingModule, {"":{f:()=>{}}});
     assertInstantiateSuccess(importingModuleBinary, {"":{f:()=>{}}});
-    assertInstantiateSuccess(importingModuleBinary.buffer, {"":{f:()=>{}}});
+    assertInstantiateSuccess(new Uint8Array(importingModuleBinary), {"":{f:()=>{}}});
     assertInstantiateSuccess(complexImportingModuleBinary, {
         a:{b:()=>{}},
         c:{d:scratch_memory},

+ 0 - 1
test/wasm/api.js

@@ -180,7 +180,6 @@ async function testModuleCustomSection(baseModule) {
   console.log("\nWebAssembly.Module.customSections tests");
   await testInvalidCases([
     ...(invalidModules.map(b => () => WebAssembly.Module.customSections(b))),
-    () => WebAssembly.Module.customSections(baseModule),
     () => WebAssembly.Module.customSections(baseModule, {toString() {throw new Error("Doesn't support toString");}}),
     () => WebAssembly.Module.customSections(baseModule, Symbol()),
   ]);

+ 22 - 23
test/wasm/baselines/api.baseline

@@ -22,8 +22,8 @@ Test 3 passed. Expected Error: TypeError: BufferSource expected
 Test 4 passed. Expected Error: TypeError: BufferSource expected
 Test 5 passed. Expected Error: TypeError: BufferSource expected
 Test 6 passed. Expected Error: TypeError: BufferSource expected
-Test 7 passed. Expected Error: WebAssemblyCompileError: Out of file: Needed: 4, Left: 0
-Test 8 passed. Expected Error: WebAssemblyCompileError: Out of file: Needed: 1, Left: 0
+Test 7 passed. Expected Error: CompileError: Out of file: Needed: 4, Left: 0
+Test 8 passed. Expected Error: CompileError: Out of file: Needed: 1, Left: 0
 Test 9 passed. Expected Error: TypeError: BufferSource expected
 Testing module
 exports
@@ -39,8 +39,8 @@ Test 3 passed. Expected Error: TypeError: BufferSource expected
 Test 4 passed. Expected Error: TypeError: BufferSource expected
 Test 5 passed. Expected Error: TypeError: BufferSource expected
 Test 6 passed. Expected Error: TypeError: BufferSource expected
-Test 7 passed. Expected Error: WebAssemblyCompileError: Out of file: Needed: 4, Left: 0
-Test 8 passed. Expected Error: WebAssemblyCompileError: Out of file: Needed: 1, Left: 0
+Test 7 passed. Expected Error: CompileError: Out of file: Needed: 4, Left: 0
+Test 8 passed. Expected Error: CompileError: Out of file: Needed: 1, Left: 0
 Test 9 passed. Expected Error: TypeError: BufferSource expected
 Test 10 passed. Expected Error: TypeError: Object expected
 Test 11 passed. Expected Error: TypeError: Object expected
@@ -87,8 +87,8 @@ Test 5 passed. Expected Error: TypeError: BufferSource expected
 Test 6 passed. Expected Error: TypeError: BufferSource expected
 Test 7 passed. Expected Error: TypeError: BufferSource expected
 Test 8 passed. Expected Error: TypeError: BufferSource expected
-Test 9 passed. Expected Error: WebAssemblyCompileError: Out of file: Needed: 4, Left: 0
-Test 10 passed. Expected Error: WebAssemblyCompileError: Out of file: Needed: 1, Left: 0
+Test 9 passed. Expected Error: CompileError: Out of file: Needed: 4, Left: 0
+Test 10 passed. Expected Error: CompileError: Out of file: Needed: 1, Left: 0
 Test 11 passed. Expected Error: TypeError: BufferSource expected
 Testing module
 exports
@@ -115,9 +115,8 @@ Test 0 passed. Expected Error: TypeError: WebAssembly.Module expected
 Test 1 passed. Expected Error: TypeError: WebAssembly.Module expected
 Test 2 passed. Expected Error: TypeError: WebAssembly.Module expected
 Test 3 passed. Expected Error: TypeError: WebAssembly.Module expected
-Test 4 passed. Expected Error: TypeError: 'sectionName' is not a string
-Test 5 passed. Expected Error: Error: Doesn't support toString
-Test 6 passed. Expected Error: TypeError: Object doesn't support property or method 'ToString'
+Test 4 passed. Expected Error: Error: Doesn't support toString
+Test 5 passed. Expected Error: TypeError: Object doesn't support property or method 'ToString'
 6/6 tests passed
 
 new WebAssembly.Instance tests
@@ -128,14 +127,14 @@ Test 3 passed. Expected Error: TypeError: Object expected
 Test 4 passed. Expected Error: TypeError: Object expected
 Test 5 passed. Expected Error: TypeError: Unable to get property 'fn' of undefined or null reference
 Test 6 passed. Expected Error: TypeError: Unable to get property 'fn' of undefined or null reference
-Test 7 passed. Expected Error: WebAssemblyLinkError: Function expected
-Test 8 passed. Expected Error: WebAssemblyLinkError: Cannot link import test.fn.Thunk[0]()->i32 to fn2()->f32 in link table due to a signature mismatch
-Test 9 passed. Expected Error: WebAssemblyLinkError: WebAssembly.Memory object expected
-Test 10 passed. Expected Error: WebAssemblyLinkError: WebAssembly.Memory object expected
-Test 11 passed. Expected Error: WebAssemblyLinkError: WebAssembly.Memory object expected
-Test 12 passed. Expected Error: WebAssemblyLinkError: WebAssembly.Table object expected
-Test 13 passed. Expected Error: WebAssemblyLinkError: WebAssembly.Table object expected
-Test 14 passed. Expected Error: WebAssemblyLinkError: WebAssembly.Table object expected
+Test 7 passed. Expected Error: LinkError: Function expected
+Test 8 passed. Expected Error: LinkError: Cannot link import test.fn.Thunk[0]()->i32 to fn2()->f32 in link table due to a signature mismatch
+Test 9 passed. Expected Error: LinkError: WebAssembly.Memory object expected
+Test 10 passed. Expected Error: LinkError: WebAssembly.Memory object expected
+Test 11 passed. Expected Error: LinkError: WebAssembly.Memory object expected
+Test 12 passed. Expected Error: LinkError: WebAssembly.Table object expected
+Test 13 passed. Expected Error: LinkError: WebAssembly.Table object expected
+Test 14 passed. Expected Error: LinkError: WebAssembly.Table object expected
 Testing instance
 f1: 5
 fn: 1
@@ -206,12 +205,12 @@ Test 4 passed. Expected Error: TypeError: WebAssembly exported function expected
 Test 5 passed. Expected Error: TypeError: WebAssembly exported function expected
 Test 6 passed. Expected Error: TypeError: WebAssembly exported function expected
 Test 7 passed. Expected Error: TypeError: WebAssembly exported function expected
-Test 8 passed. Expected Error: WebAssemblyRuntimeError: WebAssembly exported function expected
-Test 9 passed. Expected Error: WebAssemblyRuntimeError: WebAssembly exported function expected
-Test 10 passed. Expected Error: WebAssemblyRuntimeError: WebAssembly exported function expected
-Test 11 passed. Expected Error: WebAssemblyRuntimeError: Table index is out of range
-Test 12 passed. Expected Error: WebAssemblyRuntimeError: Function called with invalid signature
-Test 13 passed. Expected Error: WebAssemblyRuntimeError: Function called with invalid signature
+Test 8 passed. Expected Error: RuntimeError: WebAssembly exported function expected
+Test 9 passed. Expected Error: RuntimeError: WebAssembly exported function expected
+Test 10 passed. Expected Error: RuntimeError: WebAssembly exported function expected
+Test 11 passed. Expected Error: RuntimeError: Table index is out of range
+Test 12 passed. Expected Error: RuntimeError: Function called with invalid signature
+Test 13 passed. Expected Error: RuntimeError: Function called with invalid signature
 Current length: 30
 Length after attempt to modify : 30
 Is element in table the same as the one exported: true