Revert "[builtins] Port Proxy set trap to CSA"
This reverts commit a9f517e234
.
Reason for revert: Makes array sort flaky? https://build.chromium.org/p/client.v8/builders/V8%20Linux64%20-%20debug/builds/17894/steps/OptimizeForSize%20%28flakes%29/logs/array-sort
Original change's description:
> [builtins] Port Proxy set trap to CSA
>
> Bug: v8:6560, v8:6557
> Change-Id: I329794607e8de324fc696652555aaaeafcf519ec
> Reviewed-on: https://chromium-review.googlesource.com/625940
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Commit-Queue: Maya Lekova <mslekova@google.com>
> Cr-Commit-Position: refs/heads/master@{#47760}
TBR=neis@chromium.org,franzih@chromium.org,ishell@chromium.org,bmeurer@chromium.org,mslekova@google.com
Change-Id: Ibebf5e694945e59bd2808841108e6686af51efaf
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:6560, v8:6557
Reviewed-on: https://chromium-review.googlesource.com/646169
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47764}
This commit is contained in:
parent
6a08d18de2
commit
7c60eac7c8
2
BUILD.gn
2
BUILD.gn
@ -1005,6 +1005,8 @@ v8_source_set("v8_builtins_generators") {
|
||||
"src/builtins/builtins-promise-gen.h",
|
||||
"src/builtins/builtins-proxy-gen.cc",
|
||||
"src/builtins/builtins-proxy-gen.h",
|
||||
"src/builtins/builtins-proxy-helpers-gen.cc",
|
||||
"src/builtins/builtins-proxy-helpers-gen.h",
|
||||
"src/builtins/builtins-regexp-gen.cc",
|
||||
"src/builtins/builtins-regexp-gen.h",
|
||||
"src/builtins/builtins-sharedarraybuffer-gen.cc",
|
||||
|
@ -779,7 +779,6 @@ namespace internal {
|
||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
TFS(ProxyGetProperty, kProxy, kName, kReceiverValue) \
|
||||
TFS(ProxyHasProperty, kProxy, kName) \
|
||||
TFS(ProxySetProperty, kProxy, kName, kValue, kReceiverValue, kLanguageMode) \
|
||||
\
|
||||
/* Reflect */ \
|
||||
ASM(ReflectApply) \
|
||||
|
@ -322,257 +322,6 @@ TF_BUILTIN(ProxyHasProperty, ProxiesCodeStubAssembler) {
|
||||
StringConstant("has"), proxy);
|
||||
}
|
||||
|
||||
TF_BUILTIN(ProxyGetProperty, ProxiesCodeStubAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
Node* proxy = Parameter(Descriptor::kProxy);
|
||||
Node* name = Parameter(Descriptor::kName);
|
||||
Node* receiver = Parameter(Descriptor::kReceiverValue);
|
||||
|
||||
CSA_ASSERT(this, IsJSProxy(proxy));
|
||||
|
||||
// 1. Assert: IsPropertyKey(P) is true.
|
||||
CSA_ASSERT(this, TaggedIsNotSmi(name));
|
||||
CSA_ASSERT(this, IsName(name));
|
||||
CSA_ASSERT(this, Word32Equal(IsPrivateSymbol(name), Int32Constant(0)));
|
||||
|
||||
Label throw_proxy_handler_revoked(this, Label::kDeferred),
|
||||
trap_undefined(this);
|
||||
|
||||
// 2. Let handler be O.[[ProxyHandler]].
|
||||
Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
|
||||
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
GotoIf(IsNull(handler), &throw_proxy_handler_revoked);
|
||||
|
||||
// 4. Assert: Type(handler) is Object.
|
||||
CSA_ASSERT(this, IsJSReceiver(handler));
|
||||
|
||||
// 5. Let target be O.[[ProxyTarget]].
|
||||
Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
|
||||
|
||||
// 6. Let trap be ? GetMethod(handler, "get").
|
||||
// 7. If trap is undefined, then (see 7.a below).
|
||||
Handle<Name> trap_name = factory()->get_string();
|
||||
Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
|
||||
|
||||
// 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »).
|
||||
Node* trap_result = CallJS(
|
||||
CodeFactory::Call(isolate(), ConvertReceiverMode::kNotNullOrUndefined),
|
||||
context, trap, handler, target, name, receiver);
|
||||
|
||||
// 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
|
||||
Label return_result(this);
|
||||
CheckGetSetTrapResult(context, target, proxy, name, trap_result,
|
||||
&return_result, JSProxy::kGet);
|
||||
|
||||
BIND(&return_result);
|
||||
{
|
||||
// 11. Return trapResult.
|
||||
Return(trap_result);
|
||||
}
|
||||
|
||||
BIND(&trap_undefined);
|
||||
{
|
||||
// 7.a. Return ? target.[[Get]](P, Receiver).
|
||||
// TODO(mslekova): Introduce GetPropertyWithReceiver stub
|
||||
Return(CallRuntime(Runtime::kGetPropertyWithReceiver, context, target, name,
|
||||
receiver));
|
||||
}
|
||||
|
||||
BIND(&throw_proxy_handler_revoked);
|
||||
ThrowTypeError(context, MessageTemplate::kProxyRevoked, "get");
|
||||
}
|
||||
|
||||
TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
Node* proxy = Parameter(Descriptor::kProxy);
|
||||
Node* name = Parameter(Descriptor::kName);
|
||||
Node* value = Parameter(Descriptor::kValue);
|
||||
Node* receiver = Parameter(Descriptor::kReceiverValue);
|
||||
Node* language_mode = Parameter(Descriptor::kLanguageMode);
|
||||
|
||||
CSA_ASSERT(this, IsJSProxy(proxy));
|
||||
|
||||
// 1. Assert: IsPropertyKey(P) is true.
|
||||
CSA_ASSERT(this, TaggedIsNotSmi(name));
|
||||
CSA_ASSERT(this, IsName(name));
|
||||
|
||||
Label throw_proxy_handler_revoked(this, Label::kDeferred),
|
||||
trap_undefined(this), failure(this, Label::kDeferred),
|
||||
continue_checks(this), success(this),
|
||||
private_symbol(this, Label::kDeferred);
|
||||
|
||||
GotoIf(IsPrivateSymbol(name), &private_symbol);
|
||||
|
||||
// 2. Let handler be O.[[ProxyHandler]].
|
||||
Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
|
||||
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
GotoIfNot(IsJSReceiver(handler), &throw_proxy_handler_revoked);
|
||||
|
||||
// 4. Assert: Type(handler) is Object.
|
||||
CSA_ASSERT(this, IsJSReceiver(handler));
|
||||
|
||||
// 5. Let target be O.[[ProxyTarget]].
|
||||
Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
|
||||
|
||||
// 6. Let trap be ? GetMethod(handler, "set").
|
||||
// 7. If trap is undefined, then (see 7.a below).
|
||||
Handle<Name> set_string = factory()->set_string();
|
||||
Node* trap = GetMethod(context, handler, set_string, &trap_undefined);
|
||||
|
||||
// 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler,
|
||||
// « target, P, V, Receiver »)).
|
||||
// 9. If booleanTrapResult is false, return false.
|
||||
BranchIfToBooleanIsTrue(
|
||||
CallJS(CodeFactory::Call(isolate(),
|
||||
ConvertReceiverMode::kNotNullOrUndefined),
|
||||
context, trap, handler, target, name, value, receiver),
|
||||
&continue_checks, &failure);
|
||||
|
||||
BIND(&continue_checks);
|
||||
{
|
||||
// 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
|
||||
Label return_result(this);
|
||||
CheckGetSetTrapResult(context, target, proxy, name, value, &success,
|
||||
JSProxy::kSet);
|
||||
}
|
||||
|
||||
BIND(&failure);
|
||||
{
|
||||
Label if_throw(this, Label::kDeferred);
|
||||
Branch(SmiEqual(language_mode, SmiConstant(STRICT)), &if_throw, &success);
|
||||
|
||||
BIND(&if_throw);
|
||||
ThrowTypeError(context, MessageTemplate::kProxyTrapReturnedFalsishFor,
|
||||
HeapConstant(set_string), name);
|
||||
}
|
||||
|
||||
// 12. Return true.
|
||||
BIND(&success);
|
||||
Return(value);
|
||||
|
||||
BIND(&private_symbol);
|
||||
{
|
||||
Label failure(this), throw_error(this, Label::kDeferred);
|
||||
|
||||
Branch(SmiEqual(language_mode, SmiConstant(STRICT)), &throw_error,
|
||||
&failure);
|
||||
|
||||
BIND(&failure);
|
||||
Return(UndefinedConstant());
|
||||
|
||||
BIND(&throw_error);
|
||||
ThrowTypeError(context, MessageTemplate::kProxyPrivate);
|
||||
}
|
||||
|
||||
BIND(&trap_undefined);
|
||||
{
|
||||
// 7.a. Return ? target.[[Set]](P, V, Receiver).
|
||||
CallRuntime(Runtime::kSetPropertyWithReceiver, context, target, name, value,
|
||||
receiver, language_mode);
|
||||
Return(value);
|
||||
}
|
||||
|
||||
BIND(&throw_proxy_handler_revoked);
|
||||
ThrowTypeError(context, MessageTemplate::kProxyRevoked, "set");
|
||||
}
|
||||
|
||||
void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
|
||||
Node* context, Node* target, Node* proxy, Node* name, Node* trap_result,
|
||||
Label* check_passed, JSProxy::AccessKind access_kind) {
|
||||
Node* map = LoadMap(target);
|
||||
VARIABLE(var_value, MachineRepresentation::kTagged);
|
||||
VARIABLE(var_details, MachineRepresentation::kWord32);
|
||||
VARIABLE(var_raw_value, MachineRepresentation::kTagged);
|
||||
|
||||
Label if_found_value(this), check_in_runtime(this, Label::kDeferred);
|
||||
|
||||
Node* instance_type = LoadInstanceType(target);
|
||||
TryGetOwnProperty(context, target, target, map, instance_type, name,
|
||||
&if_found_value, &var_value, &var_details, &var_raw_value,
|
||||
check_passed, &check_in_runtime);
|
||||
|
||||
BIND(&if_found_value);
|
||||
{
|
||||
Label throw_non_configurable_data(this, Label::kDeferred),
|
||||
throw_non_configurable_accessor(this, Label::kDeferred),
|
||||
check_accessor(this), check_data(this);
|
||||
|
||||
// If targetDesc is not undefined and targetDesc.[[Configurable]] is
|
||||
// false, then:
|
||||
GotoIfNot(IsSetWord32(var_details.value(),
|
||||
PropertyDetails::kAttributesDontDeleteMask),
|
||||
check_passed);
|
||||
|
||||
// If IsDataDescriptor(targetDesc) is true and
|
||||
// targetDesc.[[Writable]] is false, then:
|
||||
BranchIfAccessorPair(var_raw_value.value(), &check_accessor, &check_data);
|
||||
|
||||
BIND(&check_data);
|
||||
{
|
||||
Node* read_only = IsSetWord32(var_details.value(),
|
||||
PropertyDetails::kAttributesReadOnlyMask);
|
||||
GotoIfNot(read_only, check_passed);
|
||||
|
||||
// If SameValue(trapResult, targetDesc.[[Value]]) is false,
|
||||
// throw a TypeError exception.
|
||||
GotoIfNot(SameValue(trap_result, var_value.value()),
|
||||
&throw_non_configurable_data);
|
||||
Goto(check_passed);
|
||||
}
|
||||
|
||||
BIND(&check_accessor);
|
||||
{
|
||||
Node* accessor_pair = var_raw_value.value();
|
||||
|
||||
if (access_kind == JSProxy::kGet) {
|
||||
Label continue_check(this, Label::kDeferred);
|
||||
// 10.b. If IsAccessorDescriptor(targetDesc) is true and
|
||||
// targetDesc.[[Get]] is undefined, then:
|
||||
Node* getter =
|
||||
LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
|
||||
// Here we check for null as well because if the getter was never
|
||||
// defined it's set as null.
|
||||
GotoIf(IsUndefined(getter), &continue_check);
|
||||
GotoIf(IsNull(getter), &continue_check);
|
||||
Goto(check_passed);
|
||||
|
||||
// 10.b.i. If trapResult is not undefined, throw a TypeError exception.
|
||||
BIND(&continue_check);
|
||||
GotoIfNot(IsUndefined(trap_result), &throw_non_configurable_accessor);
|
||||
} else {
|
||||
// 11.b.i. If targetDesc.[[Set]] is undefined, throw a TypeError
|
||||
// exception.
|
||||
Node* setter =
|
||||
LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
|
||||
GotoIf(IsUndefined(setter), &throw_non_configurable_accessor);
|
||||
GotoIf(IsNull(setter), &throw_non_configurable_accessor);
|
||||
}
|
||||
Goto(check_passed);
|
||||
}
|
||||
|
||||
BIND(&check_in_runtime);
|
||||
{
|
||||
CallRuntime(Runtime::kCheckProxyGetSetTrapResult, context, name, target,
|
||||
trap_result, SmiConstant(access_kind));
|
||||
Return(trap_result);
|
||||
}
|
||||
|
||||
BIND(&throw_non_configurable_data);
|
||||
{
|
||||
ThrowTypeError(context, MessageTemplate::kProxyGetNonConfigurableData,
|
||||
name, var_value.value(), trap_result);
|
||||
}
|
||||
|
||||
BIND(&throw_non_configurable_accessor);
|
||||
{
|
||||
ThrowTypeError(context, MessageTemplate::kProxyGetNonConfigurableAccessor,
|
||||
name, trap_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProxiesCodeStubAssembler::CheckHasTrapResult(Node* context, Node* target,
|
||||
Node* proxy, Node* name,
|
||||
Label* check_passed,
|
||||
|
@ -16,22 +16,6 @@ class ProxiesCodeStubAssembler : public CodeStubAssembler {
|
||||
explicit ProxiesCodeStubAssembler(compiler::CodeAssemblerState* state)
|
||||
: CodeStubAssembler(state) {}
|
||||
|
||||
void BranchIfAccessorPair(Node* value, Label* if_accessor_pair,
|
||||
Label* if_not_accessor_pair) {
|
||||
GotoIf(TaggedIsSmi(value), if_not_accessor_pair);
|
||||
Branch(IsAccessorPair(value), if_accessor_pair, if_not_accessor_pair);
|
||||
}
|
||||
|
||||
// ES6 section 9.5.8 [[Get]] ( P, Receiver )
|
||||
// name should not be an index.
|
||||
Node* ProxyGetProperty(Node* context, Node* proxy, Node* name,
|
||||
Node* receiver);
|
||||
|
||||
// ES6 section 9.5.9 [[Set]] ( P, V, Receiver )
|
||||
// name should not be an index.
|
||||
Node* ProxySetProperty(Node* context, Node* proxy, Node* name, Node* value,
|
||||
Node* receiver);
|
||||
|
||||
protected:
|
||||
void GotoIfRevokedProxy(Node* object, Label* if_proxy_revoked);
|
||||
Node* AllocateProxy(Node* target, Node* handler, Node* context);
|
||||
@ -40,10 +24,6 @@ class ProxiesCodeStubAssembler : public CodeStubAssembler {
|
||||
ParameterMode mode);
|
||||
void CheckHasTrapResult(Node* context, Node* target, Node* proxy, Node* name,
|
||||
Label* check_passed, Label* if_bailout);
|
||||
|
||||
void CheckGetSetTrapResult(Node* context, Node* target, Node* proxy,
|
||||
Node* name, Node* trap_result, Label* if_not_found,
|
||||
JSProxy::AccessKind access_kind);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
160
src/builtins/builtins-proxy-helpers-gen.cc
Normal file
160
src/builtins/builtins-proxy-helpers-gen.cc
Normal file
@ -0,0 +1,160 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#include "src/builtins/builtins-proxy-helpers-gen.h"
|
||||
#include "src/builtins/builtins-utils-gen.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
TF_BUILTIN(ProxyGetProperty, ProxyAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
Node* proxy = Parameter(Descriptor::kProxy);
|
||||
Node* name = Parameter(Descriptor::kName);
|
||||
Node* receiver = Parameter(Descriptor::kReceiverValue);
|
||||
|
||||
CSA_ASSERT(this, IsJSProxy(proxy));
|
||||
|
||||
// 1. Assert: IsPropertyKey(P) is true.
|
||||
CSA_ASSERT(this, IsName(name));
|
||||
|
||||
Label throw_proxy_handler_revoked(this, Label::kDeferred),
|
||||
trap_undefined(this), no_target_desc(this, Label::kDeferred),
|
||||
trap_not_callable(this, Label::kDeferred);
|
||||
|
||||
// 2. Let handler be O.[[ProxyHandler]].
|
||||
Node* handler = LoadObjectField(proxy, JSProxy::kHandlerOffset);
|
||||
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
GotoIf(IsNull(handler), &throw_proxy_handler_revoked);
|
||||
|
||||
// 4. Assert: Type(handler) is Object.
|
||||
CSA_ASSERT(this, IsJSReceiver(handler));
|
||||
|
||||
// 5. Let target be O.[[ProxyTarget]].
|
||||
Node* target = LoadObjectField(proxy, JSProxy::kTargetOffset);
|
||||
|
||||
// 6. Let trap be ? GetMethod(handler, "get").
|
||||
// 7. If trap is undefined, then (see 7.a below).
|
||||
Handle<Name> trap_name = factory()->get_string();
|
||||
Node* trap = GetMethod(context, handler, trap_name, &trap_undefined);
|
||||
|
||||
GotoIf(TaggedIsSmi(trap), &trap_not_callable);
|
||||
GotoIfNot(IsCallable(trap), &trap_not_callable);
|
||||
|
||||
// 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »).
|
||||
Node* trap_result = CallJS(CodeFactory::Call(isolate()), context, trap,
|
||||
handler, target, name, receiver);
|
||||
// 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
|
||||
Label return_result(this);
|
||||
CheckGetTrapResult(context, target, proxy, name, trap_result, &return_result,
|
||||
&no_target_desc);
|
||||
|
||||
BIND(&return_result);
|
||||
{
|
||||
// 11. Return trapResult.
|
||||
Return(trap_result);
|
||||
}
|
||||
|
||||
BIND(&no_target_desc);
|
||||
{
|
||||
CSA_ASSERT(this, IsJSReceiver(target));
|
||||
CallRuntime(Runtime::kCheckProxyGetTrapResult, context, name, target,
|
||||
trap_result);
|
||||
Return(trap_result);
|
||||
}
|
||||
|
||||
BIND(&trap_undefined);
|
||||
{
|
||||
// 7.a. Return ? target.[[Get]](P, Receiver).
|
||||
Return(CallRuntime(Runtime::kGetPropertyWithReceiver, context, target, name,
|
||||
receiver));
|
||||
}
|
||||
|
||||
BIND(&throw_proxy_handler_revoked);
|
||||
{ ThrowTypeError(context, MessageTemplate::kProxyRevoked, "get"); }
|
||||
|
||||
BIND(&trap_not_callable);
|
||||
{
|
||||
ThrowTypeError(context, MessageTemplate::kPropertyNotFunction, trap,
|
||||
StringConstant("get"), receiver);
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyAssembler::CheckGetTrapResult(Node* context, Node* target,
|
||||
Node* proxy, Node* name,
|
||||
Node* trap_result, Label* check_passed,
|
||||
Label* if_bailout) {
|
||||
Node* map = LoadMap(target);
|
||||
VARIABLE(var_value, MachineRepresentation::kTagged);
|
||||
VARIABLE(var_details, MachineRepresentation::kWord32);
|
||||
VARIABLE(var_raw_value, MachineRepresentation::kTagged);
|
||||
|
||||
Label if_found_value(this, Label::kDeferred);
|
||||
|
||||
Node* instance_type = LoadInstanceType(target);
|
||||
TryGetOwnProperty(context, proxy, target, map, instance_type, name,
|
||||
&if_found_value, &var_value, &var_details, &var_raw_value,
|
||||
check_passed, if_bailout);
|
||||
|
||||
BIND(&if_found_value);
|
||||
{
|
||||
Label throw_non_configurable_data(this, Label::kDeferred),
|
||||
throw_non_configurable_accessor(this, Label::kDeferred),
|
||||
check_accessor(this), check_data(this);
|
||||
|
||||
// 10. If targetDesc is not undefined and targetDesc.[[Configurable]] is
|
||||
// false, then:
|
||||
GotoIfNot(IsSetWord32(var_details.value(),
|
||||
PropertyDetails::kAttributesDontDeleteMask),
|
||||
check_passed);
|
||||
|
||||
// 10.a. If IsDataDescriptor(targetDesc) is true and
|
||||
// targetDesc.[[Writable]] is false, then:
|
||||
BranchIfAccessorPair(var_raw_value.value(), &check_accessor, &check_data);
|
||||
|
||||
BIND(&check_data);
|
||||
{
|
||||
Node* read_only = IsSetWord32(var_details.value(),
|
||||
PropertyDetails::kAttributesReadOnlyMask);
|
||||
GotoIfNot(read_only, check_passed);
|
||||
|
||||
// 10.a.i. If SameValue(trapResult, targetDesc.[[Value]]) is false,
|
||||
// throw a TypeError exception.
|
||||
GotoIfNot(SameValue(trap_result, var_value.value()),
|
||||
&throw_non_configurable_data);
|
||||
Goto(check_passed);
|
||||
}
|
||||
|
||||
BIND(&check_accessor);
|
||||
{
|
||||
// 10.b. If IsAccessorDescriptor(targetDesc) is true and
|
||||
// targetDesc.[[Get]] is undefined, then:
|
||||
Node* accessor_pair = var_raw_value.value();
|
||||
Node* getter =
|
||||
LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
|
||||
|
||||
// Here we check for null as well because if the getter was never
|
||||
// defined it's set as null.
|
||||
GotoIfNot(Word32Or(IsUndefined(getter), IsNull(getter)), check_passed);
|
||||
|
||||
// 10.b.i. If trapResult is not undefined, throw a TypeError exception.
|
||||
GotoIfNot(IsUndefined(trap_result), &throw_non_configurable_accessor);
|
||||
Goto(check_passed);
|
||||
}
|
||||
|
||||
BIND(&throw_non_configurable_data);
|
||||
{
|
||||
ThrowTypeError(context, MessageTemplate::kProxyGetNonConfigurableData,
|
||||
name, var_value.value(), trap_result);
|
||||
}
|
||||
|
||||
BIND(&throw_non_configurable_accessor);
|
||||
{
|
||||
ThrowTypeError(context, MessageTemplate::kProxyGetNonConfigurableAccessor,
|
||||
name, trap_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace v8
|
38
src/builtins/builtins-proxy-helpers-gen.h
Normal file
38
src/builtins/builtins-proxy-helpers-gen.h
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
#ifndef V8_BUILTINS_BUILTINS_PROXY_HELPERS_GEN_H_
|
||||
#define V8_BUILTINS_BUILTINS_PROXY_HELPERS_GEN_H_
|
||||
|
||||
#include "src/code-stub-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
using compiler::Node;
|
||||
|
||||
class ProxyAssembler : public CodeStubAssembler {
|
||||
public:
|
||||
explicit ProxyAssembler(compiler::CodeAssemblerState* state)
|
||||
: CodeStubAssembler(state) {}
|
||||
|
||||
void BranchIfAccessorPair(Node* value, Label* if_accessor_pair,
|
||||
Label* if_not_accessor_pair) {
|
||||
GotoIf(TaggedIsSmi(value), if_not_accessor_pair);
|
||||
Branch(IsAccessorPair(value), if_accessor_pair, if_not_accessor_pair);
|
||||
}
|
||||
|
||||
// ES6 section 9.5.8 [[Get]] ( P, Receiver )
|
||||
Node* ProxyGetProperty(Node* context, Node* proxy, Node* name,
|
||||
Node* receiver);
|
||||
|
||||
protected:
|
||||
void CheckGetTrapResult(Node* context, Node* target, Node* proxy, Node* name,
|
||||
Node* trap_result, Label* if_not_found,
|
||||
Label* if_bailout);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_BUILTINS_BUILTINS_PROXY_HELPERS_GEN_H_
|
@ -6916,7 +6916,6 @@ void CodeStubAssembler::EmitElementStore(Node* object, Node* key, Node* value,
|
||||
ElementsKind elements_kind,
|
||||
KeyedAccessStoreMode store_mode,
|
||||
Label* bailout) {
|
||||
CSA_ASSERT(this, Word32BinaryNot(IsJSProxy(object)));
|
||||
Node* elements = LoadElements(object);
|
||||
if (IsSmiOrObjectElementsKind(elements_kind) &&
|
||||
store_mode != STORE_NO_TRANSITION_HANDLE_COW) {
|
||||
|
@ -852,10 +852,6 @@ KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
|
||||
// Element store with prototype chain check.
|
||||
Handle<Tuple2> data_handler = Handle<Tuple2>::cast(maybe_code_handler);
|
||||
handler = handle(Code::cast(data_handler->value2()));
|
||||
} else if (maybe_code_handler->IsSmi()) {
|
||||
// Skip proxy handlers.
|
||||
DCHECK_EQ(*maybe_code_handler, *StoreHandler::StoreProxy(GetIsolate()));
|
||||
continue;
|
||||
} else {
|
||||
// Element store without prototype chain check.
|
||||
handler = Handle<Code>::cast(maybe_code_handler);
|
||||
|
@ -261,8 +261,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
|
||||
|
||||
Label constant(this), field(this), normal(this, Label::kDeferred),
|
||||
interceptor(this, Label::kDeferred), nonexistent(this),
|
||||
accessor(this, Label::kDeferred), global(this, Label::kDeferred),
|
||||
module_export(this, Label::kDeferred), proxy(this, Label::kDeferred);
|
||||
accessor(this, Label::kDeferred), proxy(this, Label::kDeferred),
|
||||
global(this, Label::kDeferred), module_export(this, Label::kDeferred);
|
||||
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field);
|
||||
|
||||
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
|
||||
@ -370,35 +370,9 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
|
||||
|
||||
BIND(&proxy);
|
||||
{
|
||||
VARIABLE(var_index, MachineType::PointerRepresentation());
|
||||
VARIABLE(var_unique, MachineRepresentation::kTagged);
|
||||
|
||||
Label if_index(this), if_unique_name(this),
|
||||
to_name_failed(this, Label::kDeferred);
|
||||
|
||||
if (support_elements == kSupportElements) {
|
||||
TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
|
||||
&to_name_failed);
|
||||
|
||||
BIND(&if_unique_name);
|
||||
exit_point->ReturnCallStub(
|
||||
Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
|
||||
p->context, holder, var_unique.value(), p->receiver);
|
||||
|
||||
BIND(&if_index);
|
||||
// TODO(mslekova): introduce TryToName that doesn't try to compute
|
||||
// the intptr index value
|
||||
Goto(&to_name_failed);
|
||||
|
||||
BIND(&to_name_failed);
|
||||
exit_point->ReturnCallRuntime(Runtime::kGetPropertyWithReceiver,
|
||||
p->context, holder, p->name, p->receiver);
|
||||
|
||||
} else {
|
||||
exit_point->ReturnCallStub(
|
||||
Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
|
||||
p->context, holder, p->name, p->receiver);
|
||||
}
|
||||
exit_point->ReturnCallStub(
|
||||
Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
|
||||
p->context, holder, p->name, p->receiver);
|
||||
}
|
||||
|
||||
BIND(&global);
|
||||
@ -638,7 +612,7 @@ void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable,
|
||||
|
||||
void AccessorAssembler::HandleStoreICHandlerCase(
|
||||
const StoreICParameters* p, Node* handler, Label* miss,
|
||||
LanguageMode language_mode, ElementSupport support_elements) {
|
||||
ElementSupport support_elements) {
|
||||
Label if_smi_handler(this), if_nonsmi_handler(this);
|
||||
Label if_proto_handler(this), if_element_handler(this), call_handler(this),
|
||||
store_global(this);
|
||||
@ -652,17 +626,10 @@ void AccessorAssembler::HandleStoreICHandlerCase(
|
||||
Node* holder = p->receiver;
|
||||
Node* handler_word = SmiUntag(handler);
|
||||
|
||||
Label if_fast_smi(this), if_proxy(this);
|
||||
|
||||
STATIC_ASSERT(StoreHandler::kStoreNormal + 1 == StoreHandler::kProxy);
|
||||
STATIC_ASSERT(StoreHandler::kProxy + 1 == StoreHandler::kKindsNumber);
|
||||
|
||||
Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
|
||||
GotoIf(IntPtrLessThan(handler_kind,
|
||||
IntPtrConstant(StoreHandler::kStoreNormal)),
|
||||
&if_fast_smi);
|
||||
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)),
|
||||
&if_proxy);
|
||||
Label if_fast_smi(this), slow(this);
|
||||
GotoIfNot(
|
||||
WordEqual(handler_word, IntPtrConstant(StoreHandler::kStoreNormal)),
|
||||
&if_fast_smi);
|
||||
|
||||
Node* properties = LoadSlowProperties(holder);
|
||||
|
||||
@ -688,9 +655,6 @@ void AccessorAssembler::HandleStoreICHandlerCase(
|
||||
BIND(&if_fast_smi);
|
||||
// Handle non-transitioning field stores.
|
||||
HandleStoreICSmiHandlerCase(handler_word, holder, p->value, nullptr, miss);
|
||||
|
||||
BIND(&if_proxy);
|
||||
HandleStoreToProxy(p, holder, miss, support_elements, language_mode);
|
||||
}
|
||||
|
||||
BIND(&if_nonsmi_handler);
|
||||
@ -709,10 +673,7 @@ void AccessorAssembler::HandleStoreICHandlerCase(
|
||||
}
|
||||
|
||||
BIND(&if_proto_handler);
|
||||
{
|
||||
HandleStoreICProtoHandler(p, handler, miss, support_elements,
|
||||
language_mode);
|
||||
}
|
||||
{ HandleStoreICProtoHandler(p, handler, miss, support_elements); }
|
||||
|
||||
// |handler| is a heap object. Must be code, call it.
|
||||
BIND(&call_handler);
|
||||
@ -801,7 +762,7 @@ void AccessorAssembler::HandleStoreICElementHandlerCase(
|
||||
|
||||
void AccessorAssembler::HandleStoreICProtoHandler(
|
||||
const StoreICParameters* p, Node* handler, Label* miss,
|
||||
ElementSupport support_elements, LanguageMode language_mode) {
|
||||
ElementSupport support_elements) {
|
||||
// IC dispatchers rely on these assumptions to be held.
|
||||
STATIC_ASSERT(FixedArray::kLengthOffset ==
|
||||
StoreHandler::kTransitionCellOffset);
|
||||
@ -831,12 +792,12 @@ void AccessorAssembler::HandleStoreICProtoHandler(
|
||||
|
||||
VARIABLE(var_transition, MachineRepresentation::kTagged);
|
||||
Label if_transition(this), if_transition_to_constant(this),
|
||||
if_store_normal(this), if_proxy(this), do_store(this);
|
||||
if_store_normal(this);
|
||||
BIND(&tuple_handler);
|
||||
{
|
||||
Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
|
||||
var_transition.Bind(transition);
|
||||
Goto(&do_store);
|
||||
Goto(&if_transition);
|
||||
}
|
||||
|
||||
BIND(&array_handler);
|
||||
@ -854,19 +815,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
|
||||
LoadFixedArrayElement(handler, StoreHandler::kTransitionCellIndex);
|
||||
Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
|
||||
var_transition.Bind(transition);
|
||||
Goto(&do_store);
|
||||
}
|
||||
|
||||
BIND(&do_store);
|
||||
{
|
||||
Branch(SmiEqual(smi_or_code, SmiConstant(StoreHandler::kProxy)), &if_proxy,
|
||||
&if_transition);
|
||||
}
|
||||
|
||||
BIND(&if_proxy);
|
||||
{
|
||||
Node* proxy = var_transition.value();
|
||||
HandleStoreToProxy(p, proxy, miss, support_elements, language_mode);
|
||||
Goto(&if_transition);
|
||||
}
|
||||
|
||||
BIND(&if_transition);
|
||||
@ -917,8 +866,9 @@ void AccessorAssembler::HandleStoreICProtoHandler(
|
||||
DescriptorArray::kEntryValueIndex));
|
||||
Node* descriptors = LoadMapDescriptors(transition);
|
||||
CSA_ASSERT(
|
||||
this, UintPtrLessThan(descriptor,
|
||||
LoadAndUntagFixedArrayBaseLength(descriptors)));
|
||||
this,
|
||||
UintPtrLessThan(descriptor,
|
||||
LoadAndUntagFixedArrayBaseLength(descriptors)));
|
||||
|
||||
Node* constant = LoadFixedArrayElement(descriptors, value_index);
|
||||
GotoIf(WordNotEqual(p->value, constant), miss);
|
||||
@ -965,42 +915,6 @@ void AccessorAssembler::HandleStoreICProtoHandler(
|
||||
}
|
||||
}
|
||||
|
||||
void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
|
||||
Node* proxy, Label* miss,
|
||||
ElementSupport support_elements,
|
||||
LanguageMode language_mode) {
|
||||
VARIABLE(var_index, MachineType::PointerRepresentation());
|
||||
VARIABLE(var_unique, MachineRepresentation::kTagged);
|
||||
|
||||
Label if_index(this), if_unique_name(this),
|
||||
to_name_failed(this, Label::kDeferred);
|
||||
|
||||
if (support_elements == kSupportElements) {
|
||||
TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
|
||||
&to_name_failed);
|
||||
|
||||
BIND(&if_unique_name);
|
||||
CallBuiltin(Builtins::kProxySetProperty, p->context, proxy,
|
||||
var_unique.value(), p->value, p->receiver,
|
||||
SmiConstant(language_mode));
|
||||
Return(p->value);
|
||||
|
||||
// The index case is handled earlier by the runtime.
|
||||
BIND(&if_index);
|
||||
// TODO(mslekova): introduce TryToName that doesn't try to compute
|
||||
// the intptr index value
|
||||
Goto(&to_name_failed);
|
||||
|
||||
BIND(&to_name_failed);
|
||||
TailCallRuntime(Runtime::kSetPropertyWithReceiver, p->context, proxy,
|
||||
p->name, p->value, p->receiver, SmiConstant(language_mode));
|
||||
} else {
|
||||
Node* name = ToName(p->context, p->name);
|
||||
TailCallBuiltin(Builtins::kProxySetProperty, p->context, proxy, name,
|
||||
p->value, p->receiver, SmiConstant(language_mode));
|
||||
}
|
||||
}
|
||||
|
||||
void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
|
||||
Node* holder, Node* value,
|
||||
Node* transition,
|
||||
@ -2323,7 +2237,7 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p,
|
||||
BIND(&if_handler);
|
||||
{
|
||||
Comment("StoreIC_if_handler");
|
||||
HandleStoreICHandlerCase(p, var_handler.value(), &miss, language_mode);
|
||||
HandleStoreICHandlerCase(p, var_handler.value(), &miss);
|
||||
}
|
||||
|
||||
BIND(&try_polymorphic);
|
||||
@ -2384,8 +2298,7 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p,
|
||||
BIND(&if_handler);
|
||||
{
|
||||
Comment("KeyedStoreIC_if_handler");
|
||||
HandleStoreICHandlerCase(p, var_handler.value(), &miss, language_mode,
|
||||
kSupportElements);
|
||||
HandleStoreICHandlerCase(p, var_handler.value(), &miss, kSupportElements);
|
||||
}
|
||||
|
||||
BIND(&try_polymorphic);
|
||||
|
@ -93,7 +93,6 @@ class AccessorAssembler : public CodeStubAssembler {
|
||||
enum ElementSupport { kOnlyProperties, kSupportElements };
|
||||
void HandleStoreICHandlerCase(
|
||||
const StoreICParameters* p, Node* handler, Label* miss,
|
||||
LanguageMode language_mode,
|
||||
ElementSupport support_elements = kOnlyProperties);
|
||||
void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
|
||||
|
||||
@ -165,8 +164,7 @@ class AccessorAssembler : public CodeStubAssembler {
|
||||
Node* handler, Label* miss);
|
||||
|
||||
void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler,
|
||||
Label* miss, ElementSupport support_elements,
|
||||
LanguageMode language_mode);
|
||||
Label* miss, ElementSupport support_elements);
|
||||
// If |transition| is nullptr then the normal field store is generated or
|
||||
// transitioning store otherwise.
|
||||
void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
|
||||
@ -177,10 +175,6 @@ class AccessorAssembler : public CodeStubAssembler {
|
||||
Representation representation, Node* value,
|
||||
Node* transition, Label* miss);
|
||||
|
||||
void HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss,
|
||||
ElementSupport support_elements,
|
||||
LanguageMode language_mode);
|
||||
|
||||
// KeyedLoadIC_Generic implementation.
|
||||
|
||||
void GenericElementLoad(Node* receiver, Node* receiver_map,
|
||||
|
@ -113,11 +113,6 @@ Handle<Smi> StoreHandler::StoreNormal(Isolate* isolate) {
|
||||
return handle(Smi::FromInt(config), isolate);
|
||||
}
|
||||
|
||||
Handle<Smi> StoreHandler::StoreProxy(Isolate* isolate) {
|
||||
int config = KindBits::encode(kProxy);
|
||||
return handle(Smi::FromInt(config), isolate);
|
||||
}
|
||||
|
||||
Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind,
|
||||
int descriptor, FieldIndex field_index,
|
||||
Representation representation,
|
||||
|
@ -160,10 +160,8 @@ class StoreHandler {
|
||||
kStoreElement,
|
||||
kStoreField,
|
||||
kStoreConstField,
|
||||
kTransitionToField,
|
||||
kStoreNormal,
|
||||
kProxy,
|
||||
kKindsNumber, // Keep last
|
||||
kTransitionToField,
|
||||
// TODO(ishell): remove once constant field tracking is done.
|
||||
kTransitionToConstant = kStoreConstField
|
||||
};
|
||||
@ -229,9 +227,6 @@ class StoreHandler {
|
||||
// Creates a Smi-handler for storing a property to a slow object.
|
||||
static inline Handle<Smi> StoreNormal(Isolate* isolate);
|
||||
|
||||
// Creates a Smi-handler for storing a property on a proxy.
|
||||
static inline Handle<Smi> StoreProxy(Isolate* isolate);
|
||||
|
||||
// Creates a Smi-handler for transitioning store to a field.
|
||||
static inline Handle<Smi> TransitionToField(Isolate* isolate, int descriptor,
|
||||
FieldIndex field_index,
|
||||
|
102
src/ic/ic.cc
102
src/ic/ic.cc
@ -1223,7 +1223,8 @@ static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
|
||||
|
||||
void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
|
||||
Handle<Map> receiver_map(receiver->map(), isolate());
|
||||
DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE); // Checked by caller.
|
||||
DCHECK(receiver_map->instance_type() != JS_VALUE_TYPE &&
|
||||
receiver_map->instance_type() != JS_PROXY_TYPE); // Checked by caller.
|
||||
MapHandles target_receiver_maps;
|
||||
TargetMaps(&target_receiver_maps);
|
||||
|
||||
@ -1305,9 +1306,6 @@ Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map) {
|
||||
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
|
||||
return BUILTIN_CODE(isolate(), KeyedLoadIC_Slow);
|
||||
}
|
||||
if (instance_type == JS_PROXY_TYPE) {
|
||||
return LoadHandler::LoadProxy(isolate());
|
||||
}
|
||||
|
||||
ElementsKind elements_kind = receiver_map->elements_kind();
|
||||
if (IsSloppyArgumentsElementsKind(elements_kind)) {
|
||||
@ -1380,7 +1378,7 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
|
||||
Object);
|
||||
} else if (FLAG_use_ic && !object->IsAccessCheckNeeded() &&
|
||||
!object->IsJSValue()) {
|
||||
if ((object->IsJSReceiver() && key->IsSmi()) ||
|
||||
if ((object->IsJSObject() && key->IsSmi()) ||
|
||||
(object->IsString() && key->IsNumber())) {
|
||||
UpdateLoadElement(Handle<HeapObject>::cast(object));
|
||||
if (is_vector_set()) {
|
||||
@ -1408,7 +1406,6 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
|
||||
JSReceiver::StoreFromKeyed store_mode) {
|
||||
// Disable ICs for non-JSObjects for now.
|
||||
Handle<Object> object = it->GetReceiver();
|
||||
if (object->IsJSProxy()) return true;
|
||||
if (!object->IsJSObject()) return false;
|
||||
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
||||
DCHECK(!receiver->map()->is_deprecated());
|
||||
@ -1419,7 +1416,7 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
|
||||
case LookupIterator::TRANSITION:
|
||||
UNREACHABLE();
|
||||
case LookupIterator::JSPROXY:
|
||||
return true;
|
||||
return false;
|
||||
case LookupIterator::INTERCEPTOR: {
|
||||
Handle<JSObject> holder = it->GetHolder<JSObject>();
|
||||
InterceptorInfo* info = holder->GetNamedInterceptor();
|
||||
@ -1521,7 +1518,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
|
||||
JSReceiver::StoreFromKeyed store_mode) {
|
||||
// TODO(verwaest): Let SetProperty do the migration, since storing a property
|
||||
// might deprecate the current map again, if value does not fit.
|
||||
if (MigrateDeprecated(object)) {
|
||||
if (MigrateDeprecated(object) || object->IsJSProxy()) {
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate(), result,
|
||||
@ -1665,45 +1662,6 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
|
||||
return handler_array;
|
||||
}
|
||||
|
||||
Handle<Object> StoreIC::StoreProxy(Handle<Map> receiver_map,
|
||||
Handle<JSProxy> proxy,
|
||||
Handle<JSReceiver> receiver,
|
||||
Handle<Name> name) {
|
||||
Handle<Object> smi_handler = StoreHandler::StoreProxy(isolate());
|
||||
|
||||
if (receiver.is_identical_to(proxy)) {
|
||||
return smi_handler;
|
||||
}
|
||||
|
||||
int checks_count =
|
||||
GetPrototypeCheckCount(isolate(), receiver_map, proxy, name);
|
||||
|
||||
DCHECK_LE(0, checks_count);
|
||||
DCHECK(!receiver_map->IsJSGlobalObjectMap());
|
||||
|
||||
Handle<Object> validity_cell =
|
||||
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
|
||||
if (validity_cell.is_null()) {
|
||||
DCHECK_EQ(0, checks_count);
|
||||
validity_cell = handle(Smi::kZero, isolate());
|
||||
}
|
||||
|
||||
Factory* factory = isolate()->factory();
|
||||
Handle<WeakCell> holder_cell = factory->NewWeakCell(proxy);
|
||||
|
||||
if (checks_count == 0) {
|
||||
return factory->NewTuple3(holder_cell, smi_handler, validity_cell, TENURED);
|
||||
}
|
||||
Handle<FixedArray> handler_array(factory->NewFixedArray(
|
||||
StoreHandler::kFirstPrototypeIndex + checks_count, TENURED));
|
||||
handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler);
|
||||
handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell);
|
||||
handler_array->set(StoreHandler::kTransitionCellIndex, *holder_cell);
|
||||
InitPrototypeChecks(isolate(), receiver_map, proxy, name, handler_array,
|
||||
StoreHandler::kFirstPrototypeIndex);
|
||||
return handler_array;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Handle<Object> StoreGlobal(Isolate* isolate, Handle<PropertyCell> cell) {
|
||||
@ -1713,10 +1671,15 @@ Handle<Object> StoreGlobal(Isolate* isolate, Handle<PropertyCell> cell) {
|
||||
} // namespace
|
||||
|
||||
Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
|
||||
|
||||
// This is currently guaranteed by checks in StoreIC::Store.
|
||||
Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
|
||||
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
||||
DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
|
||||
|
||||
switch (lookup->state()) {
|
||||
case LookupIterator::TRANSITION: {
|
||||
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
||||
|
||||
auto store_target = lookup->GetStoreTarget();
|
||||
if (store_target->IsJSGlobalObject()) {
|
||||
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
|
||||
@ -1740,9 +1703,6 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
}
|
||||
|
||||
case LookupIterator::INTERCEPTOR: {
|
||||
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
||||
USE(holder);
|
||||
|
||||
DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined(isolate()));
|
||||
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
|
||||
StoreInterceptorStub stub(isolate());
|
||||
@ -1750,11 +1710,6 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
}
|
||||
|
||||
case LookupIterator::ACCESSOR: {
|
||||
// This is currently guaranteed by checks in StoreIC::Store.
|
||||
Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
|
||||
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
||||
DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
|
||||
|
||||
if (!holder->HasFastProperties()) {
|
||||
TRACE_GENERIC_IC("accessor on slow map");
|
||||
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
||||
@ -1805,12 +1760,6 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
}
|
||||
|
||||
case LookupIterator::DATA: {
|
||||
// This is currently guaranteed by checks in StoreIC::Store.
|
||||
Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
|
||||
USE(receiver);
|
||||
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
||||
DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
|
||||
|
||||
DCHECK_EQ(kData, lookup->property_details().kind());
|
||||
if (lookup->is_dictionary_holder()) {
|
||||
if (holder->IsJSGlobalObject()) {
|
||||
@ -1843,16 +1792,10 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
||||
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
||||
return slow_stub();
|
||||
}
|
||||
case LookupIterator::JSPROXY: {
|
||||
Handle<JSReceiver> receiver =
|
||||
Handle<JSReceiver>::cast(lookup->GetReceiver());
|
||||
Handle<JSProxy> holder = lookup->GetHolder<JSProxy>();
|
||||
return StoreIC::StoreProxy(receiver_map(), holder, receiver,
|
||||
lookup->name());
|
||||
}
|
||||
|
||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
case LookupIterator::JSPROXY:
|
||||
case LookupIterator::NOT_FOUND:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -1933,8 +1876,7 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
|
||||
// transition to a different GetNonTransitioningStoreMode IC that handles a
|
||||
// superset of the original IC. Handle those here if the receiver map hasn't
|
||||
// changed or it has transitioned to a more general kind.
|
||||
KeyedAccessStoreMode old_store_mode;
|
||||
old_store_mode = GetKeyedAccessStoreMode();
|
||||
KeyedAccessStoreMode old_store_mode = GetKeyedAccessStoreMode();
|
||||
Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
|
||||
if (state() == MONOMORPHIC) {
|
||||
Handle<Map> transitioned_receiver_map = receiver_map;
|
||||
@ -2069,10 +2011,6 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
|
||||
store_mode == STORE_NO_TRANSITION_HANDLE_COW);
|
||||
DCHECK(!receiver_map->DictionaryElementsInPrototypeChainOnly());
|
||||
|
||||
if (receiver_map->IsJSProxyMap()) {
|
||||
return StoreHandler::StoreProxy(isolate());
|
||||
}
|
||||
|
||||
ElementsKind elements_kind = receiver_map->elements_kind();
|
||||
bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
|
||||
Handle<Code> stub;
|
||||
@ -2284,17 +2222,15 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
|
||||
bool is_arguments = false;
|
||||
bool key_is_valid_index = false;
|
||||
KeyedAccessStoreMode store_mode = STANDARD_STORE;
|
||||
if (use_ic && object->IsJSReceiver()) {
|
||||
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
|
||||
if (use_ic && object->IsJSObject()) {
|
||||
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
||||
old_receiver_map = handle(receiver->map(), isolate());
|
||||
is_arguments = receiver->IsJSArgumentsObject();
|
||||
bool is_proxy = receiver->IsJSProxy();
|
||||
key_is_valid_index = key->IsSmi() && Smi::ToInt(*key) >= 0;
|
||||
if (!is_arguments && !is_proxy) {
|
||||
if (!is_arguments) {
|
||||
key_is_valid_index = key->IsSmi() && Smi::ToInt(*key) >= 0;
|
||||
if (key_is_valid_index) {
|
||||
uint32_t index = static_cast<uint32_t>(Smi::ToInt(*key));
|
||||
Handle<JSObject> receiver_object = Handle<JSObject>::cast(object);
|
||||
store_mode = GetStoreMode(receiver_object, index, value);
|
||||
store_mode = GetStoreMode(receiver, index, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -359,9 +359,6 @@ class StoreIC : public IC {
|
||||
Handle<JSObject> holder,
|
||||
Handle<Map> transition, Handle<Name> name);
|
||||
|
||||
Handle<Object> StoreProxy(Handle<Map> receiver_map, Handle<JSProxy> proxy,
|
||||
Handle<JSReceiver> receiver, Handle<Name> name);
|
||||
|
||||
friend class IC;
|
||||
|
||||
bool created_new_transition_ = false;
|
||||
|
@ -841,8 +841,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
|
||||
BIND(&found_handler);
|
||||
{
|
||||
Comment("KeyedStoreGeneric found transition handler");
|
||||
HandleStoreICHandlerCase(p, var_handler.value(), notfound,
|
||||
language_mode);
|
||||
HandleStoreICHandlerCase(p, var_handler.value(), notfound);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -950,8 +949,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
|
||||
BIND(&found_handler);
|
||||
{
|
||||
Comment("KeyedStoreGeneric found handler");
|
||||
HandleStoreICHandlerCase(p, var_handler.value(), &stub_cache_miss,
|
||||
language_mode);
|
||||
HandleStoreICHandlerCase(p, var_handler.value(), &stub_cache_miss);
|
||||
}
|
||||
BIND(&stub_cache_miss);
|
||||
{
|
||||
@ -1022,14 +1020,13 @@ void KeyedStoreGenericAssembler::StoreIC_Uninitialized(
|
||||
Node* vector = Parameter(Descriptor::kVector);
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
|
||||
Label miss(this), if_proxy(this, Label::kDeferred);
|
||||
Label miss(this);
|
||||
|
||||
GotoIf(TaggedIsSmi(receiver), &miss);
|
||||
Node* receiver_map = LoadMap(receiver);
|
||||
Node* instance_type = LoadMapInstanceType(receiver_map);
|
||||
GotoIf(Word32Equal(instance_type, Int32Constant(JS_PROXY_TYPE)), &if_proxy);
|
||||
// Receivers requiring non-standard element accesses (interceptors, access
|
||||
// checks, strings and string wrappers) are handled in the runtime.
|
||||
// checks, strings and string wrappers, proxies) are handled in the runtime.
|
||||
GotoIf(Int32LessThanOrEqual(instance_type,
|
||||
Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
|
||||
&miss);
|
||||
@ -1043,12 +1040,6 @@ void KeyedStoreGenericAssembler::StoreIC_Uninitialized(
|
||||
EmitGenericPropertyStore(receiver, receiver_map, &p, &miss, language_mode,
|
||||
kDontUseStubCache);
|
||||
|
||||
BIND(&if_proxy);
|
||||
{
|
||||
CallBuiltin(Builtins::kProxySetProperty, context, receiver, name, value,
|
||||
receiver, SmiConstant(language_mode));
|
||||
Return(value);
|
||||
}
|
||||
BIND(&miss);
|
||||
{
|
||||
// Undo the optimistic state transition.
|
||||
|
@ -13,42 +13,12 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// static
|
||||
LookupIterator LookupIterator::PropertyOrElement(
|
||||
Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
|
||||
bool* success, Handle<JSReceiver> holder, Configuration configuration) {
|
||||
uint32_t index = 0;
|
||||
if (key->ToArrayIndex(&index)) {
|
||||
*success = true;
|
||||
return LookupIterator(isolate, receiver, index, holder, configuration);
|
||||
}
|
||||
|
||||
Handle<Name> name;
|
||||
*success = Object::ToName(isolate, key).ToHandle(&name);
|
||||
if (!*success) {
|
||||
DCHECK(isolate->has_pending_exception());
|
||||
// Return an unusable dummy.
|
||||
return LookupIterator(receiver, isolate->factory()->empty_string());
|
||||
}
|
||||
|
||||
if (name->AsArrayIndex(&index)) {
|
||||
LookupIterator it(isolate, receiver, index, holder, configuration);
|
||||
// Here we try to avoid having to rebuild the string later
|
||||
// by storing it on the indexed LookupIterator.
|
||||
it.name_ = name;
|
||||
return it;
|
||||
}
|
||||
|
||||
return LookupIterator(receiver, name, holder, configuration);
|
||||
}
|
||||
|
||||
// static
|
||||
LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
|
||||
Handle<Object> receiver,
|
||||
Handle<Object> key,
|
||||
bool* success,
|
||||
Configuration configuration) {
|
||||
// TODO(mslekova): come up with better way to avoid duplication
|
||||
uint32_t index = 0;
|
||||
if (key->ToArrayIndex(&index)) {
|
||||
*success = true;
|
||||
|
@ -126,11 +126,6 @@ class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
|
||||
return LookupIterator(receiver, name, holder, configuration);
|
||||
}
|
||||
|
||||
static LookupIterator PropertyOrElement(
|
||||
Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
|
||||
bool* success, Handle<JSReceiver> holder,
|
||||
Configuration configuration = DEFAULT);
|
||||
|
||||
static LookupIterator PropertyOrElement(
|
||||
Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
|
||||
bool* success, Configuration configuration = DEFAULT);
|
||||
|
@ -1106,7 +1106,7 @@ MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
|
||||
Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
|
||||
|
||||
MaybeHandle<Object> result =
|
||||
JSProxy::CheckGetSetTrapResult(isolate, name, target, trap_result, kGet);
|
||||
JSProxy::CheckGetTrapResult(isolate, name, target, trap_result);
|
||||
if (result.is_null()) {
|
||||
return result;
|
||||
}
|
||||
@ -1116,11 +1116,10 @@ MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate,
|
||||
Handle<Name> name,
|
||||
Handle<JSReceiver> target,
|
||||
Handle<Object> trap_result,
|
||||
AccessKind access_kind) {
|
||||
MaybeHandle<Object> JSProxy::CheckGetTrapResult(Isolate* isolate,
|
||||
Handle<Name> name,
|
||||
Handle<JSReceiver> target,
|
||||
Handle<Object> trap_result) {
|
||||
// 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
|
||||
PropertyDescriptor target_desc;
|
||||
Maybe<bool> target_found =
|
||||
@ -1137,43 +1136,24 @@ MaybeHandle<Object> JSProxy::CheckGetSetTrapResult(Isolate* isolate,
|
||||
!target_desc.writable() &&
|
||||
!trap_result->SameValue(*target_desc.value());
|
||||
if (inconsistent) {
|
||||
if (access_kind == kGet) {
|
||||
THROW_NEW_ERROR(
|
||||
isolate,
|
||||
NewTypeError(MessageTemplate::kProxyGetNonConfigurableData, name,
|
||||
target_desc.value(), trap_result),
|
||||
Object);
|
||||
} else {
|
||||
isolate->Throw(*isolate->factory()->NewTypeError(
|
||||
MessageTemplate::kProxySetFrozenData, name));
|
||||
return MaybeHandle<Object>();
|
||||
}
|
||||
THROW_NEW_ERROR(
|
||||
isolate, NewTypeError(MessageTemplate::kProxyGetNonConfigurableData,
|
||||
name, target_desc.value(), trap_result),
|
||||
Object);
|
||||
}
|
||||
// 10.b. If IsAccessorDescriptor(targetDesc) and targetDesc.[[Configurable]]
|
||||
// is false and targetDesc.[[Get]] is undefined, then
|
||||
// 10.b.i. If trapResult is not undefined, throw a TypeError exception.
|
||||
if (access_kind == kGet) {
|
||||
inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
|
||||
!target_desc.configurable() &&
|
||||
target_desc.get()->IsUndefined(isolate) &&
|
||||
!trap_result->IsUndefined(isolate);
|
||||
} else {
|
||||
inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
|
||||
!target_desc.configurable() &&
|
||||
target_desc.set()->IsUndefined(isolate);
|
||||
}
|
||||
inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
|
||||
!target_desc.configurable() &&
|
||||
target_desc.get()->IsUndefined(isolate) &&
|
||||
!trap_result->IsUndefined(isolate);
|
||||
if (inconsistent) {
|
||||
if (access_kind == kGet) {
|
||||
THROW_NEW_ERROR(
|
||||
isolate,
|
||||
NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor,
|
||||
name, trap_result),
|
||||
Object);
|
||||
} else {
|
||||
isolate->Throw(*isolate->factory()->NewTypeError(
|
||||
MessageTemplate::kProxySetFrozenAccessor, name));
|
||||
return MaybeHandle<Object>();
|
||||
}
|
||||
THROW_NEW_ERROR(
|
||||
isolate,
|
||||
NewTypeError(MessageTemplate::kProxyGetNonConfigurableAccessor, name,
|
||||
trap_result),
|
||||
Object);
|
||||
}
|
||||
}
|
||||
return isolate->factory()->undefined_value();
|
||||
@ -5547,11 +5527,29 @@ Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
|
||||
trap_name, name));
|
||||
}
|
||||
|
||||
MaybeHandle<Object> result =
|
||||
JSProxy::CheckGetSetTrapResult(isolate, name, target, value, kSet);
|
||||
|
||||
if (result.is_null()) {
|
||||
return Nothing<bool>();
|
||||
// Enforce the invariant.
|
||||
PropertyDescriptor target_desc;
|
||||
Maybe<bool> owned =
|
||||
JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc);
|
||||
MAYBE_RETURN(owned, Nothing<bool>());
|
||||
if (owned.FromJust()) {
|
||||
bool inconsistent = PropertyDescriptor::IsDataDescriptor(&target_desc) &&
|
||||
!target_desc.configurable() &&
|
||||
!target_desc.writable() &&
|
||||
!value->SameValue(*target_desc.value());
|
||||
if (inconsistent) {
|
||||
isolate->Throw(*isolate->factory()->NewTypeError(
|
||||
MessageTemplate::kProxySetFrozenData, name));
|
||||
return Nothing<bool>();
|
||||
}
|
||||
inconsistent = PropertyDescriptor::IsAccessorDescriptor(&target_desc) &&
|
||||
!target_desc.configurable() &&
|
||||
target_desc.set()->IsUndefined(isolate);
|
||||
if (inconsistent) {
|
||||
isolate->Throw(*isolate->factory()->NewTypeError(
|
||||
MessageTemplate::kProxySetFrozenAccessor, name));
|
||||
return Nothing<bool>();
|
||||
}
|
||||
}
|
||||
return Just(true);
|
||||
}
|
||||
|
@ -6046,13 +6046,10 @@ class JSProxy: public JSReceiver {
|
||||
Isolate* isolate, Handle<JSProxy> proxy, Handle<Name> name,
|
||||
Handle<Object> receiver, bool* was_found);
|
||||
|
||||
enum AccessKind { kGet, kSet };
|
||||
|
||||
static MaybeHandle<Object> CheckGetSetTrapResult(Isolate* isolate,
|
||||
Handle<Name> name,
|
||||
Handle<JSReceiver> target,
|
||||
Handle<Object> trap_result,
|
||||
AccessKind access_kind);
|
||||
static MaybeHandle<Object> CheckGetTrapResult(Isolate* isolate,
|
||||
Handle<Name> name,
|
||||
Handle<JSReceiver> target,
|
||||
Handle<Object> trap_result);
|
||||
|
||||
// ES6 9.5.9
|
||||
MUST_USE_RESULT static Maybe<bool> SetProperty(Handle<JSProxy> proxy,
|
||||
|
@ -51,47 +51,24 @@ RUNTIME_FUNCTION(Runtime_GetPropertyWithReceiver) {
|
||||
|
||||
DCHECK_EQ(3, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, holder, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 2);
|
||||
|
||||
bool success;
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(isolate, receiver, name,
|
||||
&success, holder);
|
||||
LookupIterator it =
|
||||
LookupIterator::PropertyOrElement(isolate, receiver, name, holder);
|
||||
RETURN_RESULT_OR_FAILURE(isolate, Object::GetProperty(&it));
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_SetPropertyWithReceiver) {
|
||||
RUNTIME_FUNCTION(Runtime_CheckProxyGetTrapResult) {
|
||||
HandleScope scope(isolate);
|
||||
|
||||
DCHECK_EQ(5, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, holder, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 3);
|
||||
CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 4);
|
||||
|
||||
bool success;
|
||||
LookupIterator it = LookupIterator::PropertyOrElement(isolate, receiver, name,
|
||||
&success, holder);
|
||||
|
||||
Maybe<bool> result = Object::SetSuperProperty(
|
||||
&it, value, language_mode, Object::MAY_BE_STORE_FROM_KEYED);
|
||||
MAYBE_RETURN(result, isolate->heap()->exception());
|
||||
return *isolate->factory()->ToBoolean(result.FromJust());
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_CheckProxyGetSetTrapResult) {
|
||||
HandleScope scope(isolate);
|
||||
|
||||
DCHECK_EQ(4, args.length());
|
||||
DCHECK_EQ(3, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, target, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, trap_result, 2);
|
||||
CONVERT_NUMBER_CHECKED(int64_t, access_kind, Int64, args[3]);
|
||||
|
||||
RETURN_RESULT_OR_FAILURE(isolate, JSProxy::CheckGetSetTrapResult(
|
||||
isolate, name, target, trap_result,
|
||||
JSProxy::AccessKind(access_kind)));
|
||||
RETURN_RESULT_OR_FAILURE(
|
||||
isolate, JSProxy::CheckGetTrapResult(isolate, name, target, trap_result));
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_CheckProxyHasTrap) {
|
||||
|
@ -469,9 +469,8 @@ namespace internal {
|
||||
F(JSProxyGetHandler, 1, 1) \
|
||||
F(JSProxyRevoke, 1, 1) \
|
||||
F(GetPropertyWithReceiver, 2, 1) \
|
||||
F(CheckProxyHasTrap, 2, 1) \
|
||||
F(SetPropertyWithReceiver, 5, 1) \
|
||||
F(CheckProxyGetSetTrapResult, 2, 1)
|
||||
F(CheckProxyGetTrapResult, 2, 1) \
|
||||
F(CheckProxyHasTrap, 2, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_REGEXP(F) \
|
||||
F(IsRegExp, 1, 1) \
|
||||
|
@ -208,6 +208,8 @@
|
||||
'builtins/builtins-promise-gen.h',
|
||||
'builtins/builtins-proxy-gen.cc',
|
||||
'builtins/builtins-proxy-gen.h',
|
||||
'builtins/builtins-proxy-helpers-gen.cc',
|
||||
'builtins/builtins-proxy-helpers-gen.h',
|
||||
'builtins/builtins-regexp-gen.cc',
|
||||
'builtins/builtins-regexp-gen.h',
|
||||
'builtins/builtins-sharedarraybuffer-gen.cc',
|
||||
|
@ -193,6 +193,7 @@
|
||||
'Error from proxy getOwnPropertyDescriptor trap');
|
||||
})();
|
||||
|
||||
|
||||
(function testGetPropertyDetailsBailout2() {
|
||||
var obj = {};
|
||||
Object.defineProperty(obj, 'prop', {
|
||||
@ -210,13 +211,3 @@
|
||||
" property on the proxy target but the proxy did not return its actual" +
|
||||
" value (expected '53' but got '42')");
|
||||
})();
|
||||
|
||||
(function test32BitIndex() {
|
||||
var index = (1 << 31) + 1;
|
||||
var obj = {};
|
||||
obj[index] = 42;
|
||||
var p = new Proxy(obj, {});
|
||||
for (var i = 0; i < 3; ++i) {
|
||||
assertEquals(42, p[index]);
|
||||
}
|
||||
})();
|
||||
|
@ -308,101 +308,3 @@ TestTrapReceiverArgument(strictReflectSet);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
function TestTargetProxy(mySet) {
|
||||
var q = new Proxy({}, {});
|
||||
var proxy = new Proxy(q, {
|
||||
set: function(t, k, v) {
|
||||
return Reflect.set(t, k, v);
|
||||
}
|
||||
});
|
||||
|
||||
for (var p of properties) {
|
||||
assertTrueIf(mySet.returnsBool, mySet(proxy, p, 42));
|
||||
assertSame(42, q[p]);
|
||||
}
|
||||
};
|
||||
|
||||
TestTargetProxy(sloppyDefaultSet);
|
||||
TestTargetProxy(sloppyReflectSet);
|
||||
TestTargetProxy(strictDefaultSet);
|
||||
TestTargetProxy(strictReflectSet);
|
||||
|
||||
|
||||
(function TestAccessorNoSet() {
|
||||
var target = {
|
||||
};
|
||||
Object.defineProperty(target, 'prop', {
|
||||
get: function() {
|
||||
return 42;
|
||||
},
|
||||
configurable: false
|
||||
})
|
||||
var handler = {
|
||||
set: function() { return true; }
|
||||
}
|
||||
var proxy = new Proxy(target, handler);
|
||||
assertThrows(function() { proxy.prop = 0; }, TypeError);
|
||||
})();
|
||||
|
||||
(function TestProxyInPrototype() {
|
||||
var handler = {
|
||||
set: function(t, k, v) {
|
||||
Reflect.set(t, k, v);
|
||||
}
|
||||
};
|
||||
var obj = {};
|
||||
var proxy = new Proxy(obj, handler);
|
||||
var o = Object.create(proxy);
|
||||
|
||||
for (var i = 0; i < 3; ++i) {
|
||||
o.prop = 42 + i;
|
||||
assertEquals(42 + i, obj.prop);
|
||||
}
|
||||
})();
|
||||
|
||||
(function TestProxyInPrototypeNoTrap() {
|
||||
var handler = {
|
||||
};
|
||||
var obj = {};
|
||||
var proxy = new Proxy(obj, handler);
|
||||
var o = Object.create(proxy);
|
||||
|
||||
for (var i = 0; i < 3; ++i) {
|
||||
o.prop = 42 + i;
|
||||
assertEquals(42 + i, o.prop);
|
||||
assertEquals(undefined, obj.prop);
|
||||
}
|
||||
})();
|
||||
|
||||
// Note: this case is currently handled by runtime.
|
||||
(function TestDifferentHolder() {
|
||||
var obj = {
|
||||
'1337': 100
|
||||
};
|
||||
var handler = {
|
||||
set(target, name, value, receiver) {
|
||||
if (name != '1337') return Reflect.set(target, name, value, receiver);
|
||||
|
||||
assertSame(target, obj);
|
||||
assertSame(receiver, p);
|
||||
return target[name] = value;
|
||||
}
|
||||
};
|
||||
var p = new Proxy(obj, handler);
|
||||
for (var i = 0; i < 3; ++i) {
|
||||
assertEquals(42, p[1337] = 42);
|
||||
}
|
||||
})();
|
||||
|
||||
(function test32BitIndex() {
|
||||
var index = (1 << 31) + 1;
|
||||
var obj = {};
|
||||
obj[index] = 42;
|
||||
var p = new Proxy(obj, {});
|
||||
for (var i = 0; i < 3; ++i) {
|
||||
p[index] = 100;
|
||||
assertEquals(100, obj[index]);
|
||||
}
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user