[proxies] Make Array.isArray respect proxies.

An array is either a JSArray or a proxy whose target is an array.

R=bmeurer@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#32558}
This commit is contained in:
neis 2015-12-03 04:51:15 -08:00 committed by Commit bot
parent a32096c43c
commit 82d974799b
7 changed files with 71 additions and 26 deletions

View File

@ -1014,6 +1014,20 @@ void Genesis::HookUpGlobalObject(Handle<JSGlobalObject> global_object) {
}
static void SimpleInstallFunction(Handle<JSObject> base, Handle<Name> name,
Builtins::Name call, int len, bool adapt) {
Handle<JSFunction> fun =
InstallFunction(base, name, JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), call, DONT_ENUM);
if (adapt) {
fun->shared()->set_internal_formal_parameter_count(len);
} else {
fun->shared()->DontAdaptArguments();
}
fun->shared()->set_length(len);
}
// This is only called if we are not using snapshots. The equivalent
// work in the snapshot case is done in HookUpGlobalObject.
void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
@ -1100,6 +1114,10 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Map::Copy(initial_map, "SetInstancePrototype");
initial_strong_map->set_is_strong();
CacheInitialJSArrayMaps(native_context(), initial_strong_map);
SimpleInstallFunction(array_function,
factory->NewStringFromAsciiChecked("isArray"),
Builtins::kArrayIsArray, 1, true);
}
{ // --- N u m b e r ---
@ -1969,20 +1987,6 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_do_expressions)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_lookbehind)
static void SimpleInstallFunction(Handle<JSObject> base, Handle<Name> name,
Builtins::Name call, int len, bool adapt) {
Handle<JSFunction> fun =
InstallFunction(base, name, JS_OBJECT_TYPE, JSObject::kHeaderSize,
MaybeHandle<JSObject>(), call, DONT_ENUM);
if (adapt) {
fun->shared()->set_internal_formal_parameter_count(len);
} else {
fun->shared()->DontAdaptArguments();
}
fun->shared()->set_length(len);
}
void InstallPublicSymbol(Factory* factory, Handle<Context> native_context,
const char* name, Handle<Symbol> value) {
Handle<JSGlobalObject> global(

View File

@ -1423,6 +1423,17 @@ BUILTIN(ArrayConcat) {
}
// ES6 section 22.1.2.2 Array.isArray
BUILTIN(ArrayIsArray) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
Handle<Object> object = args.at<Object>(1);
Maybe<bool> result = Object::IsArray(object);
MAYBE_RETURN(result, isolate->heap()->exception());
return *isolate->factory()->ToBoolean(result.FromJust());
}
// ES6 section 26.1.3 Reflect.defineProperty
BUILTIN(ReflectDefineProperty) {
HandleScope scope(isolate);

View File

@ -56,13 +56,14 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
\
V(EmptyFunction, kNone) \
\
V(ArrayPush, kNone) \
V(ArrayConcat, kNone) \
V(ArrayIsArray, kNone) \
V(ArrayPop, kNone) \
V(ArrayPush, kNone) \
V(ArrayShift, kNone) \
V(ArrayUnshift, kNone) \
V(ArraySlice, kNone) \
V(ArraySplice, kNone) \
V(ArrayConcat, kNone) \
V(ArrayUnshift, kNone) \
\
V(DateToPrimitive, kNone) \
\

View File

@ -1697,12 +1697,6 @@ function ArrayFill(value, start, end) {
}
// ES5, 15.4.3.2
function ArrayIsArray(obj) {
return IS_ARRAY(obj);
}
function AddArrayElement(constructor, array, i, value) {
if (constructor === GlobalArray) {
AddIndexedProperty(array, i, value);
@ -1816,7 +1810,6 @@ var unscopables = {
// Set up non-enumerable functions on the Array object.
utils.InstallFunctions(GlobalArray, DONT_ENUM, [
"isArray", ArrayIsArray,
"from", ArrayFrom,
"of", ArrayOf
]);

View File

@ -624,6 +624,23 @@ MaybeHandle<Object> Object::BitwiseXor(Isolate* isolate, Handle<Object> lhs,
}
Maybe<bool> Object::IsArray(Handle<Object> object) {
if (object->IsJSArray()) return Just(true);
if (object->IsJSProxy()) {
Handle<JSProxy> proxy = Handle<JSProxy>::cast(object);
Isolate* isolate = proxy->GetIsolate();
if (proxy->IsRevoked()) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kProxyRevoked,
isolate->factory()->NewStringFromAsciiChecked("IsArray")));
return Nothing<bool>();
}
return Object::IsArray(handle(proxy->target(), isolate));
}
return Just(false);
}
bool Object::IsPromise(Handle<Object> object) {
if (!object->IsJSObject()) return false;
auto js_object = Handle<JSObject>::cast(object);
@ -996,7 +1013,7 @@ MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
}
bool JSProxy::IsRevoked() {
bool JSProxy::IsRevoked() const {
// TODO(neis): Decide on how to represent revocation. For now, revocation is
// unsupported.
DCHECK(target()->IsJSReceiver());

View File

@ -1055,6 +1055,9 @@ class Object {
STRUCT_LIST(DECLARE_STRUCT_PREDICATE)
#undef DECLARE_STRUCT_PREDICATE
// ES6, section 7.2.2 IsArray. NOT to be confused with %_IsArray.
MUST_USE_RESULT static Maybe<bool> IsArray(Handle<Object> object);
// ES6, section 7.2.3 IsCallable.
INLINE(bool IsCallable() const);
@ -9498,7 +9501,7 @@ class JSProxy: public JSReceiver {
DECLARE_CAST(JSProxy)
bool IsRevoked();
bool IsRevoked() const;
// ES6 9.5.1
static MaybeHandle<Object> GetPrototype(Handle<JSProxy> receiver);

View File

@ -0,0 +1,16 @@
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-proxies
assertTrue(Array.isArray([]));
assertFalse(Array.isArray({}));
assertFalse(Array.isArray(null));
assertTrue(Array.isArray(new Proxy([], {})));
assertFalse(Array.isArray(new Proxy({}, {})));
assertTrue(Array.isArray(new Proxy(new Proxy([], {}), {})));
assertFalse(Array.isArray(new Proxy(new Proxy({}, {}), {})));