Commit 116e217b authored by Jakob Kummerow's avatar Jakob Kummerow Committed by V8 LUCI CQ

[wasm-gc] Minimal JS interop: the basics

This CL introduces a new LookupIterator state WASM_OBJECT, and updates
all switches that need to handle it.

Bug: v8:7748
Change-Id: Ie3359aed2d37f5a6854e5577fa3799f0464391e4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3865559
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83234}
parent f9bb65eb
...@@ -4,10 +4,9 @@ ...@@ -4,10 +4,9 @@
#include "src/builtins/builtins-utils-inl.h" #include "src/builtins/builtins-utils-inl.h"
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/codegen/code-factory.h"
#include "src/common/message-template.h" #include "src/common/message-template.h"
#include "src/execution/isolate.h"
#include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop. #include "src/heap/heap-inl.h" // For ToBoolean. TODO(jkummerow): Drop.
#include "src/logging/counters.h"
#include "src/objects/keys.h" #include "src/objects/keys.h"
#include "src/objects/lookup.h" #include "src/objects/lookup.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
...@@ -150,6 +149,10 @@ Object ObjectLookupAccessor(Isolate* isolate, Handle<Object> object, ...@@ -150,6 +149,10 @@ Object ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
return ObjectLookupAccessor(isolate, prototype, key, component); return ObjectLookupAccessor(isolate, prototype, key, component);
} }
case LookupIterator::WASM_OBJECT:
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
case LookupIterator::INTEGER_INDEXED_EXOTIC: case LookupIterator::INTEGER_INDEXED_EXOTIC:
case LookupIterator::DATA: case LookupIterator::DATA:
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
......
...@@ -658,6 +658,7 @@ namespace internal { ...@@ -658,6 +658,7 @@ namespace internal {
T(WasmTrapStringIsolatedSurrogate, \ T(WasmTrapStringIsolatedSurrogate, \
"Failed to encode string as UTF-8: contains unpaired surrogate") \ "Failed to encode string as UTF-8: contains unpaired surrogate") \
T(WasmExceptionError, "wasm exception") \ T(WasmExceptionError, "wasm exception") \
T(WasmObjectsAreOpaque, "WebAssembly objects are opaque") \
/* Asm.js validation related */ \ /* Asm.js validation related */ \
T(AsmJsInvalid, "Invalid asm.js: %") \ T(AsmJsInvalid, "Invalid asm.js: %") \
T(AsmJsCompiled, "Converted asm.js to WebAssembly: %") \ T(AsmJsCompiled, "Converted asm.js to WebAssembly: %") \
......
...@@ -5,9 +5,7 @@ ...@@ -5,9 +5,7 @@
#include "src/ic/ic.h" #include "src/ic/ic.h"
#include "src/api/api-arguments-inl.h" #include "src/api/api-arguments-inl.h"
#include "src/api/api.h"
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/base/bits.h"
#include "src/base/logging.h" #include "src/base/logging.h"
#include "src/builtins/accessors.h" #include "src/builtins/accessors.h"
#include "src/common/assert-scope.h" #include "src/common/assert-scope.h"
...@@ -16,6 +14,7 @@ ...@@ -16,6 +14,7 @@
#include "src/execution/execution.h" #include "src/execution/execution.h"
#include "src/execution/frames-inl.h" #include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h" #include "src/execution/isolate-inl.h"
#include "src/execution/isolate.h"
#include "src/execution/protectors-inl.h" #include "src/execution/protectors-inl.h"
#include "src/execution/tiering-manager.h" #include "src/execution/tiering-manager.h"
#include "src/handles/handles-inl.h" #include "src/handles/handles-inl.h"
...@@ -27,19 +26,13 @@ ...@@ -27,19 +26,13 @@
#include "src/ic/stub-cache.h" #include "src/ic/stub-cache.h"
#include "src/numbers/conversions.h" #include "src/numbers/conversions.h"
#include "src/objects/api-callbacks.h" #include "src/objects/api-callbacks.h"
#include "src/objects/data-handler-inl.h"
#include "src/objects/field-type.h" #include "src/objects/field-type.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/heap-number-inl.h"
#include "src/objects/instance-type.h" #include "src/objects/instance-type.h"
#include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h" #include "src/objects/js-array-inl.h"
#include "src/objects/megadom-handler.h" #include "src/objects/megadom-handler.h"
#include "src/objects/module-inl.h"
#include "src/objects/property-descriptor.h" #include "src/objects/property-descriptor.h"
#include "src/objects/prototype.h" #include "src/objects/prototype.h"
#include "src/objects/struct-inl.h"
#include "src/runtime/runtime-utils.h"
#include "src/runtime/runtime.h" #include "src/runtime/runtime.h"
#include "src/tracing/trace-event.h" #include "src/tracing/trace-event.h"
#include "src/tracing/tracing-category-observer.h" #include "src/tracing/tracing-category-observer.h"
...@@ -211,6 +204,7 @@ static void LookupForRead(LookupIterator* it, bool is_has_property) { ...@@ -211,6 +204,7 @@ static void LookupForRead(LookupIterator* it, bool is_has_property) {
case LookupIterator::TRANSITION: case LookupIterator::TRANSITION:
UNREACHABLE(); UNREACHABLE();
case LookupIterator::JSPROXY: case LookupIterator::JSPROXY:
case LookupIterator::WASM_OBJECT:
return; return;
case LookupIterator::INTERCEPTOR: { case LookupIterator::INTERCEPTOR: {
// If there is a getter, return; otherwise loop to perform the lookup. // If there is a getter, return; otherwise loop to perform the lookup.
...@@ -870,68 +864,6 @@ void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name, ...@@ -870,68 +864,6 @@ void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
} }
} }
namespace {
#if V8_ENABLE_WEBASSEMBLY
inline WasmValueType GetWasmValueType(wasm::ValueType type) {
#define TYPE_CASE(Name) \
case wasm::k##Name: \
return WasmValueType::k##Name;
switch (type.kind()) {
TYPE_CASE(I8)
TYPE_CASE(I16)
TYPE_CASE(I32)
TYPE_CASE(I64)
TYPE_CASE(F32)
TYPE_CASE(F64)
TYPE_CASE(S128)
TYPE_CASE(Ref)
TYPE_CASE(RefNull)
case wasm::kRtt:
// Rtt values are not supposed to be made available to JavaScript side.
UNREACHABLE();
case wasm::kVoid:
case wasm::kBottom:
UNREACHABLE();
}
#undef TYPE_CASE
}
Handle<Smi> MakeLoadWasmStructFieldHandler(Isolate* isolate,
Handle<JSReceiver> holder,
LookupIterator* lookup) {
DCHECK(holder->IsWasmObject(isolate));
WasmValueType type;
int field_offset;
if (holder->IsWasmArray(isolate)) {
// The only named property that WasmArray has is length.
DCHECK_EQ(0, lookup->property_details().field_index());
DCHECK_EQ(*isolate->factory()->length_string(), *lookup->name());
type = WasmValueType::kU32;
field_offset = WasmArray::kLengthOffset;
} else {
wasm::StructType* struct_type = Handle<WasmStruct>::cast(holder)->type();
int field_index = lookup->property_details().field_index();
type = GetWasmValueType(struct_type->field(field_index));
field_offset =
WasmStruct::kHeaderSize + struct_type->field_offset(field_index);
const size_t kMaxWasmFieldOffset =
WasmStruct::kHeaderSize + wasm::StructType::kMaxFieldOffset;
static_assert(kMaxWasmFieldOffset <= LoadHandler::WasmFieldOffsetBits::kMax,
"Bigger numbers of struct fields require different approach");
}
return LoadHandler::LoadWasmStructField(isolate, type, field_offset);
}
#endif // V8_ENABLE_WEBASSEMBLY
} // namespace
MaybeObjectHandle LoadIC::ComputeHandler(LookupIterator* lookup) { MaybeObjectHandle LoadIC::ComputeHandler(LookupIterator* lookup) {
Handle<Object> receiver = lookup->GetReceiver(); Handle<Object> receiver = lookup->GetReceiver();
ReadOnlyRoots roots(isolate()); ReadOnlyRoots roots(isolate());
...@@ -1155,30 +1087,14 @@ MaybeObjectHandle LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1155,30 +1087,14 @@ MaybeObjectHandle LoadIC::ComputeHandler(LookupIterator* lookup) {
return MaybeObjectHandle(smi_handler); return MaybeObjectHandle(smi_handler);
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
} else if (lookup->IsElement(*holder)) { } else if (lookup->IsElement(*holder)) {
#if V8_ENABLE_WEBASSEMBLY
if (holder_is_lookup_start_object && holder->IsWasmStruct()) {
// TODO(ishell): Consider supporting indexed access to WasmStruct
// fields.
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
return MaybeObjectHandle(LoadHandler::LoadNonExistent(isolate()));
}
#endif // V8_ENABLE_WEBASSEMBLY
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return MaybeObjectHandle(LoadHandler::LoadSlow(isolate())); return MaybeObjectHandle(LoadHandler::LoadSlow(isolate()));
} else { } else {
DCHECK_EQ(PropertyLocation::kField, DCHECK_EQ(PropertyLocation::kField,
lookup->property_details().location()); lookup->property_details().location());
#if V8_ENABLE_WEBASSEMBLY
if (V8_UNLIKELY(holder->IsWasmObject(isolate()))) {
smi_handler =
MakeLoadWasmStructFieldHandler(isolate(), holder, lookup);
} else // NOLINT(readability/braces)
#endif // V8_ENABLE_WEBASSEMBLY
{
DCHECK(holder->IsJSObject(isolate())); DCHECK(holder->IsJSObject(isolate()));
FieldIndex field = lookup->GetFieldIndex(); FieldIndex field = lookup->GetFieldIndex();
smi_handler = LoadHandler::LoadField(isolate(), field); smi_handler = LoadHandler::LoadField(isolate(), field);
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
if (holder_is_lookup_start_object) if (holder_is_lookup_start_object)
return MaybeObjectHandle(smi_handler); return MaybeObjectHandle(smi_handler);
...@@ -1227,6 +1143,9 @@ MaybeObjectHandle LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1227,6 +1143,9 @@ MaybeObjectHandle LoadIC::ComputeHandler(LookupIterator* lookup) {
return MaybeObjectHandle(LoadHandler::LoadFromPrototype( return MaybeObjectHandle(LoadHandler::LoadFromPrototype(
isolate(), map, holder_proxy, smi_handler)); isolate(), map, holder_proxy, smi_handler));
} }
case LookupIterator::WASM_OBJECT:
return MaybeObjectHandle(LoadHandler::LoadSlow(isolate()));
case LookupIterator::ACCESS_CHECK: case LookupIterator::ACCESS_CHECK:
case LookupIterator::NOT_FOUND: case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION: case LookupIterator::TRANSITION:
...@@ -1618,6 +1537,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value, ...@@ -1618,6 +1537,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
switch (it->state()) { switch (it->state()) {
case LookupIterator::NOT_FOUND: case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION: case LookupIterator::TRANSITION:
case LookupIterator::WASM_OBJECT:
UNREACHABLE(); UNREACHABLE();
case LookupIterator::JSPROXY: case LookupIterator::JSPROXY:
return true; return true;
...@@ -1773,11 +1693,15 @@ Maybe<bool> DefineOwnDataProperty(LookupIterator* it, ...@@ -1773,11 +1693,15 @@ Maybe<bool> DefineOwnDataProperty(LookupIterator* it,
return JSProxy::DefineOwnProperty(it->isolate(), it->GetHolder<JSProxy>(), return JSProxy::DefineOwnProperty(it->isolate(), it->GetHolder<JSProxy>(),
it->GetName(), &new_desc, should_throw); it->GetName(), &new_desc, should_throw);
} }
case LookupIterator::WASM_OBJECT:
RETURN_FAILURE(it->isolate(), kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
// When lazy feedback is disabled, the original state could be different // When lazy feedback is disabled, the original state could be different
// while the object is already prepared for TRANSITION. // while the object is already prepared for TRANSITION.
case LookupIterator::TRANSITION: { case LookupIterator::TRANSITION: {
switch (original_state) { switch (original_state) {
case LookupIterator::JSPROXY: case LookupIterator::JSPROXY:
case LookupIterator::WASM_OBJECT:
case LookupIterator::TRANSITION: case LookupIterator::TRANSITION:
case LookupIterator::DATA: case LookupIterator::DATA:
case LookupIterator::INTERCEPTOR: case LookupIterator::INTERCEPTOR:
...@@ -2200,6 +2124,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) { ...@@ -2200,6 +2124,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
case LookupIterator::INTEGER_INDEXED_EXOTIC: case LookupIterator::INTEGER_INDEXED_EXOTIC:
case LookupIterator::ACCESS_CHECK: case LookupIterator::ACCESS_CHECK:
case LookupIterator::NOT_FOUND: case LookupIterator::NOT_FOUND:
case LookupIterator::WASM_OBJECT:
UNREACHABLE(); UNREACHABLE();
} }
return MaybeObjectHandle(); return MaybeObjectHandle();
...@@ -2550,6 +2475,12 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object, ...@@ -2550,6 +2475,12 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
set_slow_stub_reason("map in array prototype"); set_slow_stub_reason("map in array prototype");
use_ic = false; use_ic = false;
} }
#if V8_ENABLE_WEBASSEMBLY
if (heap_object->map().IsWasmObjectMap()) {
set_slow_stub_reason("wasm object");
use_ic = false;
}
#endif
} }
Handle<Map> old_receiver_map; Handle<Map> old_receiver_map;
......
...@@ -97,6 +97,8 @@ Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) { ...@@ -97,6 +97,8 @@ Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
case LookupIterator::JSPROXY: case LookupIterator::JSPROXY:
return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(), return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
it->GetName()); it->GetName());
case LookupIterator::WASM_OBJECT:
return Just(false);
case LookupIterator::INTERCEPTOR: { case LookupIterator::INTERCEPTOR: {
Maybe<PropertyAttributes> result = Maybe<PropertyAttributes> result =
JSObject::GetPropertyAttributesWithInterceptor(it); JSObject::GetPropertyAttributesWithInterceptor(it);
...@@ -150,6 +152,7 @@ Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it, ...@@ -150,6 +152,7 @@ Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it,
case LookupIterator::INTERCEPTOR: case LookupIterator::INTERCEPTOR:
case LookupIterator::NOT_FOUND: case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION: case LookupIterator::TRANSITION:
case LookupIterator::WASM_OBJECT:
UNREACHABLE(); UNREACHABLE();
case LookupIterator::ACCESS_CHECK: case LookupIterator::ACCESS_CHECK:
// Support calling this method without an active context, but refuse // Support calling this method without an active context, but refuse
...@@ -223,6 +226,9 @@ Maybe<bool> JSReceiver::CheckPrivateNameStore(LookupIterator* it, ...@@ -223,6 +226,9 @@ Maybe<bool> JSReceiver::CheckPrivateNameStore(LookupIterator* it,
NewTypeError(message, name_string, it->GetReceiver())); NewTypeError(message, name_string, it->GetReceiver()));
} }
return Just(true); return Just(true);
case LookupIterator::WASM_OBJECT:
RETURN_FAILURE(isolate, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
} }
} }
DCHECK(!it->IsFound()); DCHECK(!it->IsFound());
...@@ -734,6 +740,8 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes( ...@@ -734,6 +740,8 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
UNREACHABLE(); UNREACHABLE();
case LookupIterator::JSPROXY: case LookupIterator::JSPROXY:
return JSProxy::GetPropertyAttributes(it); return JSProxy::GetPropertyAttributes(it);
case LookupIterator::WASM_OBJECT:
return Just(ABSENT);
case LookupIterator::INTERCEPTOR: { case LookupIterator::INTERCEPTOR: {
Maybe<PropertyAttributes> result = Maybe<PropertyAttributes> result =
JSObject::GetPropertyAttributesWithInterceptor(it); JSObject::GetPropertyAttributesWithInterceptor(it);
...@@ -948,7 +956,6 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it, ...@@ -948,7 +956,6 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
} }
return Just(true); return Just(true);
} }
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
for (; it->IsFound(); it->Next()) { for (; it->IsFound(); it->Next()) {
switch (it->state()) { switch (it->state()) {
...@@ -956,6 +963,9 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it, ...@@ -956,6 +963,9 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
case LookupIterator::NOT_FOUND: case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION: case LookupIterator::TRANSITION:
UNREACHABLE(); UNREACHABLE();
case LookupIterator::WASM_OBJECT:
RETURN_FAILURE(isolate, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
case LookupIterator::ACCESS_CHECK: case LookupIterator::ACCESS_CHECK:
if (it->HasAccess()) break; if (it->HasAccess()) break;
isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
...@@ -986,7 +996,7 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it, ...@@ -986,7 +996,7 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
if (is_strict(language_mode)) { if (is_strict(language_mode)) {
isolate->Throw(*isolate->factory()->NewTypeError( isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kStrictDeleteProperty, it->GetName(), MessageTemplate::kStrictDeleteProperty, it->GetName(),
receiver)); it->GetReceiver()));
return Nothing<bool>(); return Nothing<bool>();
} }
return Just(false); return Just(false);
...@@ -1158,6 +1168,12 @@ Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate, ...@@ -1158,6 +1168,12 @@ Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
isolate, Handle<JSModuleNamespace>::cast(object), key, desc, isolate, Handle<JSModuleNamespace>::cast(object), key, desc,
should_throw); should_throw);
} }
#if V8_ENABLE_WEBASSEMBLY
if (object->IsWasmObject()) {
RETURN_FAILURE(isolate, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
}
#endif
// OrdinaryDefineOwnProperty, by virtue of calling // OrdinaryDefineOwnProperty, by virtue of calling
// DefineOwnPropertyIgnoreAttributes, can handle arguments // DefineOwnPropertyIgnoreAttributes, can handle arguments
...@@ -1745,6 +1761,9 @@ Maybe<bool> JSReceiver::AddPrivateField(LookupIterator* it, ...@@ -1745,6 +1761,9 @@ Maybe<bool> JSReceiver::AddPrivateField(LookupIterator* it,
return JSProxy::SetPrivateSymbol(isolate, Handle<JSProxy>::cast(receiver), return JSProxy::SetPrivateSymbol(isolate, Handle<JSProxy>::cast(receiver),
symbol, &new_desc, should_throw); symbol, &new_desc, should_throw);
} }
case LookupIterator::WASM_OBJECT:
RETURN_FAILURE(isolate, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
case LookupIterator::DATA: case LookupIterator::DATA:
case LookupIterator::INTERCEPTOR: case LookupIterator::INTERCEPTOR:
case LookupIterator::ACCESSOR: case LookupIterator::ACCESSOR:
...@@ -2033,6 +2052,12 @@ Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object, ...@@ -2033,6 +2052,12 @@ Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object), return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
should_throw); should_throw);
} }
#if V8_ENABLE_WEBASSEMBLY
if (object->IsWasmObject()) {
RETURN_FAILURE(object->GetIsolate(), kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
}
#endif
DCHECK(object->IsJSObject()); DCHECK(object->IsJSObject());
return JSObject::PreventExtensions(Handle<JSObject>::cast(object), return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
should_throw); should_throw);
...@@ -2042,6 +2067,11 @@ Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) { ...@@ -2042,6 +2067,11 @@ Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
if (object->IsJSProxy()) { if (object->IsJSProxy()) {
return JSProxy::IsExtensible(Handle<JSProxy>::cast(object)); return JSProxy::IsExtensible(Handle<JSProxy>::cast(object));
} }
#if V8_ENABLE_WEBASSEMBLY
if (object->IsWasmObject()) {
return Just(false);
}
#endif
return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object))); return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object)));
} }
...@@ -3561,6 +3591,7 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( ...@@ -3561,6 +3591,7 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
for (; it->IsFound(); it->Next()) { for (; it->IsFound(); it->Next()) {
switch (it->state()) { switch (it->state()) {
case LookupIterator::JSPROXY: case LookupIterator::JSPROXY:
case LookupIterator::WASM_OBJECT:
case LookupIterator::TRANSITION: case LookupIterator::TRANSITION:
case LookupIterator::NOT_FOUND: case LookupIterator::NOT_FOUND:
UNREACHABLE(); UNREACHABLE();
......
...@@ -253,6 +253,16 @@ Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver, ...@@ -253,6 +253,16 @@ Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
Maybe<bool> result = Just(false); // Dummy initialization. Maybe<bool> result = Just(false); // Dummy initialization.
if (current->IsJSProxy()) { if (current->IsJSProxy()) {
result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current)); result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current));
#if V8_ENABLE_WEBASSEMBLY
} else if (current->IsWasmObject()) {
if (mode_ == KeyCollectionMode::kIncludePrototypes) {
RETURN_FAILURE(isolate_, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
} else {
DCHECK_EQ(KeyCollectionMode::kOwnOnly, mode_);
DCHECK_EQ(result, Just(false)); // Stop iterating.
}
#endif
} else { } else {
DCHECK(current->IsJSObject()); DCHECK(current->IsJSObject());
result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current)); result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current));
......
...@@ -22,10 +22,6 @@ ...@@ -22,10 +22,6 @@
#include "src/objects/property-details.h" #include "src/objects/property-details.h"
#include "src/objects/struct-inl.h" #include "src/objects/struct-inl.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/wasm-objects-inl.h"
#endif // V8_ENABLE_WEBASSEMBLY
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -874,18 +870,10 @@ bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const { ...@@ -874,18 +870,10 @@ bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
Handle<Object> LookupIterator::FetchValue( Handle<Object> LookupIterator::FetchValue(
AllocationPolicy allocation_policy) const { AllocationPolicy allocation_policy) const {
Object result; Object result;
if (IsElement(*holder_)) {
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
if (V8_UNLIKELY(holder_->IsWasmObject(isolate_))) { DCHECK(!holder_->IsWasmObject());
if (holder_->IsWasmStruct()) { #endif
// WasmStructs don't have elements. if (IsElement(*holder_)) {
return isolate_->factory()->undefined_value();
}
Handle<WasmArray> holder = GetHolder<WasmArray>();
return WasmArray::GetElement(isolate_, holder, number_.as_uint32());
}
#endif // V8_ENABLE_WEBASSEMBLY
DCHECK(holder_->IsJSObject(isolate_));
Handle<JSObject> holder = GetHolder<JSObject>(); Handle<JSObject> holder = GetHolder<JSObject>();
ElementsAccessor* accessor = holder->GetElementsAccessor(isolate_); ElementsAccessor* accessor = holder->GetElementsAccessor(isolate_);
return accessor->Get(isolate_, holder, number_); return accessor->Get(isolate_, holder, number_);
...@@ -903,27 +891,6 @@ Handle<Object> LookupIterator::FetchValue( ...@@ -903,27 +891,6 @@ Handle<Object> LookupIterator::FetchValue(
} }
} else if (property_details_.location() == PropertyLocation::kField) { } else if (property_details_.location() == PropertyLocation::kField) {
DCHECK_EQ(PropertyKind::kData, property_details_.kind()); DCHECK_EQ(PropertyKind::kData, property_details_.kind());
#if V8_ENABLE_WEBASSEMBLY
if (V8_UNLIKELY(holder_->IsWasmObject(isolate_))) {
if (allocation_policy == AllocationPolicy::kAllocationDisallowed) {
// TODO(ishell): consider taking field type into account and relaxing
// this a bit.
return isolate_->factory()->undefined_value();
}
if (holder_->IsWasmArray(isolate_)) {
// WasmArrays don't have other named properties besides "length".
DCHECK_EQ(*name_, ReadOnlyRoots(isolate_).length_string());
Handle<WasmArray> holder = GetHolder<WasmArray>();
uint32_t length = holder->length();
return isolate_->factory()->NewNumberFromUint(length);
}
Handle<WasmStruct> holder = GetHolder<WasmStruct>();
return WasmStruct::GetField(isolate_, holder,
property_details_.field_index());
}
#endif // V8_ENABLE_WEBASSEMBLY
DCHECK(holder_->IsJSObject(isolate_));
Handle<JSObject> holder = GetHolder<JSObject>(); Handle<JSObject> holder = GetHolder<JSObject>();
FieldIndex field_index = FieldIndex field_index =
FieldIndex::ForDescriptor(holder->map(isolate_), descriptor_number()); FieldIndex::ForDescriptor(holder->map(isolate_), descriptor_number());
...@@ -1179,42 +1146,6 @@ Handle<Object> LookupIterator::SwapDataValue(Handle<Object> value, ...@@ -1179,42 +1146,6 @@ Handle<Object> LookupIterator::SwapDataValue(Handle<Object> value,
return accessor->SwapAtomic(isolate_, holder, number_, *value, kSeqCstAccess); return accessor->SwapAtomic(isolate_, holder, number_, *value, kSeqCstAccess);
} }
#if V8_ENABLE_WEBASSEMBLY
wasm::ValueType LookupIterator::wasm_value_type() const {
DCHECK(has_property_);
DCHECK(holder_->IsWasmObject(isolate_));
if (holder_->IsWasmStruct(isolate_)) {
wasm::StructType* wasm_struct_type = WasmStruct::cast(*holder_).type();
return wasm_struct_type->field(property_details_.field_index());
} else {
DCHECK(holder_->IsWasmArray(isolate_));
wasm::ArrayType* wasm_array_type = WasmArray::cast(*holder_).type();
return wasm_array_type->element_type();
}
}
void LookupIterator::WriteDataValueToWasmObject(Handle<Object> value) {
DCHECK_EQ(DATA, state_);
DCHECK(holder_->IsWasmObject(isolate_));
Handle<JSReceiver> holder = GetHolder<JSReceiver>();
if (IsElement(*holder)) {
// TODO(ishell): consider supporting indexed access to WasmStruct fields.
// TODO(v8:11804): implement stores to WasmArrays.
UNIMPLEMENTED();
} else {
// WasmArrays don't have writable properties.
DCHECK(holder->IsWasmStruct());
Handle<WasmStruct> wasm_holder = GetHolder<WasmStruct>();
WasmStruct::SetField(isolate_, wasm_holder, property_details_.field_index(),
value);
}
}
#endif // V8_ENABLE_WEBASSEMBLY
template <bool is_element> template <bool is_element>
bool LookupIterator::SkipInterceptor(JSObject holder) { bool LookupIterator::SkipInterceptor(JSObject holder) {
InterceptorInfo info = GetInterceptor<is_element>(holder); InterceptorInfo info = GetInterceptor<is_element>(holder);
...@@ -1284,9 +1215,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder( ...@@ -1284,9 +1215,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder(
if (is_element || !name_->IsPrivate(isolate_)) return JSPROXY; if (is_element || !name_->IsPrivate(isolate_)) return JSPROXY;
} }
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
if (map.IsWasmObjectMap()) { if (map.IsWasmObjectMap()) return WASM_OBJECT;
return LookupInRegularHolder<is_element>(map, holder);
}
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
if (map.is_access_check_needed()) { if (map.is_access_check_needed()) {
if (is_element || !name_->IsPrivate(isolate_) || if (is_element || !name_->IsPrivate(isolate_) ||
...@@ -1325,6 +1254,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder( ...@@ -1325,6 +1254,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder(
return NOT_FOUND; return NOT_FOUND;
case INTEGER_INDEXED_EXOTIC: case INTEGER_INDEXED_EXOTIC:
case JSPROXY: case JSPROXY:
case WASM_OBJECT:
case TRANSITION: case TRANSITION:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -1338,33 +1268,15 @@ LookupIterator::State LookupIterator::LookupInRegularHolder( ...@@ -1338,33 +1268,15 @@ LookupIterator::State LookupIterator::LookupInRegularHolder(
if (interceptor_state_ == InterceptorState::kProcessNonMasking) { if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
return NOT_FOUND; return NOT_FOUND;
} }
if (is_element && IsElement(holder)) {
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
if (V8_UNLIKELY(holder.IsWasmObject(isolate_))) { DCHECK(!holder.IsWasmObject(isolate_));
// TODO(ishell): consider supporting indexed access to WasmStruct fields. #endif
if (holder.IsWasmArray(isolate_)) { if (is_element && IsElement(holder)) {
WasmArray wasm_array = WasmArray::cast(holder);
number_ = index_ < wasm_array.length() ? InternalIndex(index_)
: InternalIndex::NotFound();
wasm::ArrayType* wasm_array_type = wasm_array.type();
property_details_ =
PropertyDetails(PropertyKind::kData,
wasm_array_type->mutability() ? SEALED : FROZEN,
PropertyCellType::kNoCell);
} else {
DCHECK(holder.IsWasmStruct(isolate_));
DCHECK(number_.is_not_found());
}
} else // NOLINT(readability/braces)
#endif // V8_ENABLE_WEBASSEMBLY
{
JSObject js_object = JSObject::cast(holder); JSObject js_object = JSObject::cast(holder);
ElementsAccessor* accessor = js_object.GetElementsAccessor(isolate_); ElementsAccessor* accessor = js_object.GetElementsAccessor(isolate_);
FixedArrayBase backing_store = js_object.elements(isolate_); FixedArrayBase backing_store = js_object.elements(isolate_);
number_ = accessor->GetEntryForIndex(isolate_, js_object, backing_store, number_ =
index_); accessor->GetEntryForIndex(isolate_, js_object, backing_store, index_);
if (number_.is_not_found()) { if (number_.is_not_found()) {
return holder.IsJSTypedArray(isolate_) ? INTEGER_INDEXED_EXOTIC return holder.IsJSTypedArray(isolate_) ? INTEGER_INDEXED_EXOTIC
: NOT_FOUND; : NOT_FOUND;
...@@ -1375,7 +1287,6 @@ LookupIterator::State LookupIterator::LookupInRegularHolder( ...@@ -1375,7 +1287,6 @@ LookupIterator::State LookupIterator::LookupInRegularHolder(
} else if (map.has_sealed_elements()) { } else if (map.has_sealed_elements()) {
property_details_ = property_details_.CopyAddAttributes(SEALED); property_details_ = property_details_.CopyAddAttributes(SEALED);
} }
}
} else if (!map.is_dictionary_map()) { } else if (!map.is_dictionary_map()) {
DescriptorArray descriptors = map.instance_descriptors(isolate_); DescriptorArray descriptors = map.instance_descriptors(isolate_);
number_ = descriptors.SearchWithCache(isolate_, *name_, map); number_ = descriptors.SearchWithCache(isolate_, *name_, map);
......
...@@ -60,6 +60,7 @@ class V8_EXPORT_PRIVATE LookupIterator final { ...@@ -60,6 +60,7 @@ class V8_EXPORT_PRIVATE LookupIterator final {
INTEGER_INDEXED_EXOTIC, INTEGER_INDEXED_EXOTIC,
INTERCEPTOR, INTERCEPTOR,
JSPROXY, JSPROXY,
WASM_OBJECT,
NOT_FOUND, NOT_FOUND,
ACCESSOR, ACCESSOR,
DATA, DATA,
...@@ -197,13 +198,6 @@ class V8_EXPORT_PRIVATE LookupIterator final { ...@@ -197,13 +198,6 @@ class V8_EXPORT_PRIVATE LookupIterator final {
static inline void UpdateProtector(Isolate* isolate, Handle<Object> receiver, static inline void UpdateProtector(Isolate* isolate, Handle<Object> receiver,
Handle<Name> name); Handle<Name> name);
#if V8_ENABLE_WEBASSEMBLY
// Fetches type of WasmStruct's field or WasmArray's elements, it
// is used for preparing the value for storing into WasmObjects.
wasm::ValueType wasm_value_type() const;
void WriteDataValueToWasmObject(Handle<Object> value);
#endif // V8_ENABLE_WEBASSEMBLY
// Lookup a 'cached' private property for an accessor. // Lookup a 'cached' private property for an accessor.
// If not found returns false and leaves the LookupIterator unmodified. // If not found returns false and leaves the LookupIterator unmodified.
bool TryLookupCachedProperty(Handle<AccessorPair> accessor); bool TryLookupCachedProperty(Handle<AccessorPair> accessor);
......
...@@ -1167,6 +1167,10 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it, ...@@ -1167,6 +1167,10 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
if (!was_found && !is_global_reference) it->NotFound(); if (!was_found && !is_global_reference) it->NotFound();
return result; return result;
} }
case LookupIterator::WASM_OBJECT:
THROW_NEW_ERROR(it->isolate(),
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque),
Object);
case LookupIterator::INTERCEPTOR: { case LookupIterator::INTERCEPTOR: {
bool done; bool done;
Handle<Object> result; Handle<Object> result;
...@@ -2505,6 +2509,10 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it, ...@@ -2505,6 +2509,10 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
value, receiver, should_throw); value, receiver, should_throw);
} }
case LookupIterator::WASM_OBJECT:
RETURN_FAILURE(it->isolate(), kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
case LookupIterator::INTERCEPTOR: { case LookupIterator::INTERCEPTOR: {
if (it->HolderIsReceiverOrHiddenPrototype()) { if (it->HolderIsReceiverOrHiddenPrototype()) {
Maybe<bool> result = Maybe<bool> result =
...@@ -2722,6 +2730,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, ...@@ -2722,6 +2730,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
case LookupIterator::NOT_FOUND: case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION: case LookupIterator::TRANSITION:
case LookupIterator::WASM_OBJECT:
UNREACHABLE(); UNREACHABLE();
} }
} }
...@@ -2812,24 +2821,10 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { ...@@ -2812,24 +2821,10 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
} }
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
if (receiver->IsWasmObject(isolate)) { DCHECK(!receiver->IsWasmObject(isolate));
// Prepares given value for being stored into a field of given Wasm type
// or throw if the value can't be stored into the field.
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, to_assign,
WasmObject::ToWasmValue(isolate, it->wasm_value_type(), to_assign),
Nothing<bool>());
// Store prepared value.
it->WriteDataValueToWasmObject(to_assign);
} else // NOLINT(readability/braces)
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
// clang-format off
if (V8_UNLIKELY(receiver->IsJSSharedStruct(isolate) || if (V8_UNLIKELY(receiver->IsJSSharedStruct(isolate) ||
receiver->IsJSSharedArray(isolate))) { receiver->IsJSSharedArray(isolate))) {
// clang-format on
// Shared structs can only point to primitives or shared values. // Shared structs can only point to primitives or shared values.
ASSIGN_RETURN_ON_EXCEPTION_VALUE( ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, to_assign, Object::Share(isolate, to_assign, kThrowOnError), isolate, to_assign, Object::Share(isolate, to_assign, kThrowOnError),
......
...@@ -77,6 +77,10 @@ MaybeHandle<Object> HasEnumerableProperty(Isolate* isolate, ...@@ -77,6 +77,10 @@ MaybeHandle<Object> HasEnumerableProperty(Isolate* isolate,
return it.GetName(); return it.GetName();
} }
} }
case LookupIterator::WASM_OBJECT:
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque),
Object);
case LookupIterator::INTERCEPTOR: { case LookupIterator::INTERCEPTOR: {
result = JSObject::GetPropertyAttributesWithInterceptor(&it); result = JSObject::GetPropertyAttributesWithInterceptor(&it);
if (result.IsNothing()) return MaybeHandle<Object>(); if (result.IsNothing()) return MaybeHandle<Object>();
......
...@@ -987,6 +987,7 @@ MaybeHandle<Object> InstanceBuilder::LookupImportAsm( ...@@ -987,6 +987,7 @@ MaybeHandle<Object> InstanceBuilder::LookupImportAsm(
case LookupIterator::INTEGER_INDEXED_EXOTIC: case LookupIterator::INTEGER_INDEXED_EXOTIC:
case LookupIterator::INTERCEPTOR: case LookupIterator::INTERCEPTOR:
case LookupIterator::JSPROXY: case LookupIterator::JSPROXY:
case LookupIterator::WASM_OBJECT:
case LookupIterator::ACCESSOR: case LookupIterator::ACCESSOR:
case LookupIterator::TRANSITION: case LookupIterator::TRANSITION:
return ReportLinkError("not a data property", index, import_name); return ReportLinkError("not a data property", index, import_name);
......
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --experimental-wasm-gc --wasm-gc-js-interop --allow-natives-syntax
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
function MakeInstance() {
let builder = new WasmModuleBuilder();
let struct_type = builder.addStruct([makeField(kWasmI32, true)]);
let array_type = builder.addArray(kWasmI32, true);
builder.addFunction('MakeStruct', makeSig([], [kWasmExternRef]))
.exportFunc()
.addBody([
kExprI32Const, 42, // --
kGCPrefix, kExprStructNew, struct_type, // --
kGCPrefix, kExprExternExternalize // --
]);
builder.addFunction('MakeArray', makeSig([], [kWasmExternRef]))
.exportFunc()
.addBody([
kExprI32Const, 2, // length
kGCPrefix, kExprArrayNewDefault, array_type, // --
kGCPrefix, kExprExternExternalize // --
]);
return builder.instantiate();
}
let instance = MakeInstance();
let struct = instance.exports.MakeStruct();
let array = instance.exports.MakeArray();
function testThrowsRepeated(fn) {
%PrepareFunctionForOptimization(fn);
for (let i = 0; i < 5; i++) assertThrows(fn, TypeError);
%OptimizeFunctionOnNextCall(fn);
assertThrows(fn, TypeError);
}
// TODO: test repeated execution of functions using ICs, including optimized.
for (let wasm_obj of [struct, array]) {
testThrowsRepeated(() => wasm_obj.foo);
testThrowsRepeated(() => { wasm_obj.foo = 42; });
testThrowsRepeated(() => wasm_obj[0]);
testThrowsRepeated(() => { wasm_obj[0] = undefined; });
assertThrows(() => wasm_obj.__proto__, TypeError);
assertThrows(() => Object.prototype.__proto__.call(wasm_obj), TypeError);
assertThrows(() => wasm_obj.__proto__ = null, TypeError);
assertThrows(() => JSON.stringify(wasm_obj), TypeError);
assertThrows(() => { for (let p in wasm_obj) { } }, TypeError);
assertThrows(() => { for (let p of wasm_obj) { } }, TypeError);
assertThrows(() => wasm_obj.toString(), TypeError);
assertThrows(() => wasm_obj.valueOf(), TypeError);
assertThrows(() => "" + wasm_obj, TypeError);
assertThrows(() => 0 + wasm_obj, TypeError);
assertThrows(() => { delete wasm_obj.foo; }, TypeError);
assertThrows(() => Object.freeze(wasm_obj), TypeError);
assertThrows(() => Object.seal(wasm_obj), TypeError);
assertThrows(
() => Object.prototype.__lookupGetter__.call(wasm_obj, 'foo'), TypeError);
assertThrows(
() => Object.prototype.__lookupSetter__.call(wasm_obj, 'foo'), TypeError);
assertThrows(
() => Object.prototype.__defineGetter__.call(wasm_obj, 'foo', () => 42),
TypeError);
assertThrows(
() => Object.prototype.__defineSetter__.call(wasm_obj, 'foo', () => {}),
TypeError);
assertThrows(
() => Object.defineProperty(wasm_obj, 'foo', {value: 42}), TypeError);
assertEquals([], Object.getOwnPropertyNames(wasm_obj));
assertEquals([], Object.getOwnPropertySymbols(wasm_obj));
assertEquals({}, Object.getOwnPropertyDescriptors(wasm_obj));
assertEquals([], Object.keys(wasm_obj));
assertEquals([], Object.entries(wasm_obj));
assertEquals(undefined, Object.getOwnPropertyDescriptor(wasm_obj, "foo"));
assertEquals(false, "foo" in wasm_obj);
assertEquals(false, Object.prototype.hasOwnProperty.call(wasm_obj, "foo"));
assertEquals(true, Object.isSealed(wasm_obj));
assertEquals(true, Object.isFrozen(wasm_obj));
assertEquals(false, Object.isExtensible(wasm_obj));
assertEquals("object", typeof wasm_obj);
assertEquals("[object Object]", Object.prototype.toString.call(wasm_obj));
{
let js_obj = {};
js_obj.foo = wasm_obj;
assertEquals(wasm_obj, js_obj.foo);
js_obj[0] = wasm_obj;
assertEquals(wasm_obj, js_obj[0]);
}
assertEquals(42, wasm_obj ? 42 : 0);
assertFalse(Array.isArray(wasm_obj));
}
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --experimental-wasm-gc --wasm-gc-js-interop
// Flags: --expose-gc
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
const kIterationsCountForICProgression = 20;
function createArray_i() {
let builder = new WasmModuleBuilder();
const type_index = builder.addArray(kWasmI32, true);
let sig_a_i = makeSig_r_x(kWasmDataRef, kWasmI32);
let sig_i_ai = makeSig([kWasmDataRef, kWasmI32], [kWasmI32]);
let sig_v_aii = makeSig([kWasmDataRef, kWasmI32, kWasmI32], []);
builder.addFunction("new_array", sig_a_i)
.addBody([
kExprLocalGet, 0, // --
kExprI32Const, 10, // --
kGCPrefix, kExprArrayNew, type_index]) // --
.exportAs("new_array");
builder.addFunction("array_get", sig_i_ai)
.addBody([
kExprLocalGet, 0, // --
kGCPrefix, kExprRefCast, type_index, // --
kExprLocalGet, 1, // --
kGCPrefix, kExprArrayGet, type_index]) // --
.exportAs("array_get");
builder.addFunction("array_set", sig_v_aii)
.addBody([
kExprLocalGet, 0, // --
kGCPrefix, kExprRefCast, type_index, // --
kExprLocalGet, 1, // --
kExprLocalGet, 2, // --
kGCPrefix, kExprArraySet, type_index]) // --
.exportAs("array_set");
let instance = builder.instantiate();
let new_array = instance.exports.new_array;
let array_get = instance.exports.array_get;
let array_set = instance.exports.array_set;
let value = 42;
let o = new_array(value);
%DebugPrint(o);
assertEquals(10, o.length);
for (let i = 0; i < o.length; i++) {
let res;
res = array_get(o, i);
assertEquals(value, res);
array_set(o, i, i);
res = array_get(o, i);
assertEquals(i, res);
}
return o;
}
(function TestSimpleArrayInterop() {
function f(o) {
assertEquals(10, o.length);
for (let i = 0; i < o.length; i++) {
let len = o.length;
assertEquals(10, len);
let v = o[i];
assertEquals(i, v);
}
}
let o = createArray_i();
%DebugPrint(o);
f(o);
gc();
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment