Commit ddc43d9c authored by Igor Sheludko's avatar Igor Sheludko Committed by V8 LUCI CQ

[wasm-gc][ic] Support WasmObjects in LoadIC

Bug: v8:11804
Change-Id: I6eddf2d836c3916622768ef2a7d878157e89e4c8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2772980Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74796}
parent 6d6438eb
...@@ -9286,6 +9286,9 @@ void CodeStubAssembler::LoadPropertyFromFastObject( ...@@ -9286,6 +9286,9 @@ void CodeStubAssembler::LoadPropertyFromFastObject(
TNode<Uint32T> representation = TNode<Uint32T> representation =
DecodeWord32<PropertyDetails::RepresentationField>(details); DecodeWord32<PropertyDetails::RepresentationField>(details);
// TODO(ishell): support WasmValues.
CSA_ASSERT(this, Word32NotEqual(representation,
Int32Constant(Representation::kWasmValue)));
field_index = field_index =
IntPtrAdd(field_index, LoadMapInobjectPropertiesStartInWords(map)); IntPtrAdd(field_index, LoadMapInobjectPropertiesStartInWords(map));
TNode<IntPtrT> instance_size_in_words = LoadMapInstanceSizeInWords(map); TNode<IntPtrT> instance_size_in_words = LoadMapInstanceSizeInWords(map);
......
...@@ -287,7 +287,7 @@ void AccessorAssembler::HandleLoadField(TNode<JSObject> holder, ...@@ -287,7 +287,7 @@ void AccessorAssembler::HandleLoadField(TNode<JSObject> holder,
TVariable<Float64T>* var_double_value, TVariable<Float64T>* var_double_value,
Label* rebox_double, Label* miss, Label* rebox_double, Label* miss,
ExitPoint* exit_point) { ExitPoint* exit_point) {
Comment("field_load"); Comment("LoadField");
TNode<IntPtrT> index = TNode<IntPtrT> index =
Signed(DecodeWord<LoadHandler::FieldIndexBits>(handler_word)); Signed(DecodeWord<LoadHandler::FieldIndexBits>(handler_word));
TNode<IntPtrT> offset = IntPtrMul(index, IntPtrConstant(kTaggedSize)); TNode<IntPtrT> offset = IntPtrMul(index, IntPtrConstant(kTaggedSize));
...@@ -332,6 +332,108 @@ void AccessorAssembler::HandleLoadField(TNode<JSObject> holder, ...@@ -332,6 +332,108 @@ void AccessorAssembler::HandleLoadField(TNode<JSObject> holder,
} }
} }
#if V8_ENABLE_WEBASSEMBLY
void AccessorAssembler::HandleLoadWasmField(
TNode<WasmObject> holder, TNode<Int32T> wasm_value_type,
TNode<IntPtrT> field_offset, TVariable<Float64T>* var_double_value,
Label* rebox_double, ExitPoint* exit_point) {
Label type_I8(this), type_I16(this), type_I32(this), type_U32(this),
type_I64(this), type_U64(this), type_F32(this), type_F64(this),
unsupported_type(this, Label::kDeferred),
unexpected_type(this, Label::kDeferred);
Label* wasm_value_type_labels[] = {
&type_I8, &type_I16, &type_I32, &type_U32,
&type_I64, &type_F32, &type_F64, &unsupported_type,
&unsupported_type, &unsupported_type};
int32_t wasm_value_types[] = {
static_cast<int32_t>(WasmValueType::kI8),
static_cast<int32_t>(WasmValueType::kI16),
static_cast<int32_t>(WasmValueType::kI32),
static_cast<int32_t>(WasmValueType::kU32),
static_cast<int32_t>(WasmValueType::kI64),
static_cast<int32_t>(WasmValueType::kF32),
static_cast<int32_t>(WasmValueType::kF64),
// TODO(ishell): support the following value types.
static_cast<int32_t>(WasmValueType::kS128),
static_cast<int32_t>(WasmValueType::kRef),
static_cast<int32_t>(WasmValueType::kOptRef)};
const size_t kWasmValueTypeCount =
static_cast<size_t>(WasmValueType::kNumTypes);
DCHECK_EQ(kWasmValueTypeCount, arraysize(wasm_value_types));
DCHECK_EQ(kWasmValueTypeCount, arraysize(wasm_value_type_labels));
Switch(wasm_value_type, &unexpected_type, wasm_value_types,
wasm_value_type_labels, kWasmValueTypeCount);
BIND(&type_I8);
{
Comment("type_I8");
TNode<Int32T> value = LoadObjectField<Int8T>(holder, field_offset);
exit_point->Return(SmiFromInt32(value));
}
BIND(&type_I16);
{
Comment("type_I16");
TNode<Int32T> value = LoadObjectField<Int16T>(holder, field_offset);
exit_point->Return(SmiFromInt32(value));
}
BIND(&type_I32);
{
Comment("type_I32");
TNode<Int32T> value = LoadObjectField<Int32T>(holder, field_offset);
exit_point->Return(ChangeInt32ToTagged(value));
}
BIND(&type_U32);
{
Comment("type_U32");
TNode<Uint32T> value = LoadObjectField<Uint32T>(holder, field_offset);
exit_point->Return(ChangeUint32ToTagged(value));
}
BIND(&type_I64);
{
Comment("type_I64");
Unreachable();
}
BIND(&type_F32);
{
Comment("type_F32");
TNode<Float32T> value = LoadObjectField<Float32T>(holder, field_offset);
*var_double_value = ChangeFloat32ToFloat64(value);
Goto(rebox_double);
}
BIND(&type_F64);
{
Comment("type_F64");
TNode<Float64T> value = LoadObjectField<Float64T>(holder, field_offset);
*var_double_value = value;
Goto(rebox_double);
}
BIND(&unsupported_type);
{
Print("Not supported Wasm field type");
Unreachable();
}
BIND(&unexpected_type);
{ Unreachable(); }
}
void AccessorAssembler::HandleLoadWasmField(
TNode<WasmObject> holder, TNode<WordT> handler_word,
TVariable<Float64T>* var_double_value, Label* rebox_double,
ExitPoint* exit_point) {
Comment("LoadWasmField");
TNode<Int32T> wasm_value_type =
Signed(DecodeWord32<LoadHandler::WasmFieldTypeBits>(
TruncateWordToInt32(handler_word)));
TNode<IntPtrT> field_offset =
Signed(DecodeWord<LoadHandler::WasmFieldOffsetBits>(handler_word));
HandleLoadWasmField(holder, wasm_value_type, field_offset, var_double_value,
rebox_double, exit_point);
}
#endif // V8_ENABLE_WEBASSEMBLY
TNode<Object> AccessorAssembler::LoadDescriptorValue( TNode<Object> AccessorAssembler::LoadDescriptorValue(
TNode<Map> map, TNode<IntPtrT> descriptor_entry) { TNode<Map> map, TNode<IntPtrT> descriptor_entry) {
return CAST(LoadDescriptorValueOrFieldType(map, descriptor_entry)); return CAST(LoadDescriptorValueOrFieldType(map, descriptor_entry));
...@@ -378,6 +480,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( ...@@ -378,6 +480,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
BIND(&if_element); BIND(&if_element);
{ {
Comment("element_load"); Comment("element_load");
// TODO(ishell): implement
CSA_ASSERT(this, IsClearWord<LoadHandler::IsWasmArrayBits>(handler_word));
TVARIABLE(Int32T, var_instance_type); TVARIABLE(Int32T, var_instance_type);
TNode<IntPtrT> intptr_index = TryToIntptr( TNode<IntPtrT> intptr_index = TryToIntptr(
p->name(), &try_string_to_array_index, &var_instance_type); p->name(), &try_string_to_array_index, &var_instance_type);
...@@ -558,8 +662,24 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( ...@@ -558,8 +662,24 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
&module_export, &interceptor); &module_export, &interceptor);
BIND(&field); BIND(&field);
HandleLoadField(CAST(holder), handler_word, var_double_value, rebox_double, {
miss, exit_point); #if V8_ENABLE_WEBASSEMBLY
Label is_wasm_field(this);
GotoIf(IsSetWord<LoadHandler::IsWasmStructBits>(handler_word),
&is_wasm_field);
#else
CSA_ASSERT(this, IsClearWord<LoadHandler::IsWasmStructBits>(handler_word));
#endif // V8_ENABLE_WEBASSEMBLY
HandleLoadField(CAST(holder), handler_word, var_double_value, rebox_double,
miss, exit_point);
#if V8_ENABLE_WEBASSEMBLY
BIND(&is_wasm_field);
HandleLoadWasmField(CAST(holder), handler_word, var_double_value,
rebox_double, exit_point);
#endif // V8_ENABLE_WEBASSEMBLY
}
BIND(&nonexistent); BIND(&nonexistent);
// This is a handler for a load of a non-existent value. // This is a handler for a load of a non-existent value.
...@@ -2633,6 +2753,7 @@ void AccessorAssembler::GenericPropertyLoad( ...@@ -2633,6 +2753,7 @@ void AccessorAssembler::GenericPropertyLoad(
BIND(&special_receiver); BIND(&special_receiver);
{ {
// TODO(ishell): Consider supporting WasmObjects.
// TODO(jkummerow): Consider supporting JSModuleNamespace. // TODO(jkummerow): Consider supporting JSModuleNamespace.
GotoIfNot( GotoIfNot(
InstanceTypeEqual(lookup_start_object_instance_type, JS_PROXY_TYPE), InstanceTypeEqual(lookup_start_object_instance_type, JS_PROXY_TYPE),
......
...@@ -355,6 +355,18 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ...@@ -355,6 +355,18 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TVariable<Float64T>* var_double_value, TVariable<Float64T>* var_double_value,
Label* rebox_double, Label* miss, ExitPoint* exit_point); Label* rebox_double, Label* miss, ExitPoint* exit_point);
#if V8_ENABLE_WEBASSEMBLY
void HandleLoadWasmField(TNode<WasmObject> holder,
TNode<Int32T> wasm_value_type,
TNode<IntPtrT> field_offset,
TVariable<Float64T>* var_double_value,
Label* rebox_double, ExitPoint* exit_point);
void HandleLoadWasmField(TNode<WasmObject> holder, TNode<WordT> handler_word,
TVariable<Float64T>* var_double_value,
Label* rebox_double, ExitPoint* exit_point);
#endif // V8_ENABLE_WEBASSEMBLY
void EmitAccessCheck(TNode<Context> expected_native_context, void EmitAccessCheck(TNode<Context> expected_native_context,
TNode<Context> context, TNode<Object> receiver, TNode<Context> context, TNode<Object> receiver,
Label* can_access, Label* miss); Label* can_access, Label* miss);
......
...@@ -56,6 +56,14 @@ Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) { ...@@ -56,6 +56,14 @@ Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) {
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Smi> LoadHandler::LoadWasmStructField(Isolate* isolate,
WasmValueType type, int offset) {
int config = KindBits::encode(kField) | IsWasmStructBits::encode(true) |
WasmFieldTypeBits::encode(type) |
WasmFieldOffsetBits::encode(offset);
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> LoadHandler::LoadConstantFromPrototype(Isolate* isolate) { Handle<Smi> LoadHandler::LoadConstantFromPrototype(Isolate* isolate) {
int config = KindBits::encode(kConstantFromPrototype); int config = KindBits::encode(kConstantFromPrototype);
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
...@@ -118,6 +126,13 @@ Handle<Smi> LoadHandler::LoadIndexedString(Isolate* isolate, ...@@ -118,6 +126,13 @@ Handle<Smi> LoadHandler::LoadIndexedString(Isolate* isolate,
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Smi> LoadHandler::LoadWasmArrayElement(Isolate* isolate,
WasmValueType type) {
int config = KindBits::encode(kElement) | IsWasmArrayBits::encode(true) |
WasmArrayTypeBits::encode(type);
return handle(Smi::FromInt(config), isolate);
}
OBJECT_CONSTRUCTORS_IMPL(StoreHandler, DataHandler) OBJECT_CONSTRUCTORS_IMPL(StoreHandler, DataHandler)
CAST_ACCESSOR(StoreHandler) CAST_ACCESSOR(StoreHandler)
...@@ -190,6 +205,35 @@ Handle<Smi> StoreHandler::StoreApiSetter(Isolate* isolate, ...@@ -190,6 +205,35 @@ Handle<Smi> StoreHandler::StoreApiSetter(Isolate* isolate,
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
inline const char* WasmValueType2String(WasmValueType type) {
switch (type) {
case WasmValueType::kI8:
return "i8";
case WasmValueType::kI16:
return "i16";
case WasmValueType::kI32:
return "i32";
case WasmValueType::kU32:
return "u32";
case WasmValueType::kI64:
return "i64";
case WasmValueType::kF32:
return "f32";
case WasmValueType::kF64:
return "f64";
case WasmValueType::kS128:
return "s128";
case WasmValueType::kRef:
return "Ref";
case WasmValueType::kOptRef:
return "OptRef";
case WasmValueType::kNumTypes:
return "???";
}
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -315,14 +315,22 @@ void PrintSmiLoadHandler(int raw_handler, std::ostream& os) { ...@@ -315,14 +315,22 @@ void PrintSmiLoadHandler(int raw_handler, std::ostream& os) {
os << "kind = "; os << "kind = ";
switch (kind) { switch (kind) {
case LoadHandler::Kind::kElement: case LoadHandler::Kind::kElement:
os << "kElement, allow out of bounds = " os << "kElement, ";
<< LoadHandler::AllowOutOfBoundsBits::decode(raw_handler) if (LoadHandler::IsWasmArrayBits::decode(raw_handler)) {
<< ", is JSArray = " << LoadHandler::IsJsArrayBits::decode(raw_handler) os << "WasmArray, "
<< ", convert hole = " << LoadHandler::WasmArrayTypeBits::decode(raw_handler);
<< LoadHandler::ConvertHoleBits::decode(raw_handler)
<< ", elements kind = " } else {
<< ElementsKindToString( os << "allow out of bounds = "
LoadHandler::ElementsKindBits::decode(raw_handler)); << LoadHandler::AllowOutOfBoundsBits::decode(raw_handler)
<< ", is JSArray = "
<< LoadHandler::IsJsArrayBits::decode(raw_handler)
<< ", convert hole = "
<< LoadHandler::ConvertHoleBits::decode(raw_handler)
<< ", elements kind = "
<< ElementsKindToString(
LoadHandler::ElementsKindBits::decode(raw_handler));
}
break; break;
case LoadHandler::Kind::kIndexedString: case LoadHandler::Kind::kIndexedString:
os << "kIndexedString, allow out of bounds = " os << "kIndexedString, allow out of bounds = "
...@@ -335,11 +343,18 @@ void PrintSmiLoadHandler(int raw_handler, std::ostream& os) { ...@@ -335,11 +343,18 @@ void PrintSmiLoadHandler(int raw_handler, std::ostream& os) {
os << "kGlobal"; os << "kGlobal";
break; break;
case LoadHandler::Kind::kField: { case LoadHandler::Kind::kField: {
os << "kField, is in object = " if (LoadHandler::IsWasmStructBits::decode(raw_handler)) {
<< LoadHandler::IsInobjectBits::decode(raw_handler) os << "kField, WasmStruct, type = "
<< ", is double = " << LoadHandler::IsDoubleBits::decode(raw_handler) << LoadHandler::WasmFieldTypeBits::decode(raw_handler)
<< ", field index = " << ", field offset = "
<< LoadHandler::FieldIndexBits::decode(raw_handler); << LoadHandler::WasmFieldOffsetBits::decode(raw_handler);
} else {
os << "kField, is in object = "
<< LoadHandler::IsInobjectBits::decode(raw_handler)
<< ", is double = " << LoadHandler::IsDoubleBits::decode(raw_handler)
<< ", field index = "
<< LoadHandler::FieldIndexBits::decode(raw_handler);
}
break; break;
} }
case LoadHandler::Kind::kConstantFromPrototype: { case LoadHandler::Kind::kConstantFromPrototype: {
...@@ -527,6 +542,11 @@ void StoreHandler::PrintHandler(Object handler, std::ostream& os) { ...@@ -527,6 +542,11 @@ void StoreHandler::PrintHandler(Object handler, std::ostream& os) {
os << ")" << std::endl; os << ")" << std::endl;
} }
} }
std::ostream& operator<<(std::ostream& os, WasmValueType type) {
return os << WasmValueType2String(type);
}
#endif // defined(OBJECT_PRINT) #endif // defined(OBJECT_PRINT)
} // namespace internal } // namespace internal
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/handles/maybe-handles.h" #include "src/handles/maybe-handles.h"
#include "src/heap/heap.h"
#include "src/objects/data-handler.h" #include "src/objects/data-handler.h"
#include "src/objects/elements-kind.h" #include "src/objects/elements-kind.h"
#include "src/objects/field-index.h" #include "src/objects/field-index.h"
...@@ -21,6 +22,22 @@ namespace internal { ...@@ -21,6 +22,22 @@ namespace internal {
class JSProxy; class JSProxy;
enum class WasmValueType {
kI8,
kI16,
kI32,
kU32, // Used only for loading WasmArray length.
kI64,
kF32,
kF64,
kS128,
kRef,
kOptRef,
kNumTypes
};
// A set of bit fields representing Smi handlers for loads and a HeapObject // A set of bit fields representing Smi handlers for loads and a HeapObject
// that represents load handlers that can't be encoded in a Smi. // that represents load handlers that can't be encoded in a Smi.
// TODO(ishell): move to load-handler.h // TODO(ishell): move to load-handler.h
...@@ -75,7 +92,12 @@ class LoadHandler final : public DataHandler { ...@@ -75,7 +92,12 @@ class LoadHandler final : public DataHandler {
// //
// Encoding when KindBits contains kField. // Encoding when KindBits contains kField.
// //
using IsInobjectBits = LookupOnLookupStartObjectBits::Next<bool, 1>; using IsWasmStructBits = LookupOnLookupStartObjectBits::Next<bool, 1>;
//
// Encoding when KindBits contains kField and IsWasmStructBits is 0.
//
using IsInobjectBits = IsWasmStructBits::Next<bool, 1>;
using IsDoubleBits = IsInobjectBits::Next<bool, 1>; using IsDoubleBits = IsInobjectBits::Next<bool, 1>;
// +1 here is to cover all possible JSObject header sizes. // +1 here is to cover all possible JSObject header sizes.
using FieldIndexBits = using FieldIndexBits =
...@@ -83,6 +105,14 @@ class LoadHandler final : public DataHandler { ...@@ -83,6 +105,14 @@ class LoadHandler final : public DataHandler {
// Make sure we don't overflow the smi. // Make sure we don't overflow the smi.
STATIC_ASSERT(FieldIndexBits::kLastUsedBit < kSmiValueSize); STATIC_ASSERT(FieldIndexBits::kLastUsedBit < kSmiValueSize);
//
// Encoding when KindBits contains kField and IsWasmStructBits is 1.
//
using WasmFieldTypeBits = IsWasmStructBits::Next<WasmValueType, 4>;
using WasmFieldOffsetBits = WasmFieldTypeBits::Next<unsigned, 20>;
// Make sure we don't overflow the smi.
STATIC_ASSERT(WasmFieldOffsetBits::kLastUsedBit < kSmiValueSize);
// //
// Encoding when KindBits contains kElement or kIndexedString. // Encoding when KindBits contains kElement or kIndexedString.
// //
...@@ -91,18 +121,31 @@ class LoadHandler final : public DataHandler { ...@@ -91,18 +121,31 @@ class LoadHandler final : public DataHandler {
// //
// Encoding when KindBits contains kElement. // Encoding when KindBits contains kElement.
// //
using IsJsArrayBits = AllowOutOfBoundsBits::Next<bool, 1>; using IsWasmArrayBits = AllowOutOfBoundsBits::Next<bool, 1>;
//
// Encoding when KindBits contains kElement and IsWasmArrayBits is 0.
//
using IsJsArrayBits = IsWasmArrayBits::Next<bool, 1>;
using ConvertHoleBits = IsJsArrayBits::Next<bool, 1>; using ConvertHoleBits = IsJsArrayBits::Next<bool, 1>;
using ElementsKindBits = ConvertHoleBits::Next<ElementsKind, 8>; using ElementsKindBits = ConvertHoleBits::Next<ElementsKind, 8>;
// Make sure we don't overflow the smi. // Make sure we don't overflow the smi.
STATIC_ASSERT(ElementsKindBits::kLastUsedBit < kSmiValueSize); STATIC_ASSERT(ElementsKindBits::kLastUsedBit < kSmiValueSize);
//
// Encoding when KindBits contains kElement and IsWasmArrayBits is 1.
//
using WasmArrayTypeBits = IsWasmArrayBits::Next<WasmValueType, 4>;
// Make sure we don't overflow the smi.
STATIC_ASSERT(WasmArrayTypeBits::kLastUsedBit < kSmiValueSize);
// //
// Encoding when KindBits contains kModuleExport. // Encoding when KindBits contains kModuleExport.
// //
using ExportsIndexBits = LookupOnLookupStartObjectBits::Next< using ExportsIndexBits = LookupOnLookupStartObjectBits::Next<
unsigned, unsigned,
kSmiValueSize - LookupOnLookupStartObjectBits::kLastUsedBit - 1>; kSmiValueSize - LookupOnLookupStartObjectBits::kLastUsedBit - 1>;
STATIC_ASSERT(ExportsIndexBits::kLastUsedBit < kSmiValueSize);
// Decodes kind from Smi-handler. // Decodes kind from Smi-handler.
static inline Kind GetHandlerKind(Smi smi_handler); static inline Kind GetHandlerKind(Smi smi_handler);
...@@ -146,6 +189,11 @@ class LoadHandler final : public DataHandler { ...@@ -146,6 +189,11 @@ class LoadHandler final : public DataHandler {
// dictionary. // dictionary.
static inline Handle<Smi> LoadModuleExport(Isolate* isolate, int index); static inline Handle<Smi> LoadModuleExport(Isolate* isolate, int index);
static inline Handle<Smi> LoadWasmStructField(Isolate* isolate,
WasmValueType type, int offset);
static inline Handle<Smi> LoadWasmArrayElement(Isolate* isolate,
WasmValueType type);
// Creates a data handler that represents a load of a non-existent property. // Creates a data handler that represents a load of a non-existent property.
// {holder} is the object from which the property is loaded. If no holder is // {holder} is the object from which the property is loaded. If no holder is
// needed (e.g., for "nonexistent"), null_value() may be passed in. // needed (e.g., for "nonexistent"), null_value() may be passed in.
...@@ -317,6 +365,10 @@ class StoreHandler final : public DataHandler { ...@@ -317,6 +365,10 @@ class StoreHandler final : public DataHandler {
OBJECT_CONSTRUCTORS(StoreHandler, DataHandler); OBJECT_CONSTRUCTORS(StoreHandler, DataHandler);
}; };
inline const char* WasmValueType2String(WasmValueType type);
std::ostream& operator<<(std::ostream& os, WasmValueType type);
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -43,6 +43,10 @@ ...@@ -43,6 +43,10 @@
#include "src/tracing/tracing-category-observer.h" #include "src/tracing/tracing-category-observer.h"
#include "src/utils/ostreams.h" #include "src/utils/ostreams.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/struct-types.h"
#endif // V8_ENABLE_WEBASSEMBLY
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -831,6 +835,69 @@ void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name, ...@@ -831,6 +835,69 @@ 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(OptRef)
case wasm::kRtt:
case wasm::kRttWithDepth:
// 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
Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
Handle<Object> receiver = lookup->GetReceiver(); Handle<Object> receiver = lookup->GetReceiver();
ReadOnlyRoots roots(isolate()); ReadOnlyRoots roots(isolate());
...@@ -1040,13 +1107,22 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -1040,13 +1107,22 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
if (holder_is_lookup_start_object) return smi_handler; if (holder_is_lookup_start_object) return 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 LoadHandler::LoadNonExistent(isolate());
}
#endif // V8_ENABLE_WEBASSEMBLY
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return LoadHandler::LoadSlow(isolate()); return LoadHandler::LoadSlow(isolate());
} else { } else {
DCHECK_EQ(kField, lookup->property_details().location()); DCHECK_EQ(kField, lookup->property_details().location());
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
if (V8_UNLIKELY(holder->IsWasmObject(isolate()))) { if (V8_UNLIKELY(holder->IsWasmObject(isolate()))) {
smi_handler = LoadHandler::LoadSlow(isolate()); smi_handler =
MakeLoadWasmStructFieldHandler(isolate(), holder, lookup);
} else // NOLINT(readability/braces) } else // NOLINT(readability/braces)
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
{ {
......
...@@ -114,6 +114,9 @@ class StructType : public ZoneObject { ...@@ -114,6 +114,9 @@ class StructType : public ZoneObject {
bool* const mutabilities_; bool* const mutabilities_;
}; };
static const size_t kMaxFieldOffset =
(kV8MaxWasmStructFields - 1) * kMaxValueTypeSize;
private: private:
const uint32_t field_count_; const uint32_t field_count_;
uint32_t* const field_offsets_; uint32_t* const field_offsets_;
......
...@@ -50,6 +50,8 @@ class Simd128; ...@@ -50,6 +50,8 @@ class Simd128;
V(OptRef, kTaggedSizeLog2, OptRef, AnyTagged, 'n', "ref null") \ V(OptRef, kTaggedSizeLog2, OptRef, AnyTagged, 'n', "ref null") \
V(Bottom, -1, Void, None, '*', "<bot>") V(Bottom, -1, Void, None, '*', "<bot>")
constexpr int kMaxValueTypeSize = 16; // bytes
// Represents a WebAssembly heap type, as per the typed-funcref and gc // Represents a WebAssembly heap type, as per the typed-funcref and gc
// proposals. // proposals.
// The underlying Representation enumeration encodes heap types as follows: // The underlying Representation enumeration encodes heap types as follows:
......
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
// Flags: --allow-natives-syntax --experimental-wasm-gc --wasm-gc-js-interop // Flags: --allow-natives-syntax --experimental-wasm-gc --wasm-gc-js-interop
// Flags: --expose-gc // Flags: --expose-gc
// Flags: --no-lazy-feedback-allocation
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
const kIterationsCountForICProgression = 20;
// TODO(ishell): remove once leaked maps could keep NativeModule alive. // TODO(ishell): remove once leaked maps could keep NativeModule alive.
let instances = []; let instances = [];
...@@ -71,9 +72,9 @@ function createArray_i() { ...@@ -71,9 +72,9 @@ function createArray_i() {
(function TestSimpleArrayInterop() { (function TestSimpleArrayInterop() {
function f(o) { function f(o) {
for (let i = 0; i < 4; i++) { for (let i = 0; i < kIterationsCountForICProgression; i++) {
let len = o.length; let len = o.length;
print("len = " + len); assertEquals(10, len);
// Keyed loads are not supported yet // Keyed loads are not supported yet
// let v0 = o[0]; // let v0 = o[0];
// %DebugPrint(v0); // %DebugPrint(v0);
......
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
// Flags: --allow-natives-syntax --experimental-wasm-gc --wasm-gc-js-interop // Flags: --allow-natives-syntax --experimental-wasm-gc --wasm-gc-js-interop
// Flags: --expose-gc // Flags: --expose-gc
// Flags: --no-lazy-feedback-allocation
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
const kIterationsCountForICProgression = 20;
// TODO(ishell): remove once leaked maps could keep NativeModule alive. // TODO(ishell): remove once leaked maps could keep NativeModule alive.
let instances = []; let instances = [];
...@@ -69,9 +70,9 @@ function createStruct_i() { ...@@ -69,9 +70,9 @@ function createStruct_i() {
(function TestSimpleStructInterop() { (function TestSimpleStructInterop() {
function f(o) { function f(o) {
for (let i = 0; i < 4; i++) { for (let i = 0; i < kIterationsCountForICProgression; i++) {
let v = o.$field0; let v = o.$field0;
assertEquals(v, 153); assertEquals(153, v);
} }
} }
......
...@@ -475,27 +475,27 @@ KNOWN_OBJECTS = { ...@@ -475,27 +475,27 @@ KNOWN_OBJECTS = {
("old_space", 0x029b5): "StringSplitCache", ("old_space", 0x029b5): "StringSplitCache",
("old_space", 0x02dbd): "RegExpMultipleCache", ("old_space", 0x02dbd): "RegExpMultipleCache",
("old_space", 0x031c5): "BuiltinsConstantsTable", ("old_space", 0x031c5): "BuiltinsConstantsTable",
("old_space", 0x035d1): "AsyncFunctionAwaitRejectSharedFun", ("old_space", 0x035d5): "AsyncFunctionAwaitRejectSharedFun",
("old_space", 0x035f5): "AsyncFunctionAwaitResolveSharedFun", ("old_space", 0x035f9): "AsyncFunctionAwaitResolveSharedFun",
("old_space", 0x03619): "AsyncGeneratorAwaitRejectSharedFun", ("old_space", 0x0361d): "AsyncGeneratorAwaitRejectSharedFun",
("old_space", 0x0363d): "AsyncGeneratorAwaitResolveSharedFun", ("old_space", 0x03641): "AsyncGeneratorAwaitResolveSharedFun",
("old_space", 0x03661): "AsyncGeneratorYieldResolveSharedFun", ("old_space", 0x03665): "AsyncGeneratorYieldResolveSharedFun",
("old_space", 0x03685): "AsyncGeneratorReturnResolveSharedFun", ("old_space", 0x03689): "AsyncGeneratorReturnResolveSharedFun",
("old_space", 0x036a9): "AsyncGeneratorReturnClosedRejectSharedFun", ("old_space", 0x036ad): "AsyncGeneratorReturnClosedRejectSharedFun",
("old_space", 0x036cd): "AsyncGeneratorReturnClosedResolveSharedFun", ("old_space", 0x036d1): "AsyncGeneratorReturnClosedResolveSharedFun",
("old_space", 0x036f1): "AsyncIteratorValueUnwrapSharedFun", ("old_space", 0x036f5): "AsyncIteratorValueUnwrapSharedFun",
("old_space", 0x03715): "PromiseAllResolveElementSharedFun", ("old_space", 0x03719): "PromiseAllResolveElementSharedFun",
("old_space", 0x03739): "PromiseAllSettledResolveElementSharedFun", ("old_space", 0x0373d): "PromiseAllSettledResolveElementSharedFun",
("old_space", 0x0375d): "PromiseAllSettledRejectElementSharedFun", ("old_space", 0x03761): "PromiseAllSettledRejectElementSharedFun",
("old_space", 0x03781): "PromiseAnyRejectElementSharedFun", ("old_space", 0x03785): "PromiseAnyRejectElementSharedFun",
("old_space", 0x037a5): "PromiseCapabilityDefaultRejectSharedFun", ("old_space", 0x037a9): "PromiseCapabilityDefaultRejectSharedFun",
("old_space", 0x037c9): "PromiseCapabilityDefaultResolveSharedFun", ("old_space", 0x037cd): "PromiseCapabilityDefaultResolveSharedFun",
("old_space", 0x037ed): "PromiseCatchFinallySharedFun", ("old_space", 0x037f1): "PromiseCatchFinallySharedFun",
("old_space", 0x03811): "PromiseGetCapabilitiesExecutorSharedFun", ("old_space", 0x03815): "PromiseGetCapabilitiesExecutorSharedFun",
("old_space", 0x03835): "PromiseThenFinallySharedFun", ("old_space", 0x03839): "PromiseThenFinallySharedFun",
("old_space", 0x03859): "PromiseThrowerFinallySharedFun", ("old_space", 0x0385d): "PromiseThrowerFinallySharedFun",
("old_space", 0x0387d): "PromiseValueThunkFinallySharedFun", ("old_space", 0x03881): "PromiseValueThunkFinallySharedFun",
("old_space", 0x038a1): "ProxyRevokeSharedFun", ("old_space", 0x038a5): "ProxyRevokeSharedFun",
} }
# Lower 32 bits of first page addresses for various heap spaces. # Lower 32 bits of first page addresses for various heap spaces.
......
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