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}
This commit is contained in:
parent
42c6056e6f
commit
97def40dc0
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
@ -217,18 +217,6 @@ void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) {
|
||||
}
|
||||
|
||||
|
||||
void KeyAccumulator::AddKeysFromProxy(Handle<FixedArray> 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<JSObject> array_like) {
|
||||
AddKeys(array_like, CONVERT_TO_ARRAY_INDEX);
|
||||
|
@ -44,7 +44,6 @@ class KeyAccumulator final BASE_EMBEDDED {
|
||||
void AddKeys(Handle<JSObject> array,
|
||||
AddKeyConversion convert = DO_NOT_CONVERT);
|
||||
void AddKeysFromProxy(Handle<JSObject> array);
|
||||
void AddKeysFromProxy(Handle<FixedArray> keys);
|
||||
void AddElementKeysFromInterceptor(Handle<JSObject> array);
|
||||
// Jump to the next level, pushing the current |levelLength_| to
|
||||
// |levelLengths_| and adding a new list to |elements_|.
|
||||
|
@ -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") \
|
||||
|
277
src/objects.cc
277
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<JSReceiver> receiver,
|
||||
Handle<JSObject> 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<JSReceiver> receiver,
|
||||
for (PrototypeIterator iter(isolate, object,
|
||||
PrototypeIterator::START_AT_RECEIVER);
|
||||
!iter.IsAtEnd(end); iter.Advance()) {
|
||||
accumulator->NextPrototype();
|
||||
Handle<JSReceiver> current =
|
||||
PrototypeIterator::GetCurrent<JSReceiver>(iter);
|
||||
bool result = false;
|
||||
if (current->IsJSProxy()) {
|
||||
if (type == JSReceiver::OWN_ONLY) {
|
||||
result = JSProxy::OwnPropertyKeys(isolate, receiver,
|
||||
Handle<JSProxy>::cast(current),
|
||||
filter, enum_policy, accumulator);
|
||||
} else {
|
||||
DCHECK(type == JSReceiver::INCLUDE_PROTOS);
|
||||
result = JSProxy::Enumerate(
|
||||
isolate, receiver, Handle<JSProxy>::cast(current), accumulator);
|
||||
}
|
||||
Handle<Object> args[] = {current};
|
||||
Handle<Object> names;
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, names, Execution::Call(isolate, isolate->proxy_enumerate(),
|
||||
current, arraysize(args), args),
|
||||
false);
|
||||
accumulator->AddKeysFromProxy(Handle<JSObject>::cast(names));
|
||||
} else {
|
||||
DCHECK(current->IsJSObject());
|
||||
result = GetKeysFromJSObject(isolate, receiver,
|
||||
@ -8152,262 +8148,6 @@ static bool GetKeys_Internal(Isolate* isolate, Handle<JSReceiver> receiver,
|
||||
}
|
||||
|
||||
|
||||
// ES6 9.5.11
|
||||
// Returns false in case of exception.
|
||||
// static
|
||||
bool JSProxy::Enumerate(Isolate* isolate, Handle<JSReceiver> receiver,
|
||||
Handle<JSProxy> proxy, KeyAccumulator* accumulator) {
|
||||
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
Handle<Object> 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<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
|
||||
// 5. Let trap be ? GetMethod(handler, "enumerate").
|
||||
Handle<Object> trap;
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, trap, Object::GetMethod(Handle<JSReceiver>::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<Object> trap_result_array;
|
||||
Handle<Object> 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<JSObject>::cast(trap_result_array));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ES6 7.3.17 for elementTypes = (String, Symbol)
|
||||
static MaybeHandle<FixedArray> CreateListFromArrayLike_StringSymbol(
|
||||
Isolate* isolate, Handle<Object> 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<FixedArray>();
|
||||
}
|
||||
// 4. Let len be ? ToLength(? Get(obj, "length")).
|
||||
Handle<Object> raw_length_obj;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, raw_length_obj,
|
||||
JSReceiver::GetProperty(object, isolate->factory()->length_string()),
|
||||
FixedArray);
|
||||
Handle<Object> 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<uint32_t>(FixedArray::kMaxLength)) {
|
||||
isolate->Throw(*isolate->factory()->NewRangeError(
|
||||
MessageTemplate::kInvalidArrayLength));
|
||||
return MaybeHandle<FixedArray>();
|
||||
}
|
||||
// 5. Let list be an empty List.
|
||||
Handle<FixedArray> 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<Object> 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<FixedArray>();
|
||||
}
|
||||
// 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<Name>::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<JSReceiver> receiver,
|
||||
Handle<JSProxy> proxy, KeyFilter filter,
|
||||
Enumerability enum_policy,
|
||||
KeyAccumulator* accumulator) {
|
||||
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
Handle<Object> 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<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
|
||||
// 5. Let trap be ? GetMethod(handler, "ownKeys").
|
||||
Handle<Object> trap;
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, trap, Object::GetMethod(Handle<JSReceiver>::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<Object> trap_result_array;
|
||||
Handle<Object> 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<FixedArray> trap_result;
|
||||
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
|
||||
isolate, trap_result,
|
||||
CreateListFromArrayLike_StringSymbol(isolate, trap_result_array), false);
|
||||
// 9. Let extensibleTarget be ? IsExtensible(target).
|
||||
Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
|
||||
if (maybe_extensible.IsNothing()) return false;
|
||||
bool extensible_target = maybe_extensible.FromJust();
|
||||
// 10. Let targetKeys be ? target.[[OwnPropertyKeys]]().
|
||||
Handle<FixedArray> 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<FixedArray> target_configurable_keys = target_keys;
|
||||
// 13. Let targetNonconfigurableKeys be an empty List.
|
||||
Handle<FixedArray> 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<int> 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<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
|
||||
KeyCollectionType type,
|
||||
KeyFilter filter,
|
||||
@ -8421,6 +8161,7 @@ MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
|
||||
DCHECK(isolate->has_pending_exception());
|
||||
return MaybeHandle<FixedArray>();
|
||||
}
|
||||
|
||||
Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion);
|
||||
DCHECK(ContainsOnlyValidKeys(keys));
|
||||
return keys;
|
||||
|
@ -9528,16 +9528,6 @@ class JSProxy: public JSReceiver {
|
||||
MUST_USE_RESULT static Maybe<bool> DeletePropertyOrElement(
|
||||
Handle<JSProxy> proxy, Handle<Name> name, LanguageMode language_mode);
|
||||
|
||||
// ES6 9.5.11
|
||||
static bool Enumerate(Isolate* isolate, Handle<JSReceiver> receiver,
|
||||
Handle<JSProxy> proxy, KeyAccumulator* accumulator);
|
||||
|
||||
// ES6 9.5.12
|
||||
static bool OwnPropertyKeys(Isolate* isolate, Handle<JSReceiver> receiver,
|
||||
Handle<JSProxy> proxy, KeyFilter filter,
|
||||
Enumerability enum_policy,
|
||||
KeyAccumulator* accumulator);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithHandler(
|
||||
Handle<JSProxy> proxy,
|
||||
Handle<Object> receiver,
|
||||
|
@ -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);
|
@ -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);
|
Loading…
Reference in New Issue
Block a user