Commit ef1ac729 authored by neis's avatar neis Committed by Commit bot

[proxies] Make Object.{isFrozen,isSealed} behave correctly for proxies.

R=rossberg
BUG=

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

Cr-Commit-Position: refs/heads/master@{#32660}
parent 6150662d
......@@ -917,69 +917,42 @@ function ObjectDefineProperties(obj, properties) {
}
// ES5 section 15.2.3.8.
// ES6 19.1.2.17
function ObjectSealJS(obj) {
if (!IS_SPEC_OBJECT(obj)) return obj;
return %ObjectSeal(obj);
}
// ES5 section 15.2.3.9.
// ES6 19.1.2.5
function ObjectFreezeJS(obj) {
if (!IS_SPEC_OBJECT(obj)) return obj;
return %ObjectFreeze(obj);
}
// ES5 section 15.2.3.10
// ES6 19.1.2.15
function ObjectPreventExtension(obj) {
if (!IS_SPEC_OBJECT(obj)) return obj;
return %PreventExtensions(obj);
}
// ES5 section 15.2.3.11
// ES6 19.1.2.13
function ObjectIsSealed(obj) {
if (!IS_SPEC_OBJECT(obj)) return true;
if (%_IsJSProxy(obj)) {
return false; // TODO(neis): Must call isExtensible trap and ownKeys trap.
}
if (%IsExtensible(obj)) {
return false;
}
var names = OwnPropertyKeys(obj);
for (var i = 0; i < names.length; i++) {
var name = names[i];
var desc = GetOwnPropertyJS(obj, name);
if (desc.isConfigurable()) {
return false;
}
}
return true;
return %ObjectIsSealed(obj);
}
// ES5 section 15.2.3.12
// ES6 19.1.2.12
function ObjectIsFrozen(obj) {
if (!IS_SPEC_OBJECT(obj)) return true;
if (%_IsJSProxy(obj)) {
return false; // TODO(neis): Must call isExtensible trap and ownKeys trap.
}
if (%IsExtensible(obj)) {
return false;
}
var names = OwnPropertyKeys(obj);
for (var i = 0; i < names.length; i++) {
var name = names[i];
var desc = GetOwnPropertyJS(obj, name);
if (IsDataDescriptor(desc) && desc.isWritable()) return false;
if (desc.isConfigurable()) return false;
}
return true;
return %ObjectIsFrozen(obj);
}
// ES5 section 15.2.3.13
// ES6 19.1.2.11
function ObjectIsExtensible(obj) {
if (!IS_SPEC_OBJECT(obj)) return false;
return %IsExtensible(obj);
......
......@@ -7297,6 +7297,38 @@ Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
}
Maybe<bool> JSReceiver::TestIntegrityLevel(Handle<JSReceiver> object,
IntegrityLevel level) {
DCHECK(level == SEALED || level == FROZEN);
Isolate* isolate = object->GetIsolate();
Maybe<bool> extensible = JSReceiver::IsExtensible(object);
MAYBE_RETURN(extensible, Nothing<bool>());
if (extensible.FromJust()) return Just(false);
Handle<FixedArray> keys;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, keys, JSReceiver::OwnPropertyKeys(object), Nothing<bool>());
for (int i = 0; i < keys->length(); ++i) {
Handle<Object> key(keys->get(i), isolate);
PropertyDescriptor current_desc;
bool owned = JSReceiver::GetOwnPropertyDescriptor(isolate, object, key,
&current_desc);
if (isolate->has_pending_exception()) return Nothing<bool>();
if (owned) {
if (current_desc.configurable()) return Just(false);
if (level == FROZEN &&
PropertyDescriptor::IsDataDescriptor(&current_desc) &&
current_desc.writable()) {
return Just(false);
}
}
}
return Just(true);
}
Maybe<bool> JSReceiver::PreventExtensions(Handle<JSReceiver> object,
ShouldThrow should_throw) {
if (object->IsJSProxy()) {
......
......@@ -1871,6 +1871,11 @@ class JSReceiver: public HeapObject {
MUST_USE_RESULT static Maybe<bool> SetIntegrityLevel(
Handle<JSReceiver> object, IntegrityLevel lvl, ShouldThrow should_throw);
// ES6 7.3.15
// 'level' must be SEALED or FROZEN.
MUST_USE_RESULT static Maybe<bool> TestIntegrityLevel(
Handle<JSReceiver> object, IntegrityLevel lvl);
// ES6 [[PreventExtensions]] (when passed DONT_THROW)
MUST_USE_RESULT static Maybe<bool> PreventExtensions(
Handle<JSReceiver> object, ShouldThrow should_throw);
......
......@@ -343,6 +343,17 @@ RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
}
RUNTIME_FUNCTION(Runtime_ObjectIsFrozen) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
Maybe<bool> result = JSReceiver::TestIntegrityLevel(object, FROZEN);
MAYBE_RETURN(result, isolate->heap()->exception());
return isolate->heap()->ToBoolean(result.FromJust());
}
RUNTIME_FUNCTION(Runtime_ObjectSeal) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
......@@ -355,6 +366,17 @@ RUNTIME_FUNCTION(Runtime_ObjectSeal) {
}
RUNTIME_FUNCTION(Runtime_ObjectIsSealed) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
Maybe<bool> result = JSReceiver::TestIntegrityLevel(object, SEALED);
MAYBE_RETURN(result, isolate->heap()->exception());
return isolate->heap()->ToBoolean(result.FromJust());
}
RUNTIME_FUNCTION(Runtime_LoadGlobalViaContext) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -434,7 +434,9 @@ namespace internal {
F(IsExtensible, 1, 1) \
F(OptimizeObjectForAddingMultipleProperties, 2, 1) \
F(ObjectFreeze, 1, 1) \
F(ObjectIsFrozen, 1, 1) \
F(ObjectSeal, 1, 1) \
F(ObjectIsSealed, 1, 1) \
F(GetProperty, 2, 1) \
F(GetPropertyStrong, 2, 1) \
F(KeyedGetProperty, 2, 1) \
......
......@@ -93,3 +93,121 @@ logger.get = function(t, trap, r) {
assertArrayEquals(
["defineProperty", target, toKey(symbol), noconf], log[9]);
})();
(function IsSealed() {
var target = [];
var proxy = new Proxy(target, handler);
target.wurst = 42;
target[0] = true;
Object.defineProperty(target, symbol, {get: undefined});
// Extensible.
log.length = 0;
Object.isSealed(proxy);
assertEquals(1, log.length)
for (var i in log) assertSame(target, log[i][1]);
assertArrayEquals(
["isExtensible", target], log[0]);
// Not extensible but not sealed.
log.length = 0;
Object.preventExtensions(target);
Object.isSealed(proxy);
assertEquals(3, log.length)
for (var i in log) assertSame(target, log[i][1]);
assertArrayEquals(
["isExtensible", target], log[0]);
assertArrayEquals(
["ownKeys", target], log[1]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey(0)], log[2]);
// Sealed.
log.length = 0;
Object.seal(target);
Object.isSealed(proxy);
assertEquals(6, log.length)
for (var i in log) assertSame(target, log[i][1]);
assertArrayEquals(
["isExtensible", target], log[0]);
assertArrayEquals(
["ownKeys", target], log[1]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey(0)], log[2]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey("length")], log[3]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey("wurst")], log[4]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey(symbol)], log[5]);
})();
(function IsFrozen() {
var target = [];
var proxy = new Proxy(target, handler);
target.wurst = 42;
target[0] = true;
Object.defineProperty(target, symbol, {get: undefined});
// Extensible.
log.length = 0;
Object.isFrozen(proxy);
assertEquals(1, log.length)
for (var i in log) assertSame(target, log[i][1]);
assertArrayEquals(
["isExtensible", target], log[0]);
// Not extensible but not frozen.
log.length = 0;
Object.preventExtensions(target);
Object.isFrozen(proxy);
assertEquals(3, log.length)
for (var i in log) assertSame(target, log[i][1]);
assertArrayEquals(
["isExtensible", target], log[0]);
assertArrayEquals(
["ownKeys", target], log[1]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey(0)], log[2]);
// Frozen.
log.length = 0;
Object.freeze(target);
Object.isFrozen(proxy);
assertEquals(6, log.length)
for (var i in log) assertSame(target, log[i][1]);
assertArrayEquals(
["isExtensible", target], log[0]);
assertArrayEquals(
["ownKeys", target], log[1]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey(0)], log[2]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey("length")], log[3]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey("wurst")], log[4]);
assertArrayEquals(
["getOwnPropertyDescriptor", target, toKey(symbol)], log[5]);
})();
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