Commit bc8f9a78 authored by verwaest's avatar verwaest Committed by Commit bot

Add initial code-stub version of Object.prototype.hasOwnProperty

It for now only deals with fast-mode smi and object arrays with smi
keys and internalized strings; and fast-mode named properties with an internalized key or symbol.

BUG=v8:2472
LOG=n

Review URL: https://codereview.chromium.org/1843613002

Cr-Commit-Position: refs/heads/master@{#35152}
parent a0aac3cb
......@@ -1082,7 +1082,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
false);
SimpleInstallFunction(isolate->initial_object_prototype(), "hasOwnProperty",
Builtins::kObjectHasOwnProperty, 1, false);
Builtins::kObjectHasOwnProperty, 1, true);
}
Handle<JSObject> global(native_context()->global_object());
......
This diff is collapsed.
......@@ -134,7 +134,6 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(ObjectGetOwnPropertyDescriptor, kNone) \
V(ObjectGetOwnPropertyNames, kNone) \
V(ObjectGetOwnPropertySymbols, kNone) \
V(ObjectHasOwnProperty, kNone) \
V(ObjectIs, kNone) \
V(ObjectIsExtensible, kNone) \
V(ObjectIsFrozen, kNone) \
......@@ -312,7 +311,8 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(MathFloor, 2) \
V(MathRound, 2) \
V(MathSqrt, 2) \
V(MathTrunc, 2)
V(MathTrunc, 2) \
V(ObjectHasOwnProperty, 2)
// Define list of builtin handlers implemented in assembly.
#define BUILTIN_LIST_H(V) \
......@@ -611,6 +611,10 @@ class Builtins {
// ES6 section 20.1.1.1 Number ( [ value ] ) for the [[Construct]] case.
static void Generate_NumberConstructor_ConstructStub(MacroAssembler* masm);
// ES6 section 19.1.3.2 Object.prototype.hasOwnProperty
static void Generate_ObjectHasOwnProperty(
compiler::CodeStubAssembler* assembler);
static void Generate_StringConstructor(MacroAssembler* masm);
static void Generate_StringConstructor_ConstructStub(MacroAssembler* masm);
static void Generate_OnStackReplacement(MacroAssembler* masm);
......
......@@ -458,11 +458,39 @@ Node* CodeStubAssembler::LoadMapBitField(Node* map) {
IntPtrConstant(Map::kBitFieldOffset - kHeapObjectTag));
}
Node* CodeStubAssembler::LoadMapBitField2(Node* map) {
return Load(MachineType::Uint8(), map,
IntPtrConstant(Map::kBitField2Offset - kHeapObjectTag));
}
Node* CodeStubAssembler::LoadMapBitField3(Node* map) {
return Load(MachineType::Uint32(), map,
IntPtrConstant(Map::kBitField3Offset - kHeapObjectTag));
}
Node* CodeStubAssembler::LoadMapInstanceType(Node* map) {
return Load(MachineType::Uint8(), map,
IntPtrConstant(Map::kInstanceTypeOffset - kHeapObjectTag));
}
Node* CodeStubAssembler::LoadMapDescriptors(Node* map) {
return LoadObjectField(map, Map::kDescriptorsOffset);
}
Node* CodeStubAssembler::LoadNameHash(Node* name) {
return Load(MachineType::Uint32(), name,
IntPtrConstant(Name::kHashFieldOffset - kHeapObjectTag));
}
Node* CodeStubAssembler::LoadFixedArrayElementInt32Index(
Node* object, Node* int32_index, int additional_offset) {
Node* header_size = IntPtrConstant(additional_offset +
FixedArray::kHeaderSize - kHeapObjectTag);
Node* scaled_index = WordShl(int32_index, IntPtrConstant(kPointerSizeLog2));
Node* offset = IntPtrAdd(scaled_index, header_size);
return Load(MachineType::AnyTagged(), object, offset);
}
Node* CodeStubAssembler::LoadFixedArrayElementSmiIndex(Node* object,
Node* smi_index,
int additional_offset) {
......@@ -691,6 +719,14 @@ Node* CodeStubAssembler::LoadInstanceType(Node* object) {
return LoadMapInstanceType(LoadMap(object));
}
Node* CodeStubAssembler::LoadElements(Node* object) {
return LoadObjectField(object, JSObject::kElementsOffset);
}
Node* CodeStubAssembler::LoadFixedArrayBaseLength(Node* array) {
return LoadObjectField(array, FixedArrayBase::kLengthOffset);
}
Node* CodeStubAssembler::BitFieldDecode(Node* word32, uint32_t shift,
uint32_t mask) {
return raw_assembler_->Word32Shr(
......
......@@ -310,10 +310,21 @@ class CodeStubAssembler {
Node* TruncateHeapNumberValueToWord32(Node* object);
// Load the bit field of a Map.
Node* LoadMapBitField(Node* map);
// Load the instance type of a Map.
// Load bit field 2 of a map.
Node* LoadMapBitField2(Node* map);
// Load bit field 3 of a map.
Node* LoadMapBitField3(Node* map);
// Load the instance type of a map.
Node* LoadMapInstanceType(Node* map);
// Load the instance descriptors of a map.
Node* LoadMapDescriptors(Node* map);
// Load the hash field of a name.
Node* LoadNameHash(Node* name);
// Load an array element from a FixedArray.
Node* LoadFixedArrayElementInt32Index(Node* object, Node* int32_index,
int additional_offset = 0);
Node* LoadFixedArrayElementSmiIndex(Node* object, Node* smi_index,
int additional_offset = 0);
Node* LoadFixedArrayElementConstantIndex(Node* object, int index);
......@@ -335,6 +346,11 @@ class CodeStubAssembler {
// Load the instance type of an HeapObject.
Node* LoadInstanceType(Node* object);
// Load the elements backing store of a JSObject.
Node* LoadElements(Node* object);
// Load the length of a fixed array base instance.
Node* LoadFixedArrayBaseLength(Node* array);
// Returns a node that is true if the given bit is set in |word32|.
template <typename T>
Node* BitFieldDecode(Node* word32) {
......
......@@ -3088,6 +3088,11 @@ class DescriptorArray: public FixedArray {
kDescriptorDetails;
}
// Conversion from descriptor number to array indices.
static int ToKeyIndex(int descriptor_number) {
return kFirstIndex + (descriptor_number * kDescriptorSize) + kDescriptorKey;
}
private:
// An entry in a DescriptorArray, represented as an (array, index) pair.
class Entry {
......@@ -3103,13 +3108,6 @@ class DescriptorArray: public FixedArray {
int index_;
};
// Conversion from descriptor number to array indices.
static int ToKeyIndex(int descriptor_number) {
return kFirstIndex +
(descriptor_number * kDescriptorSize) +
kDescriptorKey;
}
static int ToValueIndex(int descriptor_number) {
return kFirstIndex +
(descriptor_number * kDescriptorSize) +
......
......@@ -125,6 +125,82 @@ Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate,
return JSReceiver::DeleteProperty(&it, language_mode);
}
// ES6 19.1.3.2
RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) {
HandleScope scope(isolate);
Handle<Object> property = args.at<Object>(1);
Handle<Name> key;
uint32_t index;
bool key_is_array_index = property->ToArrayIndex(&index);
if (!key_is_array_index) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
Object::ToName(isolate, property));
key_is_array_index = key->AsArrayIndex(&index);
}
Handle<Object> object = args.at<Object>(0);
if (object->IsJSObject()) {
Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
// Fast case: either the key is a real named property or it is not
// an array index and there are no interceptors or hidden
// prototypes.
// TODO(jkummerow): Make JSReceiver::HasOwnProperty fast enough to
// handle all cases directly (without this custom fast path).
{
LookupIterator::Configuration c = LookupIterator::OWN_SKIP_INTERCEPTOR;
LookupIterator it =
key_is_array_index ? LookupIterator(isolate, js_obj, index, js_obj, c)
: LookupIterator(js_obj, key, js_obj, c);
Maybe<bool> maybe = JSReceiver::HasProperty(&it);
if (maybe.IsNothing()) return isolate->heap()->exception();
DCHECK(!isolate->has_pending_exception());
if (maybe.FromJust()) return isolate->heap()->true_value();
}
Map* map = js_obj->map();
if (!map->has_hidden_prototype() &&
(key_is_array_index ? !map->has_indexed_interceptor()
: !map->has_named_interceptor())) {
return isolate->heap()->false_value();
}
// Slow case.
LookupIterator::Configuration c = LookupIterator::HIDDEN;
LookupIterator it = key_is_array_index
? LookupIterator(isolate, js_obj, index, js_obj, c)
: LookupIterator(js_obj, key, js_obj, c);
Maybe<bool> maybe = JSReceiver::HasProperty(&it);
if (maybe.IsNothing()) return isolate->heap()->exception();
DCHECK(!isolate->has_pending_exception());
return isolate->heap()->ToBoolean(maybe.FromJust());
} else if (object->IsJSProxy()) {
if (key.is_null()) {
DCHECK(key_is_array_index);
key = isolate->factory()->Uint32ToString(index);
}
Maybe<bool> result =
JSReceiver::HasOwnProperty(Handle<JSProxy>::cast(object), key);
if (!result.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(result.FromJust());
} else if (object->IsString()) {
return isolate->heap()->ToBoolean(
key_is_array_index
? index < static_cast<uint32_t>(String::cast(*object)->length())
: key->Equals(isolate->heap()->length_string()));
} else if (object->IsNull() || object->IsUndefined()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject));
}
return isolate->heap()->false_value();
}
MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
Handle<Object> object,
......
......@@ -384,6 +384,7 @@ namespace internal {
#define FOR_EACH_INTRINSIC_OBJECT(F) \
F(GetPrototype, 1, 1) \
F(ObjectHasOwnProperty, 2, 1) \
F(InternalSetPrototype, 2, 1) \
F(SetPrototype, 2, 1) \
F(GetOwnProperty_Legacy, 2, 1) \
......
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