summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/builtins-object-gen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/builtins/builtins-object-gen.cc')
-rw-r--r--deps/v8/src/builtins/builtins-object-gen.cc383
1 files changed, 191 insertions, 192 deletions
diff --git a/deps/v8/src/builtins/builtins-object-gen.cc b/deps/v8/src/builtins/builtins-object-gen.cc
index ed9f72cae1..f0d21bba56 100644
--- a/deps/v8/src/builtins/builtins-object-gen.cc
+++ b/deps/v8/src/builtins/builtins-object-gen.cc
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "src/builtins/builtins-object-gen.h"
+
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
-#include "src/codegen/code-stub-assembler.h"
#include "src/common/globals.h"
#include "src/heap/factory-inl.h"
#include "src/ic/accessor-assembler.h"
@@ -18,43 +19,6 @@
namespace v8 {
namespace internal {
-// -----------------------------------------------------------------------------
-// ES6 section 19.1 Object Objects
-
-class ObjectBuiltinsAssembler : public CodeStubAssembler {
- public:
- explicit ObjectBuiltinsAssembler(compiler::CodeAssemblerState* state)
- : CodeStubAssembler(state) {}
-
- protected:
- void ReturnToStringFormat(TNode<Context> context, TNode<String> string);
-
- // TODO(v8:11167) remove |context| and |object| once OrderedNameDictionary
- // supported.
- void AddToDictionaryIf(TNode<BoolT> condition, TNode<Context> context,
- TNode<Object> object,
- TNode<HeapObject> name_dictionary, Handle<Name> name,
- TNode<Object> value, Label* bailout);
- TNode<JSObject> FromPropertyDescriptor(TNode<Context> context,
- TNode<PropertyDescriptorObject> desc);
- TNode<JSObject> FromPropertyDetails(TNode<Context> context,
- TNode<Object> raw_value,
- TNode<Word32T> details,
- Label* if_bailout);
- TNode<JSObject> ConstructAccessorDescriptor(TNode<Context> context,
- TNode<Object> getter,
- TNode<Object> setter,
- TNode<BoolT> enumerable,
- TNode<BoolT> configurable);
- TNode<JSObject> ConstructDataDescriptor(TNode<Context> context,
- TNode<Object> value,
- TNode<BoolT> writable,
- TNode<BoolT> enumerable,
- TNode<BoolT> configurable);
- TNode<HeapObject> GetAccessorOrUndefined(TNode<HeapObject> accessor,
- Label* if_bailout);
-};
-
class ObjectEntriesValuesBuiltinsAssembler : public ObjectBuiltinsAssembler {
public:
explicit ObjectEntriesValuesBuiltinsAssembler(
@@ -738,7 +702,7 @@ TF_BUILTIN(ObjectPrototypeIsPrototypeOf, ObjectBuiltinsAssembler) {
// If {value} is a primitive HeapObject, we need to return
// false instead of throwing an exception per order of the
// steps in the specification, so check that first here.
- GotoIfNot(IsJSReceiver(value_heap_object), &if_valueisnotreceiver);
+ GotoIfNot(JSAnyIsNotPrimitive(value_heap_object), &if_valueisnotreceiver);
// Simulate the ToObject invocation on {receiver}.
ToObject(context, receiver);
@@ -751,47 +715,43 @@ TF_BUILTIN(ObjectPrototypeIsPrototypeOf, ObjectBuiltinsAssembler) {
}
TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
+ TVARIABLE(String, var_default);
+ TVARIABLE(HeapObject, var_holder);
+ TVARIABLE(Map, var_holder_map);
+
Label checkstringtag(this), if_arguments(this), if_array(this),
if_boolean(this), if_date(this), if_error(this), if_function(this),
if_number(this, Label::kDeferred), if_object(this), if_primitive(this),
- if_proxy(this, Label::kDeferred), if_regexp(this), if_string(this),
- if_symbol(this, Label::kDeferred), if_value(this),
- if_bigint(this, Label::kDeferred), if_wasm(this);
+ if_proxy(this, {&var_holder, &var_holder_map}, Label::kDeferred),
+ if_regexp(this), if_string(this), if_symbol(this, Label::kDeferred),
+ if_value(this), if_bigint(this, Label::kDeferred);
auto receiver = Parameter<Object>(Descriptor::kReceiver);
auto context = Parameter<Context>(Descriptor::kContext);
- TVARIABLE(String, var_default);
- TVARIABLE(HeapObject, var_holder);
-
// This is arranged to check the likely cases first.
GotoIf(TaggedIsSmi(receiver), &if_number);
TNode<HeapObject> receiver_heap_object = CAST(receiver);
TNode<Map> receiver_map = LoadMap(receiver_heap_object);
var_holder = receiver_heap_object;
+ var_holder_map = receiver_map;
TNode<Uint16T> receiver_instance_type = LoadMapInstanceType(receiver_map);
GotoIf(IsPrimitiveInstanceType(receiver_instance_type), &if_primitive);
GotoIf(IsFunctionInstanceType(receiver_instance_type), &if_function);
const struct {
InstanceType value;
Label* label;
- } kJumpTable[] = {
- {JS_OBJECT_TYPE, &if_object},
- {JS_ARRAY_TYPE, &if_array},
- {JS_REG_EXP_TYPE, &if_regexp},
- {JS_ARGUMENTS_OBJECT_TYPE, &if_arguments},
- {JS_DATE_TYPE, &if_date},
- {JS_API_OBJECT_TYPE, &if_object},
- {JS_SPECIAL_API_OBJECT_TYPE, &if_object},
- {JS_PROXY_TYPE, &if_proxy},
- {JS_ERROR_TYPE, &if_error},
- {JS_PRIMITIVE_WRAPPER_TYPE, &if_value},
-#if V8_ENABLE_WEBASSEMBLY
- {WASM_STRUCT_TYPE, &if_wasm},
- {WASM_ARRAY_TYPE, &if_wasm},
-#endif
- };
+ } kJumpTable[] = {{JS_OBJECT_TYPE, &if_object},
+ {JS_ARRAY_TYPE, &if_array},
+ {JS_REG_EXP_TYPE, &if_regexp},
+ {JS_ARGUMENTS_OBJECT_TYPE, &if_arguments},
+ {JS_DATE_TYPE, &if_date},
+ {JS_API_OBJECT_TYPE, &if_object},
+ {JS_SPECIAL_API_OBJECT_TYPE, &if_object},
+ {JS_PROXY_TYPE, &if_proxy},
+ {JS_ERROR_TYPE, &if_error},
+ {JS_PRIMITIVE_WRAPPER_TYPE, &if_value}};
size_t const kNumCases = arraysize(kJumpTable);
Label* case_labels[kNumCases];
int32_t case_values[kNumCases];
@@ -825,6 +785,7 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
LoadObjectField<HeapObject>(boolean_initial_map, Map::kPrototypeOffset);
var_default = BooleanToStringConstant();
var_holder = boolean_prototype;
+ var_holder_map = LoadMap(boolean_prototype);
Goto(&checkstringtag);
}
@@ -857,6 +818,7 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
LoadObjectField<HeapObject>(number_initial_map, Map::kPrototypeOffset);
var_default = NumberToStringConstant();
var_holder = number_prototype;
+ var_holder_map = LoadMap(number_prototype);
Goto(&checkstringtag);
}
@@ -884,54 +846,6 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
Return(UndefinedToStringConstant());
}
- BIND(&if_proxy);
- {
- // Check if the proxy has been revoked.
- Label throw_proxy_handler_revoked(this, Label::kDeferred);
- TNode<HeapObject> handler = CAST(LoadObjectField(
- TNode<JSProxy>::UncheckedCast(receiver), JSProxy::kHandlerOffset));
- CSA_DCHECK(this, IsNullOrJSReceiver(handler));
- GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
-
- // If {receiver} is a proxy for a JSArray, we default to "[object Array]",
- // otherwise we default to "[object Object]" or "[object Function]" here,
- // depending on whether the {receiver} is callable. The order matters here,
- // i.e. we need to execute the %ArrayIsArray check before the [[Get]] below,
- // as the exception is observable.
- TNode<Object> receiver_is_array =
- CallRuntime(Runtime::kArrayIsArray, context, receiver);
- TNode<String> builtin_tag = Select<String>(
- IsTrue(receiver_is_array), [=] { return ArrayStringConstant(); },
- [=] {
- return Select<String>(
- IsCallableMap(receiver_map),
- [=] { return FunctionStringConstant(); },
- [=] { return ObjectStringConstant(); });
- });
-
- // Lookup the @@toStringTag property on the {receiver}.
- TVARIABLE(Object, var_tag,
- GetProperty(context, receiver,
- isolate()->factory()->to_string_tag_symbol()));
- Label if_tagisnotstring(this), if_tagisstring(this);
- GotoIf(TaggedIsSmi(var_tag.value()), &if_tagisnotstring);
- Branch(IsString(CAST(var_tag.value())), &if_tagisstring,
- &if_tagisnotstring);
- BIND(&if_tagisnotstring);
- {
- var_tag = builtin_tag;
- Goto(&if_tagisstring);
- }
- BIND(&if_tagisstring);
- ReturnToStringFormat(context, CAST(var_tag.value()));
-
- BIND(&throw_proxy_handler_revoked);
- {
- ThrowTypeError(context, MessageTemplate::kProxyRevoked,
- "Object.prototype.toString");
- }
- }
-
BIND(&if_regexp);
{
var_default = RegexpToStringConstant();
@@ -949,6 +863,7 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
LoadObjectField<HeapObject>(string_initial_map, Map::kPrototypeOffset);
var_default = StringToStringConstant();
var_holder = string_prototype;
+ var_holder_map = LoadMap(string_prototype);
Goto(&checkstringtag);
}
@@ -963,6 +878,7 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
LoadObjectField<HeapObject>(symbol_initial_map, Map::kPrototypeOffset);
var_default = ObjectToStringConstant();
var_holder = symbol_prototype;
+ var_holder_map = LoadMap(symbol_prototype);
Goto(&checkstringtag);
}
@@ -977,6 +893,7 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
LoadObjectField<HeapObject>(bigint_initial_map, Map::kPrototypeOffset);
var_default = ObjectToStringConstant();
var_holder = bigint_prototype;
+ var_holder_map = LoadMap(bigint_prototype);
Goto(&checkstringtag);
}
@@ -992,7 +909,6 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
LoadJSPrimitiveWrapperValue(CAST(receiver_heap_object));
// We need to start with the object to see if the value was a subclass
// which might have interesting properties.
- var_holder = receiver_heap_object;
GotoIf(TaggedIsSmi(receiver_value), &if_value_is_number);
TNode<Map> receiver_value_map = LoadMap(CAST(receiver_value));
GotoIf(IsHeapNumberMap(receiver_value_map), &if_value_is_number);
@@ -1041,27 +957,48 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
// Check if all relevant maps (including the prototype maps) don't
// have any interesting symbols (i.e. that none of them have the
// @@toStringTag property).
- Label loop(this, &var_holder), return_default(this),
+ Label loop(this, {&var_holder, &var_holder_map}), return_default(this),
return_generic(this, Label::kDeferred);
Goto(&loop);
BIND(&loop);
{
+ Label interesting_symbols(this);
TNode<HeapObject> holder = var_holder.value();
+ TNode<Map> holder_map = var_holder_map.value();
GotoIf(IsNull(holder), &return_default);
- TNode<Map> holder_map = LoadMap(holder);
TNode<Uint32T> holder_bit_field3 = LoadMapBitField3(holder_map);
GotoIf(IsSetWord32<Map::Bits3::MayHaveInterestingSymbolsBit>(
holder_bit_field3),
- &return_generic);
+ &interesting_symbols);
var_holder = LoadMapPrototype(holder_map);
+ var_holder_map = LoadMap(var_holder.value());
Goto(&loop);
+ BIND(&interesting_symbols);
+ {
+ // Check flags for dictionary objects.
+ GotoIf(IsClearWord32<Map::Bits3::IsDictionaryMapBit>(holder_bit_field3),
+ &return_generic);
+ GotoIf(
+ InstanceTypeEqual(LoadMapInstanceType(holder_map), JS_PROXY_TYPE),
+ &if_proxy);
+ TNode<Object> properties =
+ LoadObjectField(holder, JSObject::kPropertiesOrHashOffset);
+ CSA_DCHECK(this, TaggedIsNotSmi(properties));
+ // TODO(pthier): Support swiss dictionaries.
+ if constexpr (!V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
+ CSA_DCHECK(this, IsNameDictionary(CAST(properties)));
+ TNode<Smi> flags =
+ GetNameDictionaryFlags<NameDictionary>(CAST(properties));
+ GotoIf(IsSetSmi(flags,
+ NameDictionary::MayHaveInterestingSymbolsBit::kMask),
+ &return_generic);
+ var_holder = LoadMapPrototype(holder_map);
+ var_holder_map = LoadMap(var_holder.value());
+ }
+ Goto(&loop);
+ }
}
-#if V8_ENABLE_WEBASSEMBLY
- BIND(&if_wasm);
- ThrowTypeError(context, MessageTemplate::kWasmObjectsAreOpaque);
-#endif
-
BIND(&return_generic);
{
TNode<Object> tag = GetProperty(context, ToObject(context, receiver),
@@ -1074,6 +1011,57 @@ TF_BUILTIN(ObjectToString, ObjectBuiltinsAssembler) {
BIND(&return_default);
Return(var_default.value());
}
+
+ BIND(&if_proxy);
+ {
+ receiver_heap_object = var_holder.value();
+ receiver_map = var_holder_map.value();
+ // Check if the proxy has been revoked.
+ Label throw_proxy_handler_revoked(this, Label::kDeferred);
+ TNode<HeapObject> handler =
+ CAST(LoadObjectField(receiver_heap_object, JSProxy::kHandlerOffset));
+ CSA_DCHECK(this, IsNullOrJSReceiver(handler));
+ GotoIfNot(JSAnyIsNotPrimitive(handler), &throw_proxy_handler_revoked);
+
+ // If {receiver_heap_object} is a proxy for a JSArray, we default to
+ // "[object Array]", otherwise we default to "[object Object]" or "[object
+ // Function]" here, depending on whether the {receiver_heap_object} is
+ // callable. The order matters here, i.e. we need to execute the
+ // %ArrayIsArray check before the [[Get]] below, as the exception is
+ // observable.
+ TNode<Object> receiver_is_array =
+ CallRuntime(Runtime::kArrayIsArray, context, receiver_heap_object);
+ TNode<String> builtin_tag = Select<String>(
+ IsTrue(receiver_is_array), [=] { return ArrayStringConstant(); },
+ [=] {
+ return Select<String>(
+ IsCallableMap(receiver_map),
+ [=] { return FunctionStringConstant(); },
+ [=] { return ObjectStringConstant(); });
+ });
+
+ // Lookup the @@toStringTag property on the {receiver_heap_object}.
+ TVARIABLE(Object, var_tag,
+ GetProperty(context, receiver_heap_object,
+ isolate()->factory()->to_string_tag_symbol()));
+ Label if_tagisnotstring(this), if_tagisstring(this);
+ GotoIf(TaggedIsSmi(var_tag.value()), &if_tagisnotstring);
+ Branch(IsString(CAST(var_tag.value())), &if_tagisstring,
+ &if_tagisnotstring);
+ BIND(&if_tagisnotstring);
+ {
+ var_tag = builtin_tag;
+ Goto(&if_tagisstring);
+ }
+ BIND(&if_tagisstring);
+ ReturnToStringFormat(context, CAST(var_tag.value()));
+
+ BIND(&throw_proxy_handler_revoked);
+ {
+ ThrowTypeError(context, MessageTemplate::kProxyRevoked,
+ "Object.prototype.toString");
+ }
+ }
}
// ES #sec-object.create
@@ -1131,7 +1119,7 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
BIND(&null_proto);
{
map = LoadSlowObjectWithNullPrototypeMap(native_context);
- if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
+ if constexpr (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
new_properties =
AllocateSwissNameDictionary(SwissNameDictionary::kInitialCapacity);
} else {
@@ -1319,6 +1307,67 @@ TF_BUILTIN(CreateGeneratorObject, ObjectBuiltinsAssembler) {
}
}
+TF_BUILTIN(OrdinaryGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
+ auto context = Parameter<Context>(Descriptor::kContext);
+ auto object = Parameter<JSReceiver>(Descriptor::kReceiver);
+ auto name = Parameter<Name>(Descriptor::kKey);
+ CSA_DCHECK(this, Word32BinaryNot(IsSpecialReceiverInstanceType(
+ LoadMapInstanceType(LoadMap(object)))));
+
+ Label if_notunique_name(this), if_iskeyunique(this), done(this),
+ if_keyisindex(this), call_runtime(this);
+
+ TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
+ TVARIABLE(Name, var_name, name);
+ TVARIABLE(HeapObject, result, UndefinedConstant());
+
+ TryToName(name, &if_keyisindex, &var_index, &if_iskeyunique, &var_name,
+ &call_runtime, &if_notunique_name);
+
+ BIND(&if_notunique_name);
+ {
+ Label not_in_string_table(this);
+ // If the string was not found in the string table, then no regular
+ // object can have a property with that name, so return |undefined|.
+ TryInternalizeString(CAST(name), &if_keyisindex, &var_index,
+ &if_iskeyunique, &var_name, &done, &call_runtime);
+ }
+
+ BIND(&if_iskeyunique);
+ {
+ Label if_found_value(this), if_not_found(this);
+
+ TVARIABLE(Object, var_value);
+ TVARIABLE(Uint32T, var_details);
+ TVARIABLE(Object, var_raw_value);
+ TNode<Map> map = LoadMap(object);
+ TNode<Int32T> instance_type = LoadMapInstanceType(map);
+
+ TryGetOwnProperty(context, object, object, map, instance_type,
+ var_name.value(), &if_found_value, &var_value,
+ &var_details, &var_raw_value, &done, &call_runtime,
+ kReturnAccessorPair);
+
+ BIND(&if_found_value);
+
+ // 4. Return FromPropertyDetails(desc).
+ result = AllocatePropertyDescriptorObject(context);
+ InitializePropertyDescriptorObject(CAST(result.value()), var_value.value(),
+ var_details.value(), &call_runtime);
+ Goto(&done);
+ }
+
+ BIND(&done);
+ Return(result.value());
+
+ BIND(&if_keyisindex);
+ Goto(&call_runtime);
+
+ BIND(&call_runtime);
+ TailCallRuntime(Runtime::kGetOwnPropertyDescriptorObject, context, object,
+ var_name.value());
+}
+
// ES6 section 19.1.2.7 Object.getOwnPropertyDescriptor ( O, P )
TF_BUILTIN(ObjectGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
auto argc = UncheckedParameter<Int32T>(Descriptor::kJSActualArgumentsCount);
@@ -1336,81 +1385,13 @@ TF_BUILTIN(ObjectGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
key = CallBuiltin(Builtin::kToName, context, key);
// 3. Let desc be ? obj.[[GetOwnProperty]](key).
- Label if_keyisindex(this), if_iskeyunique(this),
- call_runtime(this, Label::kDeferred),
- return_undefined(this, Label::kDeferred), if_notunique_name(this);
+ TNode<Object> desc =
+ CallBuiltin(Builtin::kGetOwnPropertyDescriptor, context, object, key);
- TNode<Map> map = LoadMap(object);
- TNode<Uint16T> instance_type = LoadMapInstanceType(map);
- GotoIf(IsSpecialReceiverInstanceType(instance_type), &call_runtime);
- {
- TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
- TVARIABLE(Name, var_name);
-
- TryToName(key, &if_keyisindex, &var_index, &if_iskeyunique, &var_name,
- &call_runtime, &if_notunique_name);
+ // 4. Return FromPropertyDescriptor(desc).
+ TNode<HeapObject> result = FromPropertyDescriptor(context, desc);
- BIND(&if_notunique_name);
- {
- Label not_in_string_table(this);
- TryInternalizeString(CAST(key), &if_keyisindex, &var_index,
- &if_iskeyunique, &var_name, &not_in_string_table,
- &call_runtime);
-
- BIND(&not_in_string_table);
- {
- // If the string was not found in the string table, then no regular
- // object can have a property with that name, so return |undefined|.
- Goto(&return_undefined);
- }
- }
-
- BIND(&if_iskeyunique);
- {
- Label if_found_value(this), return_empty(this), if_not_found(this);
-
- TVARIABLE(Object, var_value);
- TVARIABLE(Uint32T, var_details);
- TVARIABLE(Object, var_raw_value);
-
- TryGetOwnProperty(context, object, object, map, instance_type,
- var_name.value(), &if_found_value, &var_value,
- &var_details, &var_raw_value, &return_empty,
- &if_not_found, kReturnAccessorPair);
-
- BIND(&if_found_value);
- // 4. Return FromPropertyDetails(desc).
- TNode<JSObject> js_desc = FromPropertyDetails(
- context, var_value.value(), var_details.value(), &call_runtime);
- args.PopAndReturn(js_desc);
-
- BIND(&return_empty);
- var_value = UndefinedConstant();
- args.PopAndReturn(UndefinedConstant());
-
- BIND(&if_not_found);
- Goto(&call_runtime);
- }
- }
-
- BIND(&if_keyisindex);
- Goto(&call_runtime);
-
- BIND(&call_runtime);
- {
- TNode<Object> desc =
- CallRuntime(Runtime::kGetOwnPropertyDescriptor, context, object, key);
-
- GotoIf(IsUndefined(desc), &return_undefined);
-
- TNode<PropertyDescriptorObject> desc_object = CAST(desc);
-
- // 4. Return FromPropertyDescriptor(desc).
- TNode<JSObject> js_desc = FromPropertyDescriptor(context, desc_object);
- args.PopAndReturn(js_desc);
- }
- BIND(&return_undefined);
- args.PopAndReturn(UndefinedConstant());
+ args.PopAndReturn(result);
}
// TODO(v8:11167) remove remove |context| and |object| parameters once
@@ -1533,6 +1514,24 @@ TNode<JSObject> ObjectBuiltinsAssembler::FromPropertyDescriptor(
return js_descriptor.value();
}
+TNode<HeapObject> ObjectBuiltinsAssembler::FromPropertyDescriptor(
+ TNode<Context> context, TNode<Object> desc) {
+ CSA_DCHECK(this, TaggedIsNotSmi(desc));
+
+ if (IsUndefinedConstant(desc)) return UndefinedConstant();
+
+ Label done(this);
+ TVARIABLE(HeapObject, result, UndefinedConstant());
+ GotoIf(IsUndefined(desc), &done);
+
+ TNode<PropertyDescriptorObject> property_descriptor = CAST(desc);
+ result = FromPropertyDescriptor(context, property_descriptor);
+ Goto(&done);
+
+ BIND(&done);
+ return result.value();
+}
+
TNode<JSObject> ObjectBuiltinsAssembler::FromPropertyDetails(
TNode<Context> context, TNode<Object> raw_value, TNode<Word32T> details,
Label* if_bailout) {