From 97def40dc0b252b016e770eef0902d72643bcbaa Mon Sep 17 00:00:00 2001 From: machenbach Date: Sat, 28 Nov 2015 06:16:06 -0800 Subject: [PATCH] Revert of [proxies] Implement [[Enumerate]] and [[OwnPropertyKeys]] (patchset #3 id:40001 of https://codereview.chromium.org/1474083003/ ) Reason for revert: [Sheriff] Speculative revert for gc mole: https://build.chromium.org/p/client.v8/builders/V8%20Linux%20-%20gcmole/builds/5164 Original issue's description: > [proxies] Implement [[Enumerate]] and [[OwnPropertyKeys]] > > Both are integrated into JSReceiver::GetKeys(). > > For now, the implementation ignores Symbol/DONT_ENUM filtering. > > BUG=v8:1543 > LOG=n > > Committed: https://crrev.com/42c6056e6f247724d14dc887f6619a6bf5867a97 > Cr-Commit-Position: refs/heads/master@{#32384} TBR=verwaest@chromium.org,bmeurer@chromium.org,jkummerow@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=v8:1543 Review URL: https://codereview.chromium.org/1482113002 Cr-Commit-Position: refs/heads/master@{#32385} --- src/js/proxy.js | 45 ++-- src/key-accumulator.cc | 12 - src/key-accumulator.h | 1 - src/messages.h | 2 - src/objects.cc | 277 +--------------------- src/objects.h | 10 - test/mjsunit/harmony/proxies-enumerate.js | 64 ----- test/mjsunit/harmony/proxies-ownkeys.js | 84 ------- 8 files changed, 32 insertions(+), 463 deletions(-) delete mode 100644 test/mjsunit/harmony/proxies-enumerate.js delete mode 100644 test/mjsunit/harmony/proxies-ownkeys.js diff --git a/src/js/proxy.js b/src/js/proxy.js index d1202f7066..3885e408ad 100644 --- a/src/js/proxy.js +++ b/src/js/proxy.js @@ -152,30 +152,31 @@ function DerivedKeysTrap() { return enumerableNames } -// Implements part of ES6 9.5.11 Proxy.[[Enumerate]]: -// Call the trap, which should return an iterator, exhaust the iterator, -// and return an array containing the values. -function ProxyEnumerate(trap, handler, target) { - // 7. Let trapResult be ? Call(trap, handler, «target»). - var trap_result = %_Call(trap, handler, target); - // 8. If Type(trapResult) is not Object, throw a TypeError exception. - if (!IS_SPEC_OBJECT(trap_result)) { - throw MakeTypeError(kProxyHandlerReturned, handler, "non-Object", - "enumerate"); - } - // 9. Return trapResult. - var result = []; - for (var it = trap_result.next(); !it.done; it = trap_result.next()) { - var key = it.value; - // Not yet spec'ed as of 2015-11-25, but will be spec'ed soon: - // If the iterator returns a non-string value, throw a TypeError. - if (!IS_STRING(key)) { - throw MakeTypeError(kProxyHandlerReturned, handler, "non-String", - "enumerate-iterator"); +function DerivedEnumerateTrap() { + var names = this.getPropertyNames() + var enumerableNames = [] + for (var i = 0, count = 0; i < names.length; ++i) { + var name = names[i] + if (IS_SYMBOL(name)) continue + var desc = this.getPropertyDescriptor(TO_STRING(name)) + if (!IS_UNDEFINED(desc)) { + if (!desc.configurable) { + throw MakeTypeError(kProxyPropNotConfigurable, + this, name, "getPropertyDescriptor") + } + if (desc.enumerable) enumerableNames[count++] = names[i] } - result.push(key); } - return result; + return enumerableNames +} + +function ProxyEnumerate(proxy) { + var handler = %GetHandler(proxy) + if (IS_UNDEFINED(handler.enumerate)) { + return %Apply(DerivedEnumerateTrap, handler, [], 0, 0) + } else { + return ToNameArray(handler.enumerate(), "enumerate", false) + } } //------------------------------------------------------------------- diff --git a/src/key-accumulator.cc b/src/key-accumulator.cc index 68fe9d8cb7..91b014aacd 100644 --- a/src/key-accumulator.cc +++ b/src/key-accumulator.cc @@ -217,18 +217,6 @@ void KeyAccumulator::AddKeysFromProxy(Handle array_like) { } -void KeyAccumulator::AddKeysFromProxy(Handle keys) { - // Proxies define a complete list of keys with no distinction of - // elements and properties, which breaks the normal assumption for the - // KeyAccumulator. - AddKeys(keys, PROXY_MAGIC); - // Invert the current length to indicate a present proxy, so we can ignore - // element keys for this level. Otherwise we would not fully respect the order - // given by the proxy. - level_string_length_ = -level_string_length_; -} - - void KeyAccumulator::AddElementKeysFromInterceptor( Handle array_like) { AddKeys(array_like, CONVERT_TO_ARRAY_INDEX); diff --git a/src/key-accumulator.h b/src/key-accumulator.h index 47a1a6486b..8f9cc7c139 100644 --- a/src/key-accumulator.h +++ b/src/key-accumulator.h @@ -44,7 +44,6 @@ class KeyAccumulator final BASE_EMBEDDED { void AddKeys(Handle array, AddKeyConversion convert = DO_NOT_CONVERT); void AddKeysFromProxy(Handle array); - void AddKeysFromProxy(Handle keys); void AddElementKeysFromInterceptor(Handle array); // Jump to the next level, pushing the current |levelLength_| to // |levelLengths_| and adding a new list to |elements_|. diff --git a/src/messages.h b/src/messages.h index e5fa5fc31a..7825259b28 100644 --- a/src/messages.h +++ b/src/messages.h @@ -149,7 +149,6 @@ class CallSite { T(NotIntlObject, "% is not an i18n object.") \ T(NotGeneric, "% is not generic") \ T(NotIterable, "% is not iterable") \ - T(NotPropertyName, "% is not a valid property name") \ T(NotTypedArray, "this is not a typed array.") \ T(NotSharedTypedArray, "% is not a shared typed array.") \ T(NotIntegerSharedTypedArray, "% is not an integer shared typed array.") \ @@ -207,7 +206,6 @@ class CallSite { "Proxy target property '%' is not configurable") \ T(ProxyTrapFunctionExpected, \ "Proxy.createFunction called with non-function for '%' trap") \ - T(ProxyTrapResultMustInclude, "Trap result must include %.") \ T(RedefineDisallowed, "Cannot redefine property: %") \ T(RedefineExternalArray, \ "Cannot redefine a property of an object with external array elements") \ diff --git a/src/objects.cc b/src/objects.cc index a61d66d8e0..43ed55dc0d 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -28,7 +28,6 @@ #include "src/field-index-inl.h" #include "src/full-codegen/full-codegen.h" #include "src/ic/ic.h" -#include "src/identity-map.h" #include "src/interpreter/bytecodes.h" #include "src/isolate-inl.h" #include "src/key-accumulator.h" @@ -47,7 +46,6 @@ #include "src/string-search.h" #include "src/string-stream.h" #include "src/utils.h" -#include "src/zone.h" #ifdef ENABLE_DISASSEMBLER #include "src/disasm.h" @@ -8041,7 +8039,6 @@ static bool GetKeysFromJSObject(Isolate* isolate, Handle receiver, Handle object, KeyFilter filter, Enumerability enum_policy, KeyAccumulator* accumulator) { - accumulator->NextPrototype(); // Check access rights if required. if (object->IsAccessCheckNeeded() && !isolate->MayAccess(handle(isolate->context()), object)) { @@ -8121,19 +8118,18 @@ static bool GetKeys_Internal(Isolate* isolate, Handle receiver, for (PrototypeIterator iter(isolate, object, PrototypeIterator::START_AT_RECEIVER); !iter.IsAtEnd(end); iter.Advance()) { + accumulator->NextPrototype(); Handle current = PrototypeIterator::GetCurrent(iter); bool result = false; if (current->IsJSProxy()) { - if (type == JSReceiver::OWN_ONLY) { - result = JSProxy::OwnPropertyKeys(isolate, receiver, - Handle::cast(current), - filter, enum_policy, accumulator); - } else { - DCHECK(type == JSReceiver::INCLUDE_PROTOS); - result = JSProxy::Enumerate( - isolate, receiver, Handle::cast(current), accumulator); - } + Handle args[] = {current}; + Handle names; + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, names, Execution::Call(isolate, isolate->proxy_enumerate(), + current, arraysize(args), args), + false); + accumulator->AddKeysFromProxy(Handle::cast(names)); } else { DCHECK(current->IsJSObject()); result = GetKeysFromJSObject(isolate, receiver, @@ -8152,262 +8148,6 @@ static bool GetKeys_Internal(Isolate* isolate, Handle receiver, } -// ES6 9.5.11 -// Returns false in case of exception. -// static -bool JSProxy::Enumerate(Isolate* isolate, Handle receiver, - Handle proxy, KeyAccumulator* accumulator) { - // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O. - Handle handler(proxy->handler(), isolate); - // 2. If handler is null, throw a TypeError exception. - if (IsRevoked(proxy)) { - isolate->Throw(*isolate->factory()->NewTypeError( - MessageTemplate::kProxyRevoked, - isolate->factory()->enumerate_string())); - return false; - } - // 3. Assert: Type(handler) is Object. - DCHECK(handler->IsJSReceiver()); - // 4. Let target be the value of the [[ProxyTarget]] internal slot of O. - Handle target(JSReceiver::cast(proxy->target()), isolate); - // 5. Let trap be ? GetMethod(handler, "enumerate"). - Handle trap; - ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate, trap, Object::GetMethod(Handle::cast(handler), - isolate->factory()->enumerate_string()), - false); - // 6. If trap is undefined, then - if (trap->IsUndefined()) { - // 6a. Return target.[[Enumerate]](). - return GetKeys_Internal(isolate, receiver, target, INCLUDE_PROTOS, - SKIP_SYMBOLS, RESPECT_ENUMERABILITY, accumulator); - } - // The "proxy_enumerate" helper calls the trap (steps 7 - 9), which returns - // a generator; it then iterates over that generator until it's exhausted - // and returns an array containing the generated values. - Handle trap_result_array; - Handle args[] = {trap, handler, target}; - ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate, trap_result_array, - Execution::Call(isolate, isolate->proxy_enumerate(), - isolate->factory()->undefined_value(), arraysize(args), - args), - false); - accumulator->NextPrototype(); - accumulator->AddKeysFromProxy(Handle::cast(trap_result_array)); - return true; -} - - -// ES6 7.3.17 for elementTypes = (String, Symbol) -static MaybeHandle CreateListFromArrayLike_StringSymbol( - Isolate* isolate, Handle object) { - // 1. ReturnIfAbrupt(object). - // 2. (default elementTypes -- not applicable.) - // 3. If Type(obj) is not Object, throw a TypeError exception. - if (!object->IsJSReceiver()) { - isolate->Throw(*isolate->factory()->NewTypeError( - MessageTemplate::kCalledOnNonObject, - isolate->factory()->NewStringFromAsciiChecked( - "CreateListFromArrayLike"))); - return MaybeHandle(); - } - // 4. Let len be ? ToLength(? Get(obj, "length")). - Handle raw_length_obj; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, raw_length_obj, - JSReceiver::GetProperty(object, isolate->factory()->length_string()), - FixedArray); - Handle raw_length_number; - ASSIGN_RETURN_ON_EXCEPTION(isolate, raw_length_number, - Object::ToLength(isolate, raw_length_obj), - FixedArray); - uint32_t len; - if (!raw_length_number->ToUint32(&len) || - len > static_cast(FixedArray::kMaxLength)) { - isolate->Throw(*isolate->factory()->NewRangeError( - MessageTemplate::kInvalidArrayLength)); - return MaybeHandle(); - } - // 5. Let list be an empty List. - Handle list = isolate->factory()->NewFixedArray(len); - // 6. Let index be 0. - // 7. Repeat while index < len: - for (uint32_t index = 0; index < len; ++index) { - // 7a. Let indexName be ToString(index). - // 7b. Let next be ? Get(obj, indexName). - Handle next; - ASSIGN_RETURN_ON_EXCEPTION( - isolate, next, Object::GetElement(isolate, object, index), FixedArray); - // 7c. If Type(next) is not an element of elementTypes, throw a - // TypeError exception. - if (!next->IsName()) { - isolate->Throw(*isolate->factory()->NewTypeError( - MessageTemplate::kNotPropertyName, next)); - return MaybeHandle(); - } - // 7d. Append next as the last element of list. - // Internalize on the fly so we can use pointer identity later. - list->set(index, - *isolate->factory()->InternalizeName(Handle::cast(next))); - // 7e. Set index to index + 1. (See loop header.) - } - // 8. Return list. - return list; -} - - -// ES6 9.5.12 -// Returns "false" in case of exception. -// TODO(jkummerow): |filter| and |enum_policy| are currently ignored. -// static -bool JSProxy::OwnPropertyKeys(Isolate* isolate, Handle receiver, - Handle proxy, KeyFilter filter, - Enumerability enum_policy, - KeyAccumulator* accumulator) { - // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O. - Handle handler(proxy->handler(), isolate); - // 2. If handler is null, throw a TypeError exception. - if (IsRevoked(proxy)) { - isolate->Throw(*isolate->factory()->NewTypeError( - MessageTemplate::kProxyRevoked, isolate->factory()->ownKeys_string())); - return false; - } - // 3. Assert: Type(handler) is Object. - DCHECK(handler->IsJSReceiver()); - // 4. Let target be the value of the [[ProxyTarget]] internal slot of O. - Handle target(JSReceiver::cast(proxy->target()), isolate); - // 5. Let trap be ? GetMethod(handler, "ownKeys"). - Handle trap; - ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate, trap, Object::GetMethod(Handle::cast(handler), - isolate->factory()->ownKeys_string()), - false); - // 6. If trap is undefined, then - if (trap->IsUndefined()) { - // 6a. Return target.[[OwnPropertyKeys]](). - return GetKeys_Internal(isolate, receiver, target, OWN_ONLY, filter, - enum_policy, accumulator); - } - // 7. Let trapResultArray be Call(trap, handler, «target»). - Handle trap_result_array; - Handle args[] = {target}; - ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate, trap_result_array, - Execution::Call(isolate, trap, handler, arraysize(args), args), false); - // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, - // «String, Symbol»). - Handle trap_result; - ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate, trap_result, - CreateListFromArrayLike_StringSymbol(isolate, trap_result_array), false); - // 9. Let extensibleTarget be ? IsExtensible(target). - Maybe maybe_extensible = JSReceiver::IsExtensible(target); - if (maybe_extensible.IsNothing()) return false; - bool extensible_target = maybe_extensible.FromJust(); - // 10. Let targetKeys be ? target.[[OwnPropertyKeys]](). - Handle target_keys; - ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate, target_keys, - JSReceiver::GetKeys(target, JSReceiver::OWN_ONLY, INCLUDE_SYMBOLS, - CONVERT_TO_STRING, IGNORE_ENUMERABILITY), - false); - // 11. (Assert) - // 12. Let targetConfigurableKeys be an empty List. - // To save memory, we're re-using target_keys and will modify it in-place. - Handle target_configurable_keys = target_keys; - // 13. Let targetNonconfigurableKeys be an empty List. - Handle target_nonconfigurable_keys = - isolate->factory()->NewFixedArray(target_keys->length()); - int nonconfigurable_keys_length = 0; - // 14. Repeat, for each element key of targetKeys: - for (int i = 0; i < target_keys->length(); ++i) { - // 14a. Let desc be ? target.[[GetOwnProperty]](key). - PropertyDescriptor desc; - bool found = JSReceiver::GetOwnPropertyDescriptor( - isolate, target, handle(target_keys->get(i), isolate), &desc); - if (isolate->has_pending_exception()) return false; - // 14b. If desc is not undefined and desc.[[Configurable]] is false, then - if (found && !desc.configurable()) { - // 14b i. Append key as an element of targetNonconfigurableKeys. - target_nonconfigurable_keys->set(nonconfigurable_keys_length, - target_keys->get(i)); - nonconfigurable_keys_length++; - // The key was moved, null it out in the original list. - target_keys->set(i, Smi::FromInt(0)); - } else { - // 14c. Else, - // 14c i. Append key as an element of targetConfigurableKeys. - // (No-op, just keep it in |target_keys|.) - } - } - accumulator->NextPrototype(); // Prepare for accumulating keys. - // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty, - // then: - if (extensible_target && nonconfigurable_keys_length == 0) { - // 15a. Return trapResult. - accumulator->AddKeysFromProxy(trap_result); - return true; - } - // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult. - Zone set_zone; - const int kPresent = 1; - const int kGone = 0; - IdentityMap unchecked_result_keys(isolate->heap(), &set_zone); - int unchecked_result_keys_size = trap_result->length(); - for (int i = 0; i < trap_result->length(); ++i) { - DCHECK(trap_result->get(i)->IsUniqueName()); - unchecked_result_keys.Set(trap_result->get(i), kPresent); - } - // 17. Repeat, for each key that is an element of targetNonconfigurableKeys: - for (int i = 0; i < nonconfigurable_keys_length; ++i) { - Object* key = target_nonconfigurable_keys->get(i); - // 17a. If key is not an element of uncheckedResultKeys, throw a - // TypeError exception. - int* found = unchecked_result_keys.Find(key); - if (found == nullptr || *found == kGone) { - isolate->Throw(*isolate->factory()->NewTypeError( - MessageTemplate::kProxyTrapResultMustInclude, handle(key, isolate))); - return false; - } - // 17b. Remove key from uncheckedResultKeys. - *found = kGone; - unchecked_result_keys_size--; - } - // 18. If extensibleTarget is true, return trapResult. - if (extensible_target) { - accumulator->AddKeysFromProxy(trap_result); - return true; - } - // 19. Repeat, for each key that is an element of targetConfigurableKeys: - for (int i = 0; i < target_configurable_keys->length(); ++i) { - Object* key = target_configurable_keys->get(i); - if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable. - // 19a. If key is not an element of uncheckedResultKeys, throw a - // TypeError exception. - int* found = unchecked_result_keys.Find(key); - if (found == nullptr || *found == kGone) { - isolate->Throw(*isolate->factory()->NewTypeError( - MessageTemplate::kProxyTrapResultMustInclude, handle(key, isolate))); - return false; - } - // 19b. Remove key from uncheckedResultKeys. - *found = kGone; - unchecked_result_keys_size--; - } - // 20. If uncheckedResultKeys is not empty, throw a TypeError exception. - if (unchecked_result_keys_size != 0) { - DCHECK_GT(unchecked_result_keys_size, 0); - isolate->Throw(*isolate->factory()->NewTypeError( - MessageTemplate::kProxyTargetNotExtensible)); - return false; - } - // 21. Return trapResult. - accumulator->AddKeysFromProxy(trap_result); - return true; -} - - MaybeHandle JSReceiver::GetKeys(Handle object, KeyCollectionType type, KeyFilter filter, @@ -8421,6 +8161,7 @@ MaybeHandle JSReceiver::GetKeys(Handle object, DCHECK(isolate->has_pending_exception()); return MaybeHandle(); } + Handle keys = accumulator.GetKeys(keys_conversion); DCHECK(ContainsOnlyValidKeys(keys)); return keys; diff --git a/src/objects.h b/src/objects.h index cd5b9f86e5..cc0c0dc8f8 100644 --- a/src/objects.h +++ b/src/objects.h @@ -9528,16 +9528,6 @@ class JSProxy: public JSReceiver { MUST_USE_RESULT static Maybe DeletePropertyOrElement( Handle proxy, Handle name, LanguageMode language_mode); - // ES6 9.5.11 - static bool Enumerate(Isolate* isolate, Handle receiver, - Handle proxy, KeyAccumulator* accumulator); - - // ES6 9.5.12 - static bool OwnPropertyKeys(Isolate* isolate, Handle receiver, - Handle proxy, KeyFilter filter, - Enumerability enum_policy, - KeyAccumulator* accumulator); - MUST_USE_RESULT static MaybeHandle GetPropertyWithHandler( Handle proxy, Handle receiver, diff --git a/test/mjsunit/harmony/proxies-enumerate.js b/test/mjsunit/harmony/proxies-enumerate.js deleted file mode 100644 index 32d6bb5873..0000000000 --- a/test/mjsunit/harmony/proxies-enumerate.js +++ /dev/null @@ -1,64 +0,0 @@ -// 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 - -var target = { - "target_one": 1 -}; -target.__proto__ = { - "target_two": 2 -}; -var handler = { - enumerate: function(target) { - function* keys() { - yield "foo"; - yield "bar"; - } - return keys(); - } -} - -var proxy = new Proxy(target, handler); - -function TestForIn(receiver, expected) { - var result = []; - for (var k in receiver) { - result.push(k); - } - assertEquals(expected, result); -} - -TestForIn(proxy, ["foo", "bar"]); - -// Properly call traps on proxies on the prototype chain. -var receiver = { - "receiver_one": 1 -}; -receiver.__proto__ = proxy; -// TODO(jkummerow): Needs proper 'has' trap; implement that and enable this! -// TestForIn(receiver, ["receiver_one", "foo", "bar"]); - -// Fall through to default behavior when trap is undefined. -handler.enumerate = undefined; -TestForIn(proxy, ["target_one", "target_two"]); -delete handler.enumerate; -TestForIn(proxy, ["target_one", "target_two"]); - -// Non-string keys must be filtered. -function TestNonStringKey(key) { - handler.enumerate = function(target) { - function* keys() { yield key; } - return keys(); - } - assertThrows("for (var k in proxy) {}", TypeError); -} - -TestNonStringKey(1); -TestNonStringKey(3.14); -TestNonStringKey(Symbol("foo")); -TestNonStringKey({bad: "value"}); -TestNonStringKey(null); -TestNonStringKey(undefined); -TestNonStringKey(true); diff --git a/test/mjsunit/harmony/proxies-ownkeys.js b/test/mjsunit/harmony/proxies-ownkeys.js deleted file mode 100644 index de913671d4..0000000000 --- a/test/mjsunit/harmony/proxies-ownkeys.js +++ /dev/null @@ -1,84 +0,0 @@ -// 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 --harmony-reflect - -var target = { - "target_one": 1 -}; -target.__proto__ = { - "target_proto_two": 2 -}; -var handler = { - ownKeys: function(target) { - return ["foo", "bar"]; - } -} - -var proxy = new Proxy(target, handler); - -// Simple case. -assertEquals(["foo", "bar"], Reflect.ownKeys(proxy)); - -// Test interesting steps of the algorithm: - -// Step 6: Fall through to target.[[OwnPropertyKeys]] if the trap is undefined. -handler.ownKeys = undefined; -assertEquals(["target_one"], Reflect.ownKeys(proxy)); - -// Step 7: Throwing traps don't crash. -handler.ownKeys = function(target) { throw 1; }; -assertThrows("Reflect.ownKeys(proxy)"); - -// Step 8: CreateListFromArrayLike error cases: -// Returning a non-Object throws. -var keys = 1; -handler.ownKeys = function(target) { return keys; }; -assertThrows("Reflect.ownKeys(proxy)", TypeError); -keys = "string"; -assertThrows("Reflect.ownKeys(proxy)", TypeError); -keys = Symbol("foo"); -assertThrows("Reflect.ownKeys(proxy)", TypeError); -keys = null; -assertThrows("Reflect.ownKeys(proxy)", TypeError); - -// "length" property is honored. -keys = { 0: "a", 1: "b", 2: "c" }; -keys.length = 0; -assertEquals([], Reflect.ownKeys(proxy)); -keys.length = 1; -assertEquals(["a"], Reflect.ownKeys(proxy)); -keys.length = 3; -assertEquals(["a", "b", "c"], Reflect.ownKeys(proxy)); -// The spec wants to allow lengths up to 2^53, but we can't allocate arrays -// of that size, so we throw even for smaller values. -keys.length = Math.pow(2, 33); -assertThrows("Reflect.ownKeys(proxy)", RangeError); - -// Non-Name results throw. -keys = [1]; -assertThrows("Reflect.ownKeys(proxy)", TypeError); -keys = [{}]; -assertThrows("Reflect.ownKeys(proxy)", TypeError); -keys = [{toString: function() { return "foo"; }}]; -assertThrows("Reflect.ownKeys(proxy)", TypeError); -keys = [null]; -assertThrows("Reflect.ownKeys(proxy)", TypeError); - -// Step 17a: The trap result must include all non-configurable keys. -Object.defineProperty(target, "nonconf", {value: 1, configurable: false}); -keys = ["foo"]; -assertThrows("Reflect.ownKeys(proxy)", TypeError); -keys = ["nonconf"]; -assertEquals(keys, Reflect.ownKeys(proxy)); - -// Step 19a: The trap result must all keys of a non-extensible target. -Object.freeze(target); -assertThrows("Reflect.ownKeys(proxy)", TypeError); -keys = ["nonconf", "target_one"]; -assertEquals(keys, Reflect.ownKeys(proxy)); - -// Step 20: The trap result must not add keys to a non-extensible target. -keys = ["nonconf", "target_one", "fantasy"]; -assertThrows("Reflect.ownKeys(proxy)", TypeError);