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 @@
#include "src/builtins/builtins-utils-inl.h"
#include "src/builtins/builtins.h"
#include "src/codegen/code-factory.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/logging/counters.h"
#include "src/objects/keys.h"
#include "src/objects/lookup.h"
#include "src/objects/objects-inl.h"
......@@ -150,6 +149,10 @@ Object ObjectLookupAccessor(Isolate* isolate, Handle<Object> object,
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::DATA:
return ReadOnlyRoots(isolate).undefined_value();
......
......@@ -658,6 +658,7 @@ namespace internal {
T(WasmTrapStringIsolatedSurrogate, \
"Failed to encode string as UTF-8: contains unpaired surrogate") \
T(WasmExceptionError, "wasm exception") \
T(WasmObjectsAreOpaque, "WebAssembly objects are opaque") \
/* Asm.js validation related */ \
T(AsmJsInvalid, "Invalid asm.js: %") \
T(AsmJsCompiled, "Converted asm.js to WebAssembly: %") \
......
......@@ -5,9 +5,7 @@
#include "src/ic/ic.h"
#include "src/api/api-arguments-inl.h"
#include "src/api/api.h"
#include "src/ast/ast.h"
#include "src/base/bits.h"
#include "src/base/logging.h"
#include "src/builtins/accessors.h"
#include "src/common/assert-scope.h"
......@@ -16,6 +14,7 @@
#include "src/execution/execution.h"
#include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h"
#include "src/execution/isolate.h"
#include "src/execution/protectors-inl.h"
#include "src/execution/tiering-manager.h"
#include "src/handles/handles-inl.h"
......@@ -27,19 +26,13 @@
#include "src/ic/stub-cache.h"
#include "src/numbers/conversions.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/data-handler-inl.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/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/megadom-handler.h"
#include "src/objects/module-inl.h"
#include "src/objects/property-descriptor.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/tracing/trace-event.h"
#include "src/tracing/tracing-category-observer.h"
......@@ -211,6 +204,7 @@ static void LookupForRead(LookupIterator* it, bool is_has_property) {
case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::JSPROXY:
case LookupIterator::WASM_OBJECT:
return;
case LookupIterator::INTERCEPTOR: {
// 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,
}
}
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) {
Handle<Object> receiver = lookup->GetReceiver();
ReadOnlyRoots roots(isolate());
......@@ -1155,30 +1087,14 @@ MaybeObjectHandle LoadIC::ComputeHandler(LookupIterator* lookup) {
return MaybeObjectHandle(smi_handler);
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
} 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);
return MaybeObjectHandle(LoadHandler::LoadSlow(isolate()));
} else {
DCHECK_EQ(PropertyLocation::kField,
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()));
FieldIndex field = lookup->GetFieldIndex();
smi_handler = LoadHandler::LoadField(isolate(), field);
}
DCHECK(holder->IsJSObject(isolate()));
FieldIndex field = lookup->GetFieldIndex();
smi_handler = LoadHandler::LoadField(isolate(), field);
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldDH);
if (holder_is_lookup_start_object)
return MaybeObjectHandle(smi_handler);
......@@ -1227,6 +1143,9 @@ MaybeObjectHandle LoadIC::ComputeHandler(LookupIterator* lookup) {
return MaybeObjectHandle(LoadHandler::LoadFromPrototype(
isolate(), map, holder_proxy, smi_handler));
}
case LookupIterator::WASM_OBJECT:
return MaybeObjectHandle(LoadHandler::LoadSlow(isolate()));
case LookupIterator::ACCESS_CHECK:
case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION:
......@@ -1618,6 +1537,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
switch (it->state()) {
case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION:
case LookupIterator::WASM_OBJECT:
UNREACHABLE();
case LookupIterator::JSPROXY:
return true;
......@@ -1773,11 +1693,15 @@ Maybe<bool> DefineOwnDataProperty(LookupIterator* it,
return JSProxy::DefineOwnProperty(it->isolate(), it->GetHolder<JSProxy>(),
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
// while the object is already prepared for TRANSITION.
case LookupIterator::TRANSITION: {
switch (original_state) {
case LookupIterator::JSPROXY:
case LookupIterator::WASM_OBJECT:
case LookupIterator::TRANSITION:
case LookupIterator::DATA:
case LookupIterator::INTERCEPTOR:
......@@ -2200,6 +2124,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
case LookupIterator::INTEGER_INDEXED_EXOTIC:
case LookupIterator::ACCESS_CHECK:
case LookupIterator::NOT_FOUND:
case LookupIterator::WASM_OBJECT:
UNREACHABLE();
}
return MaybeObjectHandle();
......@@ -2550,6 +2475,12 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
set_slow_stub_reason("map in array prototype");
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;
......
......@@ -97,6 +97,8 @@ Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
case LookupIterator::JSPROXY:
return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
it->GetName());
case LookupIterator::WASM_OBJECT:
return Just(false);
case LookupIterator::INTERCEPTOR: {
Maybe<PropertyAttributes> result =
JSObject::GetPropertyAttributesWithInterceptor(it);
......@@ -150,6 +152,7 @@ Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it,
case LookupIterator::INTERCEPTOR:
case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION:
case LookupIterator::WASM_OBJECT:
UNREACHABLE();
case LookupIterator::ACCESS_CHECK:
// Support calling this method without an active context, but refuse
......@@ -223,6 +226,9 @@ Maybe<bool> JSReceiver::CheckPrivateNameStore(LookupIterator* it,
NewTypeError(message, name_string, it->GetReceiver()));
}
return Just(true);
case LookupIterator::WASM_OBJECT:
RETURN_FAILURE(isolate, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
}
}
DCHECK(!it->IsFound());
......@@ -734,6 +740,8 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
UNREACHABLE();
case LookupIterator::JSPROXY:
return JSProxy::GetPropertyAttributes(it);
case LookupIterator::WASM_OBJECT:
return Just(ABSENT);
case LookupIterator::INTERCEPTOR: {
Maybe<PropertyAttributes> result =
JSObject::GetPropertyAttributesWithInterceptor(it);
......@@ -948,7 +956,6 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
}
return Just(true);
}
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
......@@ -956,6 +963,9 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::WASM_OBJECT:
RETURN_FAILURE(isolate, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
case LookupIterator::ACCESS_CHECK:
if (it->HasAccess()) break;
isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>());
......@@ -986,7 +996,7 @@ Maybe<bool> JSReceiver::DeleteProperty(LookupIterator* it,
if (is_strict(language_mode)) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kStrictDeleteProperty, it->GetName(),
receiver));
it->GetReceiver()));
return Nothing<bool>();
}
return Just(false);
......@@ -1158,6 +1168,12 @@ Maybe<bool> JSReceiver::DefineOwnProperty(Isolate* isolate,
isolate, Handle<JSModuleNamespace>::cast(object), key, desc,
should_throw);
}
#if V8_ENABLE_WEBASSEMBLY
if (object->IsWasmObject()) {
RETURN_FAILURE(isolate, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
}
#endif
// OrdinaryDefineOwnProperty, by virtue of calling
// DefineOwnPropertyIgnoreAttributes, can handle arguments
......@@ -1745,6 +1761,9 @@ Maybe<bool> JSReceiver::AddPrivateField(LookupIterator* it,
return JSProxy::SetPrivateSymbol(isolate, Handle<JSProxy>::cast(receiver),
symbol, &new_desc, should_throw);
}
case LookupIterator::WASM_OBJECT:
RETURN_FAILURE(isolate, kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
case LookupIterator::DATA:
case LookupIterator::INTERCEPTOR:
case LookupIterator::ACCESSOR:
......@@ -2033,6 +2052,12 @@ Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
return JSProxy::PreventExtensions(Handle<JSProxy>::cast(object),
should_throw);
}
#if V8_ENABLE_WEBASSEMBLY
if (object->IsWasmObject()) {
RETURN_FAILURE(object->GetIsolate(), kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
}
#endif
DCHECK(object->IsJSObject());
return JSObject::PreventExtensions(Handle<JSObject>::cast(object),
should_throw);
......@@ -2042,6 +2067,11 @@ Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) {
if (object->IsJSProxy()) {
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)));
}
......@@ -3561,6 +3591,7 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::JSPROXY:
case LookupIterator::WASM_OBJECT:
case LookupIterator::TRANSITION:
case LookupIterator::NOT_FOUND:
UNREACHABLE();
......
......@@ -253,6 +253,16 @@ Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
Maybe<bool> result = Just(false); // Dummy initialization.
if (current->IsJSProxy()) {
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 {
DCHECK(current->IsJSObject());
result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current));
......
......@@ -22,10 +22,6 @@
#include "src/objects/property-details.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 internal {
......@@ -874,18 +870,10 @@ bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
Handle<Object> LookupIterator::FetchValue(
AllocationPolicy allocation_policy) const {
Object result;
if (IsElement(*holder_)) {
#if V8_ENABLE_WEBASSEMBLY
if (V8_UNLIKELY(holder_->IsWasmObject(isolate_))) {
if (holder_->IsWasmStruct()) {
// WasmStructs don't have elements.
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_));
DCHECK(!holder_->IsWasmObject());
#endif
if (IsElement(*holder_)) {
Handle<JSObject> holder = GetHolder<JSObject>();
ElementsAccessor* accessor = holder->GetElementsAccessor(isolate_);
return accessor->Get(isolate_, holder, number_);
......@@ -903,27 +891,6 @@ Handle<Object> LookupIterator::FetchValue(
}
} else if (property_details_.location() == PropertyLocation::kField) {
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>();
FieldIndex field_index =
FieldIndex::ForDescriptor(holder->map(isolate_), descriptor_number());
......@@ -1179,42 +1146,6 @@ Handle<Object> LookupIterator::SwapDataValue(Handle<Object> value,
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>
bool LookupIterator::SkipInterceptor(JSObject holder) {
InterceptorInfo info = GetInterceptor<is_element>(holder);
......@@ -1284,9 +1215,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder(
if (is_element || !name_->IsPrivate(isolate_)) return JSPROXY;
}
#if V8_ENABLE_WEBASSEMBLY
if (map.IsWasmObjectMap()) {
return LookupInRegularHolder<is_element>(map, holder);
}
if (map.IsWasmObjectMap()) return WASM_OBJECT;
#endif // V8_ENABLE_WEBASSEMBLY
if (map.is_access_check_needed()) {
if (is_element || !name_->IsPrivate(isolate_) ||
......@@ -1325,6 +1254,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder(
return NOT_FOUND;
case INTEGER_INDEXED_EXOTIC:
case JSPROXY:
case WASM_OBJECT:
case TRANSITION:
UNREACHABLE();
}
......@@ -1338,43 +1268,24 @@ LookupIterator::State LookupIterator::LookupInRegularHolder(
if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
return NOT_FOUND;
}
if (is_element && IsElement(holder)) {
#if V8_ENABLE_WEBASSEMBLY
if (V8_UNLIKELY(holder.IsWasmObject(isolate_))) {
// TODO(ishell): consider supporting indexed access to WasmStruct fields.
if (holder.IsWasmArray(isolate_)) {
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);
ElementsAccessor* accessor = js_object.GetElementsAccessor(isolate_);
FixedArrayBase backing_store = js_object.elements(isolate_);
number_ = accessor->GetEntryForIndex(isolate_, js_object, backing_store,
index_);
if (number_.is_not_found()) {
return holder.IsJSTypedArray(isolate_) ? INTEGER_INDEXED_EXOTIC
: NOT_FOUND;
}
property_details_ = accessor->GetDetails(js_object, number_);
if (map.has_frozen_elements()) {
property_details_ = property_details_.CopyAddAttributes(FROZEN);
} else if (map.has_sealed_elements()) {
property_details_ = property_details_.CopyAddAttributes(SEALED);
}
DCHECK(!holder.IsWasmObject(isolate_));
#endif
if (is_element && IsElement(holder)) {
JSObject js_object = JSObject::cast(holder);
ElementsAccessor* accessor = js_object.GetElementsAccessor(isolate_);
FixedArrayBase backing_store = js_object.elements(isolate_);
number_ =
accessor->GetEntryForIndex(isolate_, js_object, backing_store, index_);
if (number_.is_not_found()) {
return holder.IsJSTypedArray(isolate_) ? INTEGER_INDEXED_EXOTIC
: NOT_FOUND;
}
property_details_ = accessor->GetDetails(js_object, number_);
if (map.has_frozen_elements()) {
property_details_ = property_details_.CopyAddAttributes(FROZEN);
} else if (map.has_sealed_elements()) {
property_details_ = property_details_.CopyAddAttributes(SEALED);
}
} else if (!map.is_dictionary_map()) {
DescriptorArray descriptors = map.instance_descriptors(isolate_);
......
......@@ -60,6 +60,7 @@ class V8_EXPORT_PRIVATE LookupIterator final {
INTEGER_INDEXED_EXOTIC,
INTERCEPTOR,
JSPROXY,
WASM_OBJECT,
NOT_FOUND,
ACCESSOR,
DATA,
......@@ -197,13 +198,6 @@ class V8_EXPORT_PRIVATE LookupIterator final {
static inline void UpdateProtector(Isolate* isolate, Handle<Object> receiver,
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.
// If not found returns false and leaves the LookupIterator unmodified.
bool TryLookupCachedProperty(Handle<AccessorPair> accessor);
......
......@@ -1167,6 +1167,10 @@ MaybeHandle<Object> Object::GetProperty(LookupIterator* it,
if (!was_found && !is_global_reference) it->NotFound();
return result;
}
case LookupIterator::WASM_OBJECT:
THROW_NEW_ERROR(it->isolate(),
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque),
Object);
case LookupIterator::INTERCEPTOR: {
bool done;
Handle<Object> result;
......@@ -2505,6 +2509,10 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it,
value, receiver, should_throw);
}
case LookupIterator::WASM_OBJECT:
RETURN_FAILURE(it->isolate(), kThrowOnError,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
case LookupIterator::INTERCEPTOR: {
if (it->HolderIsReceiverOrHiddenPrototype()) {
Maybe<bool> result =
......@@ -2722,6 +2730,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
case LookupIterator::NOT_FOUND:
case LookupIterator::TRANSITION:
case LookupIterator::WASM_OBJECT:
UNREACHABLE();
}
}
......@@ -2812,37 +2821,23 @@ Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) {
}
#if V8_ENABLE_WEBASSEMBLY
if (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
// clang-format off
DCHECK(!receiver->IsWasmObject(isolate));
#endif // V8_ENABLE_WEBASSEMBLY
if (V8_UNLIKELY(receiver->IsJSSharedStruct(isolate) ||
receiver->IsJSSharedArray(isolate))) {
// clang-format on
// Shared structs can only point to primitives or shared values.
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, to_assign, Object::Share(isolate, to_assign, kThrowOnError),
Nothing<bool>());
it->WriteDataValue(to_assign, false);
} else {
// Possibly migrate to the most up-to-date map that will be able to store
// |value| under it->name().
it->PrepareForDataProperty(to_assign);
// Shared structs can only point to primitives or shared values.
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, to_assign, Object::Share(isolate, to_assign, kThrowOnError),
Nothing<bool>());
it->WriteDataValue(to_assign, false);
} else {
// Possibly migrate to the most up-to-date map that will be able to store
// |value| under it->name().
it->PrepareForDataProperty(to_assign);
// Write the property value.
it->WriteDataValue(to_assign, false);
}
// Write the property value.
it->WriteDataValue(to_assign, false);
}
#if VERIFY_HEAP
if (v8_flags.verify_heap) {
......
......@@ -77,6 +77,10 @@ MaybeHandle<Object> HasEnumerableProperty(Isolate* isolate,
return it.GetName();
}
}
case LookupIterator::WASM_OBJECT:
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kWasmObjectsAreOpaque),
Object);
case LookupIterator::INTERCEPTOR: {
result = JSObject::GetPropertyAttributesWithInterceptor(&it);
if (result.IsNothing()) return MaybeHandle<Object>();
......
......@@ -987,6 +987,7 @@ MaybeHandle<Object> InstanceBuilder::LookupImportAsm(
case LookupIterator::INTEGER_INDEXED_EXOTIC:
case LookupIterator::INTERCEPTOR:
case LookupIterator::JSPROXY:
case LookupIterator::WASM_OBJECT:
case LookupIterator::ACCESSOR:
case LookupIterator::TRANSITION:
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