From b7a70c5c33b4216e0239dfbd55ca54c4070804fd Mon Sep 17 00:00:00 2001 From: HyukWoo Park Date: Wed, 24 Jul 2024 15:56:22 +0900 Subject: [PATCH] Update WASM js-api Signed-off-by: HyukWoo Park --- src/runtime/StaticStrings.h | 2 + src/wasm/BuiltinWASM.cpp | 156 ++++++++++++----------- src/wasm/ExportedFunctionObject.cpp | 6 +- src/wasm/WASMObject.cpp | 184 ++++++++++++++++++---------- src/wasm/WASMObject.h | 17 ++- src/wasm/WASMOperations.cpp | 8 +- src/wasm/WASMValueConverter.cpp | 121 +++++++++++------- src/wasm/WASMValueConverter.h | 7 +- third_party/walrus | 2 +- tools/run-tests.py | 2 +- tools/test/wasm-js/exclude_list.txt | 5 - 11 files changed, 307 insertions(+), 203 deletions(-) diff --git a/src/runtime/StaticStrings.h b/src/runtime/StaticStrings.h index 2408ed927..9cfae8fbd 100644 --- a/src/runtime/StaticStrings.h +++ b/src/runtime/StaticStrings.h @@ -509,6 +509,7 @@ namespace Escargot { F(customSections) \ F(element) \ F(exports) \ + F(externref) \ F(f32) \ F(f64) \ F(i32) \ @@ -522,6 +523,7 @@ namespace Escargot { F(memory) \ F(module) \ F(table) \ + F(v128) \ F(validate) #else #define FOR_EACH_STATIC_WASM_STRING(F) diff --git a/src/wasm/BuiltinWASM.cpp b/src/wasm/BuiltinWASM.cpp index 028482398..d54304157 100644 --- a/src/wasm/BuiltinWASM.cpp +++ b/src/wasm/BuiltinWASM.cpp @@ -550,13 +550,12 @@ static Value builtinWASMTableConstructor(ExecutionState& state, Value thisValue, Value desc = argv[0]; - // check 'element' property from the first argument - { - Value elemValue = wasmGetValueFromObjectProperty(state, desc, strings->element, strings->toString).second; - // element property should be 'anyfunc' - if (UNLIKELY(!elemValue.isString() || !elemValue.asString()->equals(strings->anyfunc.string()))) { - ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->WebAssembly.string(), false, strings->Table.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument); - } + // Let elementType be ToValueType(descriptor["element"]). + wasm_valkind_t elementType = WASMValueConverter::toValueType(state, wasmGetValueFromObjectProperty(state, desc, strings->element, strings->toString).second); + // If elementType is not a reftype, + if (UNLIKELY(elementType != WASM_FUNCREF && elementType != WASM_ANYREF)) { + // Throw a TypeError exception. + ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->WebAssembly.string(), false, strings->Table.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument); } // check and get 'initial' property from the first argument @@ -586,19 +585,34 @@ static Value builtinWASMTableConstructor(ExecutionState& state, Value thisValue, ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, strings->WebAssembly.string(), false, strings->Table.string(), ErrorObject::Messages::GlobalObject_RangeError); } + // If value is missing, + // Let ref be DefaultValue(elementType). + ASSERT(elementType == WASM_ANYREF || elementType == WASM_FUNCREF); + wasm_ref_t* ref = nullptr; + wasm_val_t value; + if (argc > 1) { + // Let ref be ? ToWebAssemblyValue(value, elementType). + value = WASMValueConverter::toWebAssemblyValue(state, argv[1], elementType); + } else { + // If value is missing, + // Let ref be DefaultValue(elementType). + value = WASMValueConverter::defaultValue(state, elementType); + } + ASSERT(value.kind == WASM_ANYREF || value.kind == WASM_FUNCREF); + ref = value.of.ref; + // Let type be the table type {min n, max maximum} anyfunc. wasm_limits_t limits = { initial, maximum }; // wasm_valtype_t is deleted inside wasm_tabletype_t constructor - own wasm_tabletype_t* tabletype = wasm_tabletype_new(wasm_valtype_new(WASM_FUNCREF), &limits); + own wasm_tabletype_t* tabletype = wasm_tabletype_new(wasm_valtype_new(elementType), &limits); - // Let (store, tableaddr) be table_alloc(store, type). - own wasm_table_t* tableaddr = wasm_table_new(ThreadLocal::wasmStore(), tabletype, nullptr); + // Let (store, tableaddr) be table_alloc(store, type, ref). + own wasm_table_t* tableaddr = wasm_table_new(ThreadLocal::wasmStore(), tabletype, ref); wasm_tabletype_delete(tabletype); wasm_ref_t* tableref = wasm_table_as_ref(tableaddr); // Let map be the surrounding agent's associated Table object cache. - // Let proto be ? GetPrototypeFromConstructor(newTarget, "%WebAssemblyTablePrototype%"). Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* { return constructorRealm->globalObject()->wasmTablePrototype(); @@ -633,8 +647,28 @@ static Value builtinWASMTableGrow(ExecutionState& state, Value thisValue, size_t wasm_table_t* tableaddr = thisValue.asObject()->asWASMTableObject()->table(); wasm_table_size_t initialSize = wasm_table_size(tableaddr); - // Let result be table_grow(store, tableaddr, delta). - bool result = wasm_table_grow(tableaddr, delta, nullptr); + // Let (limits, elementType) be table_type(tableaddr). + own wasm_tabletype_t* tabletype = wasm_table_type(tableaddr); + wasm_valkind_t elementType = wasm_valtype_kind(wasm_tabletype_element(tabletype)); + wasm_tabletype_delete(tabletype); + ASSERT(elementType == WASM_ANYREF || elementType == WASM_FUNCREF); + + wasm_ref_t* ref = nullptr; + wasm_val_t value; + if (argc > 1) { + // Let ref be ? ToWebAssemblyValue(value, elementType). + value = WASMValueConverter::toWebAssemblyValue(state, argv[1], elementType); + } else { + // If value is missing, + // Let ref be DefaultValue(elementType). + value = WASMValueConverter::defaultValue(state, elementType); + } + ASSERT(value.kind == WASM_ANYREF || value.kind == WASM_FUNCREF); + ref = value.of.ref; + + + // Let result be table_grow(store, tableaddr, delta, ref). + bool result = wasm_table_grow(tableaddr, delta, ref); // If result is error, throw a RangeError exception. if (!result) { ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, strings->WebAssemblyDotTable.string(), false, strings->grow.string(), ErrorObject::Messages::GlobalObject_RangeError); @@ -661,14 +695,12 @@ static Value builtinWASMTableGet(ExecutionState& state, Value thisValue, size_t // Let tableaddr be this.[[Table]]. wasm_table_t* tableaddr = thisValue.asObject()->asWASMTableObject()->table(); - // Let result be table_read(store, tableaddr, index). - own wasm_ref_t* result = wasm_table_get(tableaddr, index); - // If result is error, throw a RangeError exception. - // FIXME - if (!result) { + if (UNLIKELY(index >= wasm_table_size(tableaddr))) { ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, strings->WebAssemblyDotTable.string(), false, strings->get.string(), ErrorObject::Messages::GlobalObject_RangeError); } + // Let result be table_read(store, tableaddr, index). + own wasm_ref_t* result = wasm_table_get(tableaddr, index); own wasm_tabletype_t* tabletype = wasm_table_type(tableaddr); wasm_valkind_t elementType = wasm_valtype_kind(wasm_tabletype_element(tabletype)); @@ -684,8 +716,11 @@ static Value builtinWASMTableGet(ExecutionState& state, Value thisValue, size_t resultVal.kind = WASM_FUNCREF; resultVal.of.ref = result; } - Value resultValue = WASMValueConverter::wasmToJSValue(state, resultVal); - wasm_ref_delete(result); + Value resultValue = WASMValueConverter::toJSValue(state, resultVal); + if (result && !WASMCacheMap::isOtherExternAddr(result)) { + // result could be nullptr (ref.null) + wasm_ref_delete(result); + } return resultValue; } @@ -716,15 +751,17 @@ static Value builtinWASMTableSet(ExecutionState& state, Value thisValue, size_t ASSERT(elementType == WASM_ANYREF || elementType == WASM_FUNCREF); wasm_ref_t* ref = nullptr; - // If value is missing, - // Let ref be DefaultValue(elementType). - // FIXME invoke wasmDefaultValue ? + wasm_val_t value; if (argc > 1) { // Let ref be ? ToWebAssemblyValue(value, elementType). - wasm_val_t value = WASMValueConverter::wasmToWebAssemblyValue(state, argv[1], elementType); - ASSERT(value.kind == WASM_ANYREF || value.kind == WASM_FUNCREF); - ref = value.of.ref; + value = WASMValueConverter::toWebAssemblyValue(state, argv[1], elementType); + } else { + // If value is missing, + // Let ref be DefaultValue(elementType). + value = WASMValueConverter::defaultValue(state, elementType); } + ASSERT(value.kind == WASM_ANYREF || value.kind == WASM_FUNCREF); + ref = value.of.ref; // Let store be table_write(store, tableaddr, index, ref). bool result = wasm_table_set(tableaddr, index, ref); @@ -735,31 +772,6 @@ static Value builtinWASMTableSet(ExecutionState& state, Value thisValue, size_t // Return undefined. return Value(); - - /* - - // Value value = argv[1]; - // FIXME If value is null, let funcaddr be an empty function element. - wasm_ref_t* funcaddr = nullptr; - if (!value.isNull()) { - // If value does not have a [[FunctionAddress]] internal slot, throw a TypeError exception. - if (!value.isObject() || !value.asObject()->isExportedFunctionObject()) { - ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->WebAssemblyDotTable.string(), false, strings->set.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument); - } - // Let funcaddr be value.[[FunctionAddress]]. - funcaddr = wasm_func_as_ref(value.asObject()->asExportedFunctionObject()->function()); - } - - // Let store be table_write(store, tableaddr, index, funcaddr). - bool result = wasm_table_set(tableaddr, index, funcaddr); - // If store is error, throw a RangeError exception. - if (!result) { - ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, strings->WebAssemblyDotTable.string(), false, strings->set.string(), ErrorObject::Messages::GlobalObject_RangeError); - } - - // Return undefined. - return Value(); - */ } static Value builtinWASMTableLengthGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional newTarget) @@ -795,39 +807,25 @@ static Value builtinWASMGlobalConstructor(ExecutionState& state, Value thisValue mut = mutValue.toBoolean() ? WASM_VAR : WASM_CONST; } - // check and get 'value' property from the first argument - wasm_valkind_t valuetype = WASM_ANYREF; - { - // Let valuetype be ToValueType(descriptor["value"]). - Value valTypeValue = wasmGetValueFromObjectProperty(state, desc, strings->value, strings->toString).second; - if (!valTypeValue.isString()) { - ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->WebAssembly.string(), false, strings->Global.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument); - } - if (valTypeValue.asString()->equals(strings->i32.string())) { - valuetype = WASM_I32; - } else if (valTypeValue.asString()->equals(strings->i64.string())) { - valuetype = WASM_I64; - } else if (valTypeValue.asString()->equals(strings->f32.string())) { - valuetype = WASM_F32; - } else if (valTypeValue.asString()->equals(strings->f64.string())) { - valuetype = WASM_F64; - } else { - ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->WebAssembly.string(), false, strings->Global.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument); - } + // Let valuetype be ToValueType(descriptor["value"]). + wasm_valkind_t valuetype = WASMValueConverter::toValueType(state, wasmGetValueFromObjectProperty(state, desc, strings->value, strings->toString).second); + // If valuetype is v128, + if (valuetype == WASM_V128) { + // Throw a TypeError exception. + ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, strings->WebAssembly.string(), false, strings->Global.string(), ErrorObject::Messages::GlobalObject_IllegalFirstArgument); } - Value valueArg = argc > 1 ? argv[1] : Value(); - own wasm_val_t value; - if (valueArg.isUndefined()) { - // let value be DefaultValue(valuetype). - value = WASMValueConverter::wasmDefaultValue(valuetype); - } else { + wasm_val_t value; + if (argc > 1 && !argv[1].isUndefined()) { // Let value be ToWebAssemblyValue(v, valuetype). - value = WASMValueConverter::wasmToWebAssemblyValue(state, valueArg, valuetype); + value = WASMValueConverter::toWebAssemblyValue(state, argv[1], valuetype); + } else { + // If v is missing, + // Let value be DefaultValue(valuetype). + value = WASMValueConverter::defaultValue(state, valuetype); } // If mutable is true, let globaltype be var valuetype; otherwise, let globaltype be const valuetype. - // Note) value should not have any reference in itself, so we don't have to call `wasm_val_delete` own wasm_globaltype_t* globaltype = wasm_globaltype_new(wasm_valtype_new(valuetype), mut); // Let (store, globaladdr) be global_alloc(store, globaltype, value). @@ -888,7 +886,7 @@ static Value builtinWASMGlobalValueSetter(ExecutionState& state, Value thisValue // Let value be ToWebAssemblyValue(the given value, valuetype). // Note) value should not have any reference in itself, so we don't have to call `wasm_val_delete` - own wasm_val_t value = WASMValueConverter::wasmToWebAssemblyValue(state, argv[0], valuetype); + own wasm_val_t value = WASMValueConverter::toWebAssemblyValue(state, argv[0], valuetype); // Let store be global_write(store, globaladdr, value). // TODO If store is error, throw a RangeError exception. diff --git a/src/wasm/ExportedFunctionObject.cpp b/src/wasm/ExportedFunctionObject.cpp index b0e49394c..c32b46393 100644 --- a/src/wasm/ExportedFunctionObject.cpp +++ b/src/wasm/ExportedFunctionObject.cpp @@ -85,7 +85,7 @@ static Value callExportedFunction(ExecutionState& state, Value thisValue, size_t Value arg = (argc > i) ? argv[i] : Value(); // Append ToWebAssemblyValue(arg, t) to args. - args.data[i] = WASMValueConverter::wasmToWebAssemblyValue(state, arg, wasm_valtype_kind(parameters->data[i])); + args.data[i] = WASMValueConverter::toWebAssemblyValue(state, arg, wasm_valtype_kind(parameters->data[i])); } wasm_val_t* retBuffer = ALLOCA(results->size * sizeof(wasm_val_t), wasm_val_t); @@ -114,7 +114,7 @@ static Value callExportedFunction(ExecutionState& state, Value thisValue, size_t return Value(); } else if (outArity == 1) { // Otherwise, if outArity is 1, return ToJSValue(ret[0]). - return WASMValueConverter::wasmToJSValue(state, ret.data[0]); + return WASMValueConverter::toJSValue(state, ret.data[0]); } // Otherwise, @@ -125,7 +125,7 @@ static Value callExportedFunction(ExecutionState& state, Value thisValue, size_t // For each r of ret, // Append ToJSValue(r) to values. for (size_t i = 0; i < ret.size; i++) { - values[i] = WASMValueConverter::wasmToJSValue(state, ret.data[i]); + values[i] = WASMValueConverter::toJSValue(state, ret.data[i]); } // Return CreateArrayFromList(values). diff --git a/src/wasm/WASMObject.cpp b/src/wasm/WASMObject.cpp index dabc748a2..4ce68b4fd 100644 --- a/src/wasm/WASMObject.cpp +++ b/src/wasm/WASMObject.cpp @@ -328,7 +328,7 @@ Value WASMGlobalObject::getGlobalValue(ExecutionState& state) const wasm_global_get(globaladdr, &value); // Return ToJSValue(value). - return WASMValueConverter::wasmToJSValue(state, value); + return WASMValueConverter::toJSValue(state, value); } void WASMCacheMap::appendMemory(wasm_ref_t* ref, WASMMemoryObject* memoryObj) @@ -359,28 +359,44 @@ void WASMCacheMap::appendFunction(wasm_ref_t* ref, ExportedFunctionObject* funcO m_functionMap.pushBack(std::make_pair(ref, funcObj)); } +void WASMCacheMap::appendOther(wasm_ref_t* ref, const Value& value) +{ + ASSERT(!!ref && isOtherExternAddr(ref)); + ASSERT(!findOther(ref).first); + m_otherMap.pushBack(std::make_pair(ref, value)); +} + wasm_ref_t* WASMCacheMap::insertRefByValue(const Value& value) { - ASSERT(value.isObject()); - Object* val = value.asObject(); wasm_ref_t* result = nullptr; - if (val->isWASMMemoryObject()) { - result = wasm_memory_as_ref(val->asWASMMemoryObject()->memory()); - appendMemory(result, val->asWASMMemoryObject()); - } else if (val->isWASMTableObject()) { - result = wasm_table_as_ref(val->asWASMTableObject()->table()); - appendTable(result, val->asWASMTableObject()); - } else if (val->isWASMGlobalObject()) { - result = wasm_global_as_ref(val->asWASMGlobalObject()->global()); - appendGlobal(result, val->asWASMGlobalObject()); - } else if (val->isExportedFunctionObject()) { - result = wasm_func_as_ref(val->asExportedFunctionObject()->function()); - appendFunction(result, val->asExportedFunctionObject()); - } else { - ASSERT_NOT_REACHED(); + if (value.isObject()) { + Object* val = value.asObject(); + if (val->isWASMMemoryObject()) { + result = wasm_memory_as_ref(val->asWASMMemoryObject()->memory()); + appendMemory(result, val->asWASMMemoryObject()); + return result; + } else if (val->isWASMTableObject()) { + result = wasm_table_as_ref(val->asWASMTableObject()->table()); + appendTable(result, val->asWASMTableObject()); + return result; + } else if (val->isWASMGlobalObject()) { + result = wasm_global_as_ref(val->asWASMGlobalObject()->global()); + appendGlobal(result, val->asWASMGlobalObject()); + return result; + } else if (val->isExportedFunctionObject()) { + result = wasm_func_as_ref(val->asExportedFunctionObject()->function()); + appendFunction(result, val->asExportedFunctionObject()); + return result; + } } + // Let extern address externaddr be the smallest address such that map[externaddr] exists is false. + // Set map[externaddr] to v. + result = getOtherExternAddr(); + ASSERT(isOtherExternAddr(result)); + appendOther(result, value); + return result; } @@ -424,76 +440,116 @@ ExportedFunctionObject* WASMCacheMap::findFunction(wasm_ref_t* ref) return nullptr; } -wasm_ref_t* WASMCacheMap::findRefByValue(const Value& value) +std::pair WASMCacheMap::findOther(wasm_ref_t* ref) { - ASSERT(value.isObject()); - Object* val = value.asObject(); - wasm_ref_t* ref = nullptr; + ASSERT(isOtherExternAddr(ref)); + for (auto iter = m_otherMap.begin(); iter != m_otherMap.end(); iter++) { + if (iter->first == ref) { + return std::make_pair(true, iter->second); + } + } + return std::make_pair(false, Value()); +} - if (val->isWASMMemoryObject()) { - ref = wasm_memory_as_ref(val->asWASMMemoryObject()->memory()); - for (auto iter = m_memoryMap.begin(); iter != m_memoryMap.end(); iter++) { - if (wasm_ref_same(iter->first, ref)) { - return ref; +wasm_ref_t* WASMCacheMap::findRefByValue(const Value& value) +{ + if (value.isObject()) { + wasm_ref_t* ref = nullptr; + Object* val = value.asObject(); + if (val->isWASMMemoryObject()) { + ref = wasm_memory_as_ref(val->asWASMMemoryObject()->memory()); + for (auto iter = m_memoryMap.begin(); iter != m_memoryMap.end(); iter++) { + if (wasm_ref_same(iter->first, ref)) { + ASSERT(iter->second == val->asWASMMemoryObject()); + return ref; + } } - } - return nullptr; - } else if (val->isWASMTableObject()) { - ref = wasm_table_as_ref(val->asWASMTableObject()->table()); - for (auto iter = m_tableMap.begin(); iter != m_tableMap.end(); iter++) { - if (wasm_ref_same(iter->first, ref)) { - return ref; + return nullptr; + } else if (val->isWASMTableObject()) { + ref = wasm_table_as_ref(val->asWASMTableObject()->table()); + for (auto iter = m_tableMap.begin(); iter != m_tableMap.end(); iter++) { + if (wasm_ref_same(iter->first, ref)) { + ASSERT(iter->second == val->asWASMTableObject()); + return ref; + } } - } - return nullptr; - } else if (val->isWASMGlobalObject()) { - ref = wasm_global_as_ref(val->asWASMGlobalObject()->global()); - for (auto iter = m_globalMap.begin(); iter != m_globalMap.end(); iter++) { - if (wasm_ref_same(iter->first, ref)) { - return ref; + return nullptr; + } else if (val->isWASMGlobalObject()) { + ref = wasm_global_as_ref(val->asWASMGlobalObject()->global()); + for (auto iter = m_globalMap.begin(); iter != m_globalMap.end(); iter++) { + if (wasm_ref_same(iter->first, ref)) { + ASSERT(iter->second == val->asWASMGlobalObject()); + return ref; + } } - } - return nullptr; - } else if (val->isExportedFunctionObject()) { - ref = wasm_func_as_ref(val->asExportedFunctionObject()->function()); - for (auto iter = m_functionMap.begin(); iter != m_functionMap.end(); iter++) { - if (wasm_ref_same(iter->first, ref)) { - return ref; + return nullptr; + } else if (val->isExportedFunctionObject()) { + ref = wasm_func_as_ref(val->asExportedFunctionObject()->function()); + for (auto iter = m_functionMap.begin(); iter != m_functionMap.end(); iter++) { + if (wasm_ref_same(iter->first, ref)) { + ASSERT(iter->second == val->asExportedFunctionObject()); + return ref; + } } + return nullptr; + } + } + + for (auto iter = m_otherMap.begin(); iter != m_otherMap.end(); iter++) { + if (iter->second == value) { + return iter->first; } - return nullptr; - } else { - ASSERT_NOT_REACHED(); - return nullptr; } + return nullptr; } Value WASMCacheMap::findValueByRef(wasm_ref_t* ref) { + // should find a value in WASMCacheMap ASSERT(!!ref); - Object* result = nullptr; - - if ((result = findFunction(ref))) { - return result; - } + if (UNLIKELY(isOtherExternAddr(ref))) { + auto result = findOther(ref); + ASSERT(result.first); + return result.second; + } else { + Object* result = nullptr; + if ((result = findFunction(ref))) { + return result; + } - if ((result = findGlobal(ref))) { - return result; - } + if ((result = findGlobal(ref))) { + return result; + } - if ((result = findMemory(ref))) { - return result; - } + if ((result = findMemory(ref))) { + return result; + } - if ((result = findTable(ref))) { - return result; + if ((result = findTable(ref))) { + return result; + } } // Assert: map[externaddr] exists. ASSERT_NOT_REACHED(); + return Value(); +} + +bool WASMCacheMap::isOtherExternAddr(wasm_ref_t* ref) +{ + return ((size_t)ref & OTHER_EXTERN_REF_TAG); +} + +wasm_ref_t* WASMCacheMap::getOtherExternAddr() +{ + ASSERT((m_otherExternAddrIndex << OTHER_EXTERN_REF_TAG) < std::numeric_limits::max()); + + wasm_ref_t* result = reinterpret_cast((m_otherExternAddrIndex << OTHER_EXTERN_REF_TAG) | OTHER_EXTERN_REF_TAG); + m_otherExternAddrIndex++; return result; } + } // namespace Escargot #endif // ENABLE_WASM diff --git a/src/wasm/WASMObject.h b/src/wasm/WASMObject.h index 1034bd434..50f289704 100644 --- a/src/wasm/WASMObject.h +++ b/src/wasm/WASMObject.h @@ -182,18 +182,25 @@ class WASMGlobalObject : public DerivedObject { typedef Vector, GCUtil::gc_malloc_allocator>> WASMMemoryMap; typedef Vector, GCUtil::gc_malloc_allocator>> WASMTableMap; typedef Vector, GCUtil::gc_malloc_allocator>> WASMGlobalMap; +typedef Vector, GCUtil::gc_malloc_allocator>> WASMOtherMap; class ExportedFunctionObject; typedef Vector, GCUtil::gc_malloc_allocator>> WASMFunctionMap; class WASMCacheMap : public gc { public: - WASMCacheMap() {} + static const size_t OTHER_EXTERN_REF_TAG = 1; + + WASMCacheMap() + : m_otherExternAddrIndex(0) + { + } void appendMemory(wasm_ref_t* ref, WASMMemoryObject* memoryObj); void appendTable(wasm_ref_t* ref, WASMTableObject* tableObj); void appendGlobal(wasm_ref_t* ref, WASMGlobalObject* globalObj); void appendFunction(wasm_ref_t* ref, ExportedFunctionObject* funcObj); + void appendOther(wasm_ref_t* ref, const Value& value); wasm_ref_t* insertRefByValue(const Value& value); @@ -201,15 +208,23 @@ class WASMCacheMap : public gc { WASMTableObject* findTable(wasm_ref_t* ref); WASMGlobalObject* findGlobal(wasm_ref_t* ref); ExportedFunctionObject* findFunction(wasm_ref_t* ref); + std::pair findOther(wasm_ref_t* ref); wasm_ref_t* findRefByValue(const Value& value); Value findValueByRef(wasm_ref_t* ref); + static bool isOtherExternAddr(wasm_ref_t* ref); + private: + wasm_ref_t* getOtherExternAddr(); + WASMMemoryMap m_memoryMap; WASMTableMap m_tableMap; WASMGlobalMap m_globalMap; WASMFunctionMap m_functionMap; + WASMOtherMap m_otherMap; + + size_t m_otherExternAddrIndex; // used as a arbitrary extern address for WASMOtherMap }; } // namespace Escargot #endif // __EscargotWASMObject__ diff --git a/src/wasm/WASMOperations.cpp b/src/wasm/WASMOperations.cpp index acafbc32f..14e901ca7 100644 --- a/src/wasm/WASMOperations.cpp +++ b/src/wasm/WASMOperations.cpp @@ -62,7 +62,7 @@ static own wasm_trap_t* callbackHostFunction(void* env, const wasm_val_vec_t* ar // For each arg of arguments, for (size_t i = 0; i < argSize; i++) { // Append ! ToJSValue(arg) to jsArguments. - jsArguments[i] = WASMValueConverter::wasmToJSValue(state, args->data[i]); + jsArguments[i] = WASMValueConverter::toJSValue(state, args->data[i]); } // Let ret be ? Call(func, undefined, jsArguments). @@ -104,7 +104,7 @@ static own wasm_trap_t* callbackHostFunction(void* env, const wasm_val_vec_t* ar Value ret = result.result; if (resultsSize == 1) { // Otherwise, if resultsSize is 1, return << ToWebAssemblyValue(ret, results[0]) >> - results->data[0] = WASMValueConverter::wasmToWebAssemblyValue(state, ret, wasm_valtype_kind(res->data[0])); + results->data[0] = WASMValueConverter::toWebAssemblyValue(state, ret, wasm_valtype_kind(res->data[0])); } else { // Otherwise, // Let method be ? GetMethod(ret, @@iterator). @@ -124,7 +124,7 @@ static own wasm_trap_t* callbackHostFunction(void* env, const wasm_val_vec_t* ar // For each value and resultType in values and results, paired linearly, // Append ToWebAssemblyValue(value, resultType) to wasmValues. for (size_t i = 0; i < resultsSize; i++) { - results->data[i] = WASMValueConverter::wasmToWebAssemblyValue(state, values[i], wasm_valtype_kind(res->data[i])); + results->data[i] = WASMValueConverter::toWebAssemblyValue(state, values[i], wasm_valtype_kind(res->data[i])); } } @@ -456,7 +456,7 @@ void WASMOperations::readImportsOfModule(ExecutionState& state, wasm_module_t* m // Let value be ToWebAssemblyValue(v, valtype). // Note) value should not have any reference in itself, so we don't have to call `wasm_val_delete` - own wasm_val_t value = WASMValueConverter::wasmToWebAssemblyValue(state, v, wasm_valtype_kind(valtype)); + own wasm_val_t value = WASMValueConverter::toWebAssemblyValue(state, v, wasm_valtype_kind(valtype)); // Let (store, globaladdr) be global_alloc(store, const valtype, value). // FIXME globaltype diff --git a/src/wasm/WASMValueConverter.cpp b/src/wasm/WASMValueConverter.cpp index 81aacf098..e1c6acddd 100644 --- a/src/wasm/WASMValueConverter.cpp +++ b/src/wasm/WASMValueConverter.cpp @@ -67,7 +67,45 @@ namespace Escargot { result.kind = WASM_ANYREF; \ result.of.ref = nullptr; -Value WASMValueConverter::wasmToJSValue(ExecutionState& state, const wasm_val_t& value) +wasm_val_t WASMValueConverter::defaultValue(ExecutionState& state, wasm_valkind_t type) +{ + WASM_INIT_VAL(result); + switch (type) { + case WASM_I32: { + WASM_I32_VAL(result, 0); + break; + } + case WASM_I64: { + WASM_I64_VAL(result, 0); + break; + } + case WASM_F32: { + WASM_F32_VAL(result, 0); + break; + } + case WASM_F64: { + WASM_F64_VAL(result, 0); + break; + } + case WASM_ANYREF: { + // return ToWebAssemblyValue(undefined, valuetype). + WASM_REF_VAL(result, toWebAssemblyValue(state, Value(), type).of.ref); + break; + } + case WASM_FUNCREF: { + WASM_FUNC_VAL(result, nullptr); + break; + } + default: { + ASSERT_NOT_REACHED(); + break; + } + } + + return result; +} + +Value WASMValueConverter::toJSValue(ExecutionState& state, const wasm_val_t& value) { Value result; switch (value.kind) { @@ -88,12 +126,20 @@ Value WASMValueConverter::wasmToJSValue(ExecutionState& state, const wasm_val_t& break; } case WASM_ANYREF: { - result = state.context()->wasmCache()->findValueByRef(value.of.ref); + if (!value.of.ref) { + result = Value(Value::Null); + } else { + result = state.context()->wasmCache()->findValueByRef(value.of.ref); + } break; } case WASM_FUNCREF: { - // FIXME set parameter index as 0, need to be fixed - result = ExportedFunctionObject::createExportedFunction(state, wasm_ref_as_func(value.of.ref), 0); + if (!value.of.ref) { + result = Value(Value::Null); + } else { + // FIXME set parameter index as 0, need to be fixed + result = ExportedFunctionObject::createExportedFunction(state, wasm_ref_as_func(value.of.ref), 0); + } break; } default: { @@ -105,7 +151,35 @@ Value WASMValueConverter::wasmToJSValue(ExecutionState& state, const wasm_val_t& return result; } -wasm_val_t WASMValueConverter::wasmToWebAssemblyValue(ExecutionState& state, const Value& value, wasm_valkind_t type) +wasm_valkind_t WASMValueConverter::toValueType(ExecutionState& state, const Value& valTypeValue) +{ + const StaticStrings* strings = &state.context()->staticStrings(); + + if (!valTypeValue.isString()) { + ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument); + } + + if (valTypeValue.asString()->equals(strings->i32.string())) { + return WASM_I32; + } else if (valTypeValue.asString()->equals(strings->i64.string())) { + return WASM_I64; + } else if (valTypeValue.asString()->equals(strings->f32.string())) { + return WASM_F32; + } else if (valTypeValue.asString()->equals(strings->f64.string())) { + return WASM_F64; + } else if (valTypeValue.asString()->equals(strings->v128.string())) { + return WASM_V128; + } else if (valTypeValue.asString()->equals(strings->anyfunc.string())) { + return WASM_FUNCREF; + } else if (valTypeValue.asString()->equals(strings->externref.string())) { + return WASM_ANYREF; + } + + ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_IllegalFirstArgument); + return WASM_ANYREF; +} + +wasm_val_t WASMValueConverter::toWebAssemblyValue(ExecutionState& state, const Value& value, wasm_valkind_t type) { WASM_INIT_VAL(result); switch (type) { @@ -178,42 +252,5 @@ wasm_val_t WASMValueConverter::wasmToWebAssemblyValue(ExecutionState& state, con return result; } -wasm_val_t WASMValueConverter::wasmDefaultValue(wasm_valkind_t type) -{ - WASM_INIT_VAL(result); - switch (type) { - case WASM_I32: { - WASM_I32_VAL(result, 0); - break; - } - case WASM_I64: { - WASM_I64_VAL(result, 0); - break; - } - case WASM_F32: { - WASM_F32_VAL(result, 0); - break; - } - case WASM_F64: { - WASM_F64_VAL(result, 0); - break; - } - case WASM_ANYREF: { - // FIXME return ToWebAssemblyValue(undefined, valuetype). - WASM_REF_VAL(result, nullptr); - break; - } - case WASM_FUNCREF: { - WASM_FUNC_VAL(result, nullptr); - break; - } - default: { - ASSERT_NOT_REACHED(); - break; - } - } - - return result; -} } // namespace Escargot #endif // ENABLE_WASM diff --git a/src/wasm/WASMValueConverter.h b/src/wasm/WASMValueConverter.h index b07bcbaef..53e4ec751 100644 --- a/src/wasm/WASMValueConverter.h +++ b/src/wasm/WASMValueConverter.h @@ -26,9 +26,10 @@ namespace Escargot { class WASMValueConverter { public: - static Value wasmToJSValue(ExecutionState& state, const wasm_val_t& value); - static wasm_val_t wasmToWebAssemblyValue(ExecutionState& state, const Value& value, wasm_valkind_t type); - static wasm_val_t wasmDefaultValue(wasm_valkind_t type); + static wasm_val_t defaultValue(ExecutionState& state, wasm_valkind_t type); + static Value toJSValue(ExecutionState& state, const wasm_val_t& value); + static wasm_valkind_t toValueType(ExecutionState& state, const Value& desc); + static wasm_val_t toWebAssemblyValue(ExecutionState& state, const Value& value, wasm_valkind_t type); }; } // namespace Escargot #endif // __EscargotWASMValueConverter__ diff --git a/third_party/walrus b/third_party/walrus index 8fc0dec19..7800a31ea 160000 --- a/third_party/walrus +++ b/third_party/walrus @@ -1 +1 @@ -Subproject commit 8fc0dec19d7af902ae812b69dac8bfd996ae8ff0 +Subproject commit 7800a31eacf47663cdf21c299ae6e6d4d7550af8 diff --git a/tools/run-tests.py b/tools/run-tests.py index bdb7283d2..14727c2a1 100755 --- a/tools/run-tests.py +++ b/tools/run-tests.py @@ -848,7 +848,7 @@ def run_wasm_js(engine, arch, extra_arg): if (script.startswith(WPT_ROOT)): script = join(WASM_TEST_DIR, script[len(WPT_ROOT):]) else: - script = join(WASM_TEST_DIR, script) + script = join(os.path.dirname(file), script) script_files.append(script) script_files.append(file) diff --git a/tools/test/wasm-js/exclude_list.txt b/tools/test/wasm-js/exclude_list.txt index 75f8067c3..c203ba798 100644 --- a/tools/test/wasm-js/exclude_list.txt +++ b/tools/test/wasm-js/exclude_list.txt @@ -1,8 +1,3 @@ limits.any.js memory/grow.any.js module/customSections.any.js -constructor/instantiate-bad-imports.any.js -instance/constructor-bad-imports.any.js -table/constructor.any.js -table/get-set.any.js -table/grow.any.js