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.cc178
1 files changed, 166 insertions, 12 deletions
diff --git a/deps/v8/src/builtins/builtins-object-gen.cc b/deps/v8/src/builtins/builtins-object-gen.cc
index be83f5d1ef..6173bb79ab 100644
--- a/deps/v8/src/builtins/builtins-object-gen.cc
+++ b/deps/v8/src/builtins/builtins-object-gen.cc
@@ -54,11 +54,13 @@ TF_BUILTIN(ObjectHasOwnProperty, ObjectBuiltinsAssembler) {
Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext);
- Label call_runtime(this), return_true(this), return_false(this);
+ Label call_runtime(this), return_true(this), return_false(this),
+ to_primitive(this);
- // Smi receivers do not have own properties.
+ // Smi receivers do not have own properties, just perform ToPrimitive on the
+ // key.
Label if_objectisnotsmi(this);
- Branch(TaggedIsSmi(object), &return_false, &if_objectisnotsmi);
+ Branch(TaggedIsSmi(object), &to_primitive, &if_objectisnotsmi);
BIND(&if_objectisnotsmi);
Node* map = LoadMap(object);
@@ -68,20 +70,44 @@ TF_BUILTIN(ObjectHasOwnProperty, ObjectBuiltinsAssembler) {
VARIABLE(var_index, MachineType::PointerRepresentation());
VARIABLE(var_unique, MachineRepresentation::kTagged);
- Label keyisindex(this), if_iskeyunique(this);
- TryToName(key, &keyisindex, &var_index, &if_iskeyunique, &var_unique,
- &call_runtime);
+ Label if_index(this), if_unique_name(this), if_notunique_name(this);
+ TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique,
+ &call_runtime, &if_notunique_name);
- BIND(&if_iskeyunique);
+ BIND(&if_unique_name);
TryHasOwnProperty(object, map, instance_type, var_unique.value(),
&return_true, &return_false, &call_runtime);
- BIND(&keyisindex);
- // Handle negative keys in the runtime.
- GotoIf(IntPtrLessThan(var_index.value(), IntPtrConstant(0)), &call_runtime);
- TryLookupElement(object, map, instance_type, var_index.value(),
- &return_true, &return_false, &return_false, &call_runtime);
+ BIND(&if_index);
+ {
+ // Handle negative keys in the runtime.
+ GotoIf(IntPtrLessThan(var_index.value(), IntPtrConstant(0)),
+ &call_runtime);
+ TryLookupElement(object, map, instance_type, var_index.value(),
+ &return_true, &return_false, &return_false,
+ &call_runtime);
+ }
+
+ BIND(&if_notunique_name);
+ {
+ Label not_in_string_table(this);
+ TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
+ &var_unique, &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 |false|.
+ // "Special API objects" with interceptors must take the slow path.
+ Branch(IsSpecialReceiverInstanceType(instance_type), &call_runtime,
+ &return_false);
+ }
+ }
}
+ BIND(&to_primitive);
+ GotoIf(IsNumber(key), &return_false);
+ Branch(IsName(key), &return_false, &call_runtime);
+
BIND(&return_true);
Return(BooleanConstant(true));
@@ -92,6 +118,88 @@ TF_BUILTIN(ObjectHasOwnProperty, ObjectBuiltinsAssembler) {
Return(CallRuntime(Runtime::kObjectHasOwnProperty, context, object, key));
}
+// ES #sec-object.keys
+TF_BUILTIN(ObjectKeys, ObjectBuiltinsAssembler) {
+ Node* object = Parameter(Descriptor::kObject);
+ Node* context = Parameter(Descriptor::kContext);
+
+ 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);
+
+ // Check if the {object} has a usable enum cache.
+ GotoIf(TaggedIsSmi(object), &if_slow);
+ Node* object_map = LoadMap(object);
+ Node* object_bit_field3 = LoadMapBitField3(object_map);
+ Node* object_enum_length =
+ DecodeWordFromWord32<Map::EnumLengthBits>(object_bit_field3);
+ GotoIf(
+ WordEqual(object_enum_length, IntPtrConstant(kInvalidEnumCacheSentinel)),
+ &if_slow);
+
+ // 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);
+ 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);
+
+ // Allocate a JSArray and copy the elements from the {object_enum_cache}.
+ Node* array = nullptr;
+ Node* elements = nullptr;
+ Node* native_context = LoadNativeContext(context);
+ Node* array_map = LoadJSArrayElementsMap(FAST_ELEMENTS, native_context);
+ Node* array_length = SmiTag(object_enum_length);
+ std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
+ FAST_ELEMENTS, array_map, array_length, nullptr, object_enum_length,
+ INTPTR_PARAMETERS);
+ StoreMapNoWriteBarrier(elements, Heap::kFixedArrayMapRootIndex);
+ StoreObjectFieldNoWriteBarrier(elements, FixedArray::kLengthOffset,
+ array_length);
+ CopyFixedArrayElements(FAST_ELEMENTS, object_enum_cache, elements,
+ object_enum_length, SKIP_WRITE_BARRIER);
+ Return(array);
+ }
+
+ BIND(&if_empty);
+ {
+ // The {object} doesn't have any enumerable keys.
+ var_length.Bind(SmiConstant(0));
+ var_elements.Bind(EmptyFixedArrayConstant());
+ Goto(&if_join);
+ }
+
+ BIND(&if_slow);
+ {
+ // Let the runtime compute the elements.
+ Node* elements = CallRuntime(Runtime::kObjectKeys, context, object);
+ var_length.Bind(LoadObjectField(elements, FixedArray::kLengthOffset));
+ var_elements.Bind(elements);
+ Goto(&if_join);
+ }
+
+ BIND(&if_join);
+ {
+ // Wrap the elements into a proper JSArray and return that.
+ Node* native_context = LoadNativeContext(context);
+ Node* array_map = LoadJSArrayElementsMap(FAST_ELEMENTS, native_context);
+ Node* array = AllocateUninitializedJSArrayWithoutElements(
+ FAST_ELEMENTS, array_map, var_length.value(), nullptr);
+ StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset,
+ var_elements.value());
+ Return(array);
+ }
+}
+
// ES6 #sec-object.prototype.tostring
TF_BUILTIN(ObjectProtoToString, ObjectBuiltinsAssembler) {
Label return_undefined(this, Label::kDeferred),
@@ -400,5 +508,51 @@ TF_BUILTIN(GetSuperConstructor, ObjectBuiltinsAssembler) {
Return(GetSuperConstructor(object, context));
}
+TF_BUILTIN(CreateGeneratorObject, ObjectBuiltinsAssembler) {
+ Node* closure = Parameter(Descriptor::kClosure);
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* context = Parameter(Descriptor::kContext);
+
+ // Get the initial map from the function, jumping to the runtime if we don't
+ // have one.
+ Node* maybe_map =
+ LoadObjectField(closure, JSFunction::kPrototypeOrInitialMapOffset);
+ Label runtime(this);
+ GotoIf(DoesntHaveInstanceType(maybe_map, MAP_TYPE), &runtime);
+
+ Node* shared =
+ LoadObjectField(closure, JSFunction::kSharedFunctionInfoOffset);
+ Node* bytecode_array =
+ LoadObjectField(shared, SharedFunctionInfo::kFunctionDataOffset);
+ Node* frame_size = ChangeInt32ToIntPtr(LoadObjectField(
+ bytecode_array, BytecodeArray::kFrameSizeOffset, MachineType::Int32()));
+ Node* size = WordSar(frame_size, IntPtrConstant(kPointerSizeLog2));
+ Node* register_file = AllocateFixedArray(FAST_HOLEY_ELEMENTS, size);
+ FillFixedArrayWithValue(FAST_HOLEY_ELEMENTS, register_file, IntPtrConstant(0),
+ size, Heap::kUndefinedValueRootIndex);
+
+ Node* const result = AllocateJSObjectFromMap(maybe_map);
+
+ StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kFunctionOffset,
+ closure);
+ StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kContextOffset,
+ context);
+ StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kReceiverOffset,
+ receiver);
+ StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kRegisterFileOffset,
+ register_file);
+ Node* executing = SmiConstant(JSGeneratorObject::kGeneratorExecuting);
+ StoreObjectFieldNoWriteBarrier(result, JSGeneratorObject::kContinuationOffset,
+ executing);
+ HandleSlackTracking(context, result, maybe_map, JSGeneratorObject::kSize);
+ Return(result);
+
+ BIND(&runtime);
+ {
+ Return(CallRuntime(Runtime::kCreateJSGeneratorObject, context, closure,
+ receiver));
+ }
+}
+
} // namespace internal
} // namespace v8