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.cc222
1 files changed, 212 insertions, 10 deletions
diff --git a/deps/v8/src/builtins/builtins-object-gen.cc b/deps/v8/src/builtins/builtins-object-gen.cc
index 18d2434b88..b1af0cf8ab 100644
--- a/deps/v8/src/builtins/builtins-object-gen.cc
+++ b/deps/v8/src/builtins/builtins-object-gen.cc
@@ -5,6 +5,9 @@
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h"
+#include "src/factory-inl.h"
+#include "src/objects/property-descriptor-object.h"
+#include "src/objects/shared-function-info.h"
namespace v8 {
namespace internal {
@@ -21,6 +24,9 @@ class ObjectBuiltinsAssembler : public CodeStubAssembler {
protected:
void ReturnToStringFormat(Node* context, Node* string);
+ void AddToDictionaryIf(Node* condition, Node* name_dictionary,
+ Handle<Name> name, Node* value, Label* bailout);
+ Node* FromPropertyDescriptor(Node* context, Node* desc);
};
void ObjectBuiltinsAssembler::ReturnToStringFormat(Node* context,
@@ -111,8 +117,8 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
VARIABLE(var_length, MachineRepresentation::kTagged);
VARIABLE(var_elements, MachineRepresentation::kTagged);
- Label if_empty(this, Label::kDeferred), if_fast(this),
- if_slow(this, Label::kDeferred), if_join(this);
+ Label if_empty(this, Label::kDeferred), if_empty_elements(this),
+ if_fast(this), if_slow(this, Label::kDeferred), if_join(this);
// Check if the {object} has a usable enum cache.
GotoIf(TaggedIsSmi(object), &if_slow);
@@ -127,19 +133,24 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
// Ensure that the {object} doesn't have any elements.
CSA_ASSERT(this, IsJSObjectMap(object_map));
Node* object_elements = LoadObjectField(object, JSObject::kElementsOffset);
- GotoIfNot(IsEmptyFixedArray(object_elements), &if_slow);
+ GotoIf(IsEmptyFixedArray(object_elements), &if_empty_elements);
+ Branch(IsEmptySlowElementDictionary(object_elements), &if_empty_elements,
+ &if_slow);
+
+ // Check whether there are enumerable properties.
+ BIND(&if_empty_elements);
Branch(WordEqual(object_enum_length, IntPtrConstant(0)), &if_empty, &if_fast);
BIND(&if_fast);
{
// The {object} has a usable enum cache, use that.
Node* object_descriptors = LoadMapDescriptors(object_map);
- Node* object_enum_cache_bridge = LoadObjectField(
- object_descriptors, DescriptorArray::kEnumCacheBridgeOffset);
- Node* object_enum_cache = LoadObjectField(
- object_enum_cache_bridge, DescriptorArray::kEnumCacheBridgeCacheOffset);
+ Node* object_enum_cache =
+ LoadObjectField(object_descriptors, DescriptorArray::kEnumCacheOffset);
+ Node* object_enum_keys =
+ LoadObjectField(object_enum_cache, EnumCache::kKeysOffset);
- // Allocate a JSArray and copy the elements from the {object_enum_cache}.
+ // Allocate a JSArray and copy the elements from the {object_enum_keys}.
Node* array = nullptr;
Node* elements = nullptr;
Node* native_context = LoadNativeContext(context);
@@ -148,7 +159,7 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
PACKED_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
INTPTR_PARAMETERS);
- CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_cache, elements,
+ CopyFixedArrayElements(PACKED_ELEMENTS, object_enum_keys, elements,
object_enum_length, SKIP_WRITE_BARRIER);
Return(array);
}
@@ -176,7 +187,7 @@ TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
Node* native_context = LoadNativeContext(context);
Node* array_map = LoadJSArrayElementsMap(PACKED_ELEMENTS, native_context);
Node* array = AllocateUninitializedJSArrayWithoutElements(
- PACKED_ELEMENTS, array_map, var_length.value(), nullptr);
+ array_map, var_length.value(), nullptr);
StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset,
var_elements.value());
Return(array);
@@ -587,6 +598,21 @@ TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) {
}
}
+// ES #sec-object.is
+TF_BUILTIN(ObjectIs, ObjectBuiltinsAssembler) {
+ Node* const left = Parameter(Descriptor::kLeft);
+ Node* const right = Parameter(Descriptor::kRight);
+
+ Label return_true(this), return_false(this);
+ BranchIfSameValue(left, right, &return_true, &return_false);
+
+ BIND(&return_true);
+ Return(TrueConstant());
+
+ BIND(&return_false);
+ Return(FalseConstant());
+}
+
TF_BUILTIN(CreateIterResultObject, ObjectBuiltinsAssembler) {
Node* const value = Parameter(Descriptor::kValue);
Node* const done = Parameter(Descriptor::kDone);
@@ -682,5 +708,181 @@ TF_BUILTIN(CreateGeneratorObject, ObjectBuiltinsAssembler) {
}
}
+// ES6 section 19.1.2.7 Object.getOwnPropertyDescriptor ( O, P )
+TF_BUILTIN(ObjectGetOwnPropertyDescriptor, ObjectBuiltinsAssembler) {
+ Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount);
+ Node* context = Parameter(BuiltinDescriptor::kContext);
+ CSA_ASSERT(this, WordEqual(Parameter(BuiltinDescriptor::kNewTarget),
+ UndefinedConstant()));
+
+ CodeStubArguments args(this, ChangeInt32ToIntPtr(argc));
+ Node* obj = args.GetOptionalArgumentValue(0);
+ Node* key = args.GetOptionalArgumentValue(1);
+
+ // 1. Let obj be ? ToObject(O).
+ Node* object = CallBuiltin(Builtins::kToObject, context, obj);
+
+ // 2. Let key be ? ToPropertyKey(P).
+ Node* name = ToName(context, key);
+
+ // 3. Let desc be ? obj.[[GetOwnProperty]](key).
+ Node* desc =
+ CallRuntime(Runtime::kGetOwnPropertyDescriptor, context, object, name);
+
+ Label return_undefined(this, Label::kDeferred);
+ GotoIf(IsUndefined(desc), &return_undefined);
+
+ CSA_ASSERT(this, IsFixedArray(desc));
+
+ // 4. Return FromPropertyDescriptor(desc).
+ args.PopAndReturn(FromPropertyDescriptor(context, desc));
+
+ BIND(&return_undefined);
+ args.PopAndReturn(UndefinedConstant());
+}
+
+void ObjectBuiltinsAssembler::AddToDictionaryIf(Node* condition,
+ Node* name_dictionary,
+ Handle<Name> name, Node* value,
+ Label* bailout) {
+ Label done(this);
+ GotoIfNot(condition, &done);
+
+ Add<NameDictionary>(name_dictionary, HeapConstant(name), value, bailout);
+ Goto(&done);
+
+ BIND(&done);
+}
+
+Node* ObjectBuiltinsAssembler::FromPropertyDescriptor(Node* context,
+ Node* desc) {
+ VARIABLE(js_descriptor, MachineRepresentation::kTagged);
+
+ Node* flags = LoadAndUntagToWord32ObjectField(
+ desc, PropertyDescriptorObject::kFlagsOffset);
+
+ Node* has_flags =
+ Word32And(flags, Int32Constant(PropertyDescriptorObject::kHasMask));
+
+ Label if_accessor_desc(this), if_data_desc(this), if_generic_desc(this),
+ return_desc(this);
+ GotoIf(
+ Word32Equal(has_flags,
+ Int32Constant(
+ PropertyDescriptorObject::kRegularAccessorPropertyBits)),
+ &if_accessor_desc);
+ GotoIf(Word32Equal(
+ has_flags,
+ Int32Constant(PropertyDescriptorObject::kRegularDataPropertyBits)),
+ &if_data_desc);
+ Goto(&if_generic_desc);
+
+ BIND(&if_accessor_desc);
+ {
+ Node* native_context = LoadNativeContext(context);
+ Node* map = LoadContextElement(
+ native_context, Context::ACCESSOR_PROPERTY_DESCRIPTOR_MAP_INDEX);
+ Node* js_desc = AllocateJSObjectFromMap(map);
+
+ StoreObjectFieldNoWriteBarrier(
+ js_desc, JSAccessorPropertyDescriptor::kGetOffset,
+ LoadObjectField(desc, PropertyDescriptorObject::kGetOffset));
+ StoreObjectFieldNoWriteBarrier(
+ js_desc, JSAccessorPropertyDescriptor::kSetOffset,
+ LoadObjectField(desc, PropertyDescriptorObject::kSetOffset));
+ StoreObjectFieldNoWriteBarrier(
+ js_desc, JSAccessorPropertyDescriptor::kEnumerableOffset,
+ SelectBooleanConstant(
+ IsSetWord32<PropertyDescriptorObject::IsEnumerableBit>(flags)));
+ StoreObjectFieldNoWriteBarrier(
+ js_desc, JSAccessorPropertyDescriptor::kConfigurableOffset,
+ SelectBooleanConstant(
+ IsSetWord32<PropertyDescriptorObject::IsConfigurableBit>(flags)));
+
+ js_descriptor.Bind(js_desc);
+ Goto(&return_desc);
+ }
+
+ BIND(&if_data_desc);
+ {
+ Node* native_context = LoadNativeContext(context);
+ Node* map = LoadContextElement(native_context,
+ Context::DATA_PROPERTY_DESCRIPTOR_MAP_INDEX);
+ Node* js_desc = AllocateJSObjectFromMap(map);
+
+ StoreObjectFieldNoWriteBarrier(
+ js_desc, JSDataPropertyDescriptor::kValueOffset,
+ LoadObjectField(desc, PropertyDescriptorObject::kValueOffset));
+ StoreObjectFieldNoWriteBarrier(
+ js_desc, JSDataPropertyDescriptor::kWritableOffset,
+ SelectBooleanConstant(
+ IsSetWord32<PropertyDescriptorObject::IsWritableBit>(flags)));
+ StoreObjectFieldNoWriteBarrier(
+ js_desc, JSDataPropertyDescriptor::kEnumerableOffset,
+ SelectBooleanConstant(
+ IsSetWord32<PropertyDescriptorObject::IsEnumerableBit>(flags)));
+ StoreObjectFieldNoWriteBarrier(
+ js_desc, JSDataPropertyDescriptor::kConfigurableOffset,
+ SelectBooleanConstant(
+ IsSetWord32<PropertyDescriptorObject::IsConfigurableBit>(flags)));
+
+ js_descriptor.Bind(js_desc);
+ Goto(&return_desc);
+ }
+
+ BIND(&if_generic_desc);
+ {
+ Node* native_context = LoadNativeContext(context);
+ Node* map = LoadContextElement(
+ native_context, Context::SLOW_OBJECT_WITH_OBJECT_PROTOTYPE_MAP);
+ // We want to preallocate the slots for value, writable, get, set,
+ // enumerable and configurable - a total of 6
+ Node* properties = AllocateNameDictionary(6);
+ Node* js_desc = AllocateJSObjectFromMap(map, properties);
+
+ Label bailout(this, Label::kDeferred);
+
+ Factory* factory = isolate()->factory();
+ Node* value = LoadObjectField(desc, PropertyDescriptorObject::kValueOffset);
+ AddToDictionaryIf(IsNotTheHole(value), properties, factory->value_string(),
+ value, &bailout);
+ AddToDictionaryIf(
+ IsSetWord32<PropertyDescriptorObject::HasWritableBit>(flags),
+ properties, factory->writable_string(),
+ SelectBooleanConstant(
+ IsSetWord32<PropertyDescriptorObject::IsWritableBit>(flags)),
+ &bailout);
+
+ Node* get = LoadObjectField(desc, PropertyDescriptorObject::kGetOffset);
+ AddToDictionaryIf(IsNotTheHole(get), properties, factory->get_string(), get,
+ &bailout);
+ Node* set = LoadObjectField(desc, PropertyDescriptorObject::kSetOffset);
+ AddToDictionaryIf(IsNotTheHole(set), properties, factory->set_string(), set,
+ &bailout);
+
+ AddToDictionaryIf(
+ IsSetWord32<PropertyDescriptorObject::HasEnumerableBit>(flags),
+ properties, factory->enumerable_string(),
+ SelectBooleanConstant(
+ IsSetWord32<PropertyDescriptorObject::IsEnumerableBit>(flags)),
+ &bailout);
+ AddToDictionaryIf(
+ IsSetWord32<PropertyDescriptorObject::HasConfigurableBit>(flags),
+ properties, factory->configurable_string(),
+ SelectBooleanConstant(
+ IsSetWord32<PropertyDescriptorObject::IsConfigurableBit>(flags)),
+ &bailout);
+
+ js_descriptor.Bind(js_desc);
+ Goto(&return_desc);
+
+ BIND(&bailout);
+ CSA_ASSERT(this, Int32Constant(0));
+ Unreachable();
+ }
+
+ BIND(&return_desc);
+ return js_descriptor.value();
+}
} // namespace internal
} // namespace v8