diff options
Diffstat (limited to 'deps/v8/src/builtins/builtins-object-gen.cc')
-rw-r--r-- | deps/v8/src/builtins/builtins-object-gen.cc | 383 |
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, ¬_in_string_table, - &call_runtime); - - BIND(¬_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) { |