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

Move hasOwnProperty to builtins.cc

This gets rid of the JavaScript wrapper. That way we can more quickly handle non-JSReceivers and indexed properties; and don't need to optimize the JavaScript wrapper either.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#34356}
parent c7339e6e
......@@ -1121,6 +1121,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Builtins::kObjectPreventExtensions, 1, false);
SimpleInstallFunction(object_function, "seal", Builtins::kObjectSeal, 1,
false);
SimpleInstallFunction(isolate->initial_object_prototype(), "hasOwnProperty",
Builtins::kObjectHasOwnProperty, 1, false);
}
Handle<JSObject> global(native_context()->global_object());
......
......@@ -352,6 +352,83 @@ BUILTIN(Illegal) {
BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); }
// ES6 7.3.11
BUILTIN(ObjectHasOwnProperty) {
HandleScope scope(isolate);
Handle<Object> property = args.atOrUndefined(isolate, 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.receiver();
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, c)
: LookupIterator(js_obj, key, 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, c)
: LookupIterator(js_obj, key, 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();
}
BUILTIN(ArrayPush) {
HandleScope scope(isolate);
......
......@@ -128,6 +128,7 @@ 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) \
......
......@@ -35,6 +35,7 @@ var MakeTypeError;
var MathFloor;
var ObjectDefineProperties = utils.ImportNow("ObjectDefineProperties");
var ObjectDefineProperty = utils.ImportNow("ObjectDefineProperty");
var ObjectHasOwnProperty = utils.ImportNow("ObjectHasOwnProperty");
var patternSymbol = utils.ImportNow("intl_pattern_symbol");
var RegExpTest;
var resolvedSymbol = utils.ImportNow("intl_resolved_symbol");
......@@ -545,7 +546,7 @@ function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
}
for (var key in keyValues) {
if (%HasOwnProperty(keyValues, key)) {
if (HAS_OWN_PROPERTY(keyValues, key)) {
var value = UNDEFINED;
var map = keyValues[key];
if (!IS_UNDEFINED(map.property)) {
......@@ -561,7 +562,7 @@ function setOptions(inOptions, extensionMap, keyValues, getOption, outOptions) {
// User options didn't have it, check Unicode extension.
// Here we want to convert strings 'true', 'false' into proper Boolean
// values (not a user error).
if (%HasOwnProperty(extensionMap, key)) {
if (HAS_OWN_PROPERTY(extensionMap, key)) {
value = extensionMap[key];
if (!IS_UNDEFINED(value)) {
updateProperty(map.property, map.type, value);
......@@ -637,7 +638,7 @@ function getAvailableLocalesOf(service) {
var available = %AvailableLocalesOf(service);
for (var i in available) {
if (%HasOwnProperty(available, i)) {
if (HAS_OWN_PROPERTY(available, i)) {
var parts =
%_Call(StringMatch, i, /^([a-z]{2,3})-([A-Z][a-z]{3})-([A-Z]{2})$/);
if (parts !== null) {
......@@ -953,7 +954,7 @@ function initializeCollator(collator, locales, options) {
var collation = 'default';
var extension = '';
if (%HasOwnProperty(extensionMap, 'co') && internalOptions.usage === 'sort') {
if (HAS_OWN_PROPERTY(extensionMap, 'co') && internalOptions.usage === 'sort') {
/**
* Allowed -u-co- values. List taken from:
......@@ -1226,10 +1227,10 @@ function initializeNumberFormat(numberFormat, locales, options) {
style: {value: internalOptions.style, writable: true},
useGrouping: {writable: true}
});
if (%HasOwnProperty(internalOptions, 'minimumSignificantDigits')) {
if (HAS_OWN_PROPERTY(internalOptions, 'minimumSignificantDigits')) {
defineWEProperty(resolved, 'minimumSignificantDigits', UNDEFINED);
}
if (%HasOwnProperty(internalOptions, 'maximumSignificantDigits')) {
if (HAS_OWN_PROPERTY(internalOptions, 'maximumSignificantDigits')) {
defineWEProperty(resolved, 'maximumSignificantDigits', UNDEFINED);
}
var formatter = %CreateNumberFormat(requestedLocale,
......@@ -1301,12 +1302,12 @@ InstallFunction(Intl.NumberFormat.prototype, 'resolvedOptions', function() {
format[resolvedSymbol].currencyDisplay);
}
if (%HasOwnProperty(format[resolvedSymbol], 'minimumSignificantDigits')) {
if (HAS_OWN_PROPERTY(format[resolvedSymbol], 'minimumSignificantDigits')) {
defineWECProperty(result, 'minimumSignificantDigits',
format[resolvedSymbol].minimumSignificantDigits);
}
if (%HasOwnProperty(format[resolvedSymbol], 'maximumSignificantDigits')) {
if (HAS_OWN_PROPERTY(format[resolvedSymbol], 'maximumSignificantDigits')) {
defineWECProperty(result, 'maximumSignificantDigits',
format[resolvedSymbol].maximumSignificantDigits);
}
......@@ -1486,7 +1487,7 @@ function fromLDMLString(ldmlString) {
function appendToDateTimeObject(options, option, match, pairs) {
if (IS_NULL(match)) {
if (!%HasOwnProperty(options, option)) {
if (!HAS_OWN_PROPERTY(options, option)) {
defineWEProperty(options, option, UNDEFINED);
}
return options;
......
......@@ -122,12 +122,12 @@ macro TO_PRIMITIVE_NUMBER(arg) = (%_ToPrimitive_Number(arg));
macro TO_PRIMITIVE_STRING(arg) = (%_ToPrimitive_String(arg));
macro TO_NAME(arg) = (%_ToName(arg));
macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
macro HAS_OWN_PROPERTY(arg, index) = (%_Call(ObjectHasOwnProperty, arg, index));
macro HAS_OWN_PROPERTY(obj, key) = (%_Call(ObjectHasOwnProperty, obj, key));
macro HAS_INDEX(array, index, is_array) = ((is_array && %_HasFastPackedElements(%IS_VAR(array)) && (index < array.length)) || (index in array));
# Private names.
macro IS_PRIVATE(sym) = (%SymbolIsPrivate(sym));
macro HAS_PRIVATE(obj, sym) = (%HasOwnProperty(obj, sym));
macro HAS_PRIVATE(obj, key) = HAS_OWN_PROPERTY(obj, key);
macro HAS_DEFINED_PRIVATE(obj, sym) = (!IS_UNDEFINED(obj[sym]));
macro GET_PRIVATE(obj, sym) = (obj[sym]);
macro SET_PRIVATE(obj, sym, val) = (obj[sym] = val);
......
......@@ -34,6 +34,7 @@ var Int8x16ToString;
var InternalArray = utils.InternalArray;
var internalErrorSymbol = utils.ImportNow("internal_error_symbol");
var ObjectDefineProperty;
var ObjectHasOwnProperty;
var ObjectToString = utils.ImportNow("object_to_string");
var Script = utils.ImportNow("Script");
var stackTraceSymbol = utils.ImportNow("stack_trace_symbol");
......@@ -56,6 +57,7 @@ utils.Import(function(from) {
Int32x4ToString = from.Int32x4ToString;
Int8x16ToString = from.Int8x16ToString;
ObjectDefineProperty = from.ObjectDefineProperty;
ObjectHasOwnProperty = from.ObjectHasOwnProperty;
StringCharAt = from.StringCharAt;
StringIndexOf = from.StringIndexOf;
StringSubstring = from.StringSubstring;
......
......@@ -134,14 +134,6 @@ function ObjectValueOf() {
}
// ES6 7.3.11
function ObjectHasOwnProperty(value) {
var name = TO_NAME(value);
var object = TO_OBJECT(this);
return %HasOwnProperty(object, name);
}
// ES6 19.1.3.3 Object.prototype.isPrototypeOf(V)
function ObjectIsPrototypeOf(V) {
if (!IS_RECEIVER(V)) return false;
......@@ -850,7 +842,6 @@ utils.InstallFunctions(GlobalObject.prototype, DONT_ENUM, [
"toString", ObjectToString,
"toLocaleString", ObjectToLocaleString,
"valueOf", ObjectValueOf,
"hasOwnProperty", ObjectHasOwnProperty,
"isPrototypeOf", ObjectIsPrototypeOf,
"propertyIsEnumerable", ObjectPropertyIsEnumerable,
"__defineGetter__", ObjectDefineGetter,
......@@ -1108,7 +1099,7 @@ utils.Export(function(to) {
to.NumberIsNaN = NumberIsNaN;
to.ObjectDefineProperties = ObjectDefineProperties;
to.ObjectDefineProperty = ObjectDefineProperty;
to.ObjectHasOwnProperty = ObjectHasOwnProperty;
to.ObjectHasOwnProperty = GlobalObject.prototype.hasOwnProperty;
});
%InstallToContext([
......
......@@ -532,85 +532,6 @@ RUNTIME_FUNCTION(Runtime_DeleteProperty_Strict) {
}
static Object* HasOwnPropertyImplementation(Isolate* isolate,
Handle<JSObject> object,
Handle<Name> key) {
Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key);
if (!maybe.IsJust()) return isolate->heap()->exception();
if (maybe.FromJust()) return isolate->heap()->true_value();
// Handle hidden prototypes. If there's a hidden prototype above this thing
// then we have to check it for properties, because they are supposed to
// look like they are on this object.
if (object->map()->has_hidden_prototype()) {
PrototypeIterator iter(isolate, object);
DCHECK(!iter.IsAtEnd());
// TODO(verwaest): The recursion is not necessary for keys that are array
// indices. Removing this.
// Casting to JSObject is fine because JSProxies are never used as
// hidden prototypes.
return HasOwnPropertyImplementation(
isolate, PrototypeIterator::GetCurrent<JSObject>(iter), key);
}
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return isolate->heap()->false_value();
}
RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
uint32_t index;
const bool key_is_array_index = key->AsArrayIndex(&index);
// Only JS objects can have properties.
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).
Maybe<bool> maybe = Nothing<bool>();
if (key_is_array_index) {
LookupIterator it(js_obj->GetIsolate(), js_obj, index,
LookupIterator::HIDDEN);
maybe = JSReceiver::HasProperty(&it);
} else {
maybe = JSObject::HasRealNamedProperty(js_obj, key);
}
if (!maybe.IsJust()) return isolate->heap()->exception();
DCHECK(!isolate->has_pending_exception());
if (maybe.FromJust()) {
return isolate->heap()->true_value();
}
Map* map = js_obj->map();
if (!key_is_array_index && !map->has_named_interceptor() &&
!map->has_hidden_prototype()) {
return isolate->heap()->false_value();
}
// Slow case.
return HasOwnPropertyImplementation(isolate, Handle<JSObject>(js_obj),
Handle<Name>(key));
} else if (object->IsString() && key_is_array_index) {
// Well, there is one exception: Handle [] on strings.
Handle<String> string = Handle<String>::cast(object);
if (index < static_cast<uint32_t>(string->length())) {
return isolate->heap()->true_value();
}
} else if (object->IsJSProxy()) {
Maybe<bool> result =
JSReceiver::HasOwnProperty(Handle<JSProxy>::cast(object), key);
if (!result.IsJust()) return isolate->heap()->exception();
return isolate->heap()->ToBoolean(result.FromJust());
}
return isolate->heap()->false_value();
}
// ES6 section 12.9.3, operator in.
RUNTIME_FUNCTION(Runtime_HasProperty) {
HandleScope scope(isolate);
......
......@@ -411,7 +411,6 @@ namespace internal {
F(AppendElement, 2, 1) \
F(DeleteProperty_Sloppy, 2, 1) \
F(DeleteProperty_Strict, 2, 1) \
F(HasOwnProperty, 2, 1) \
F(HasProperty, 2, 1) \
F(PropertyIsEnumerable, 2, 1) \
F(GetOwnPropertyKeys, 2, 1) \
......
......@@ -22065,7 +22065,7 @@ TEST(AccessCheckThrows) {
CheckCorrectThrow("%DeleteProperty_Strict(other, 'x')");
CheckCorrectThrow("%DeleteProperty_Sloppy(other, '1')");
CheckCorrectThrow("%DeleteProperty_Strict(other, '1')");
CheckCorrectThrow("%HasOwnProperty(other, 'x')");
CheckCorrectThrow("Object.prototype.hasOwnProperty.call(other, 'x')");
CheckCorrectThrow("%HasProperty('x', other)");
CheckCorrectThrow("%PropertyIsEnumerable(other, 'x')");
// PROPERTY_ATTRIBUTES_NONE = 0
......
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