Reland ^3 "[builtins] Port getting property from Proxy to CSA""
This is a reland ofe86c066b77
With fixes for crbug.com/752846, crbug.com/752712, crbug.com/752850 Previously landed as:47a97aa53b
/ 47113 Previously landed as:15ef03cbf3
/ 47159 TBR=jkummerow@chromium.org, franzih@chromium.org, bmeurer@chromium.org, jgruber@chromium.org, mstarzinger@chromium.org Bug: v8:6559, v8:6557 Change-Id: I12ccae44331b05dd3f304ac538c0154133b43c35 Reviewed-on: https://chromium-review.googlesource.com/608187 Reviewed-by: Georg Neis <neis@chromium.org> Commit-Queue: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#47245}
This commit is contained in:
parent
c5263279eb
commit
edc4ae14c8
2
BUILD.gn
2
BUILD.gn
@ -994,6 +994,8 @@ v8_source_set("v8_builtins_generators") {
|
|||||||
"src/builtins/builtins-promise-gen.cc",
|
"src/builtins/builtins-promise-gen.cc",
|
||||||
"src/builtins/builtins-promise-gen.h",
|
"src/builtins/builtins-promise-gen.h",
|
||||||
"src/builtins/builtins-proxy-gen.cc",
|
"src/builtins/builtins-proxy-gen.cc",
|
||||||
|
"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.cc",
|
||||||
"src/builtins/builtins-regexp-gen.h",
|
"src/builtins/builtins-regexp-gen.h",
|
||||||
"src/builtins/builtins-sharedarraybuffer-gen.cc",
|
"src/builtins/builtins-sharedarraybuffer-gen.cc",
|
||||||
|
@ -802,6 +802,7 @@ namespace internal {
|
|||||||
TFJ(ProxyConstructor, 0) \
|
TFJ(ProxyConstructor, 0) \
|
||||||
TFJ(ProxyConstructor_ConstructStub, \
|
TFJ(ProxyConstructor_ConstructStub, \
|
||||||
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||||
|
TFS(ProxyGetProperty, kProxy, kName, kReceiverValue) \
|
||||||
\
|
\
|
||||||
/* Reflect */ \
|
/* Reflect */ \
|
||||||
ASM(ReflectApply) \
|
ASM(ReflectApply) \
|
||||||
|
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_
|
@ -6033,6 +6033,16 @@ void CodeStubAssembler::TryGetOwnProperty(
|
|||||||
Node* context, Node* receiver, Node* object, Node* map, Node* instance_type,
|
Node* context, Node* receiver, Node* object, Node* map, Node* instance_type,
|
||||||
Node* unique_name, Label* if_found_value, Variable* var_value,
|
Node* unique_name, Label* if_found_value, Variable* var_value,
|
||||||
Label* if_not_found, Label* if_bailout) {
|
Label* if_not_found, Label* if_bailout) {
|
||||||
|
TryGetOwnProperty(context, receiver, object, map, instance_type, unique_name,
|
||||||
|
if_found_value, var_value, nullptr, nullptr, if_not_found,
|
||||||
|
if_bailout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CodeStubAssembler::TryGetOwnProperty(
|
||||||
|
Node* context, Node* receiver, Node* object, Node* map, Node* instance_type,
|
||||||
|
Node* unique_name, Label* if_found_value, Variable* var_value,
|
||||||
|
Variable* var_details, Variable* var_raw_value, Label* if_not_found,
|
||||||
|
Label* if_bailout) {
|
||||||
DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
|
DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep());
|
||||||
Comment("TryGetOwnProperty");
|
Comment("TryGetOwnProperty");
|
||||||
|
|
||||||
@ -6041,8 +6051,11 @@ void CodeStubAssembler::TryGetOwnProperty(
|
|||||||
|
|
||||||
Label if_found_fast(this), if_found_dict(this), if_found_global(this);
|
Label if_found_fast(this), if_found_dict(this), if_found_global(this);
|
||||||
|
|
||||||
VARIABLE(var_details, MachineRepresentation::kWord32);
|
VARIABLE(local_var_details, MachineRepresentation::kWord32);
|
||||||
Variable* vars[] = {var_value, &var_details};
|
if (!var_details) {
|
||||||
|
var_details = &local_var_details;
|
||||||
|
}
|
||||||
|
Variable* vars[] = {var_value, var_details};
|
||||||
Label if_found(this, 2, vars);
|
Label if_found(this, 2, vars);
|
||||||
|
|
||||||
TryLookupProperty(object, map, instance_type, unique_name, &if_found_fast,
|
TryLookupProperty(object, map, instance_type, unique_name, &if_found_fast,
|
||||||
@ -6054,14 +6067,14 @@ void CodeStubAssembler::TryGetOwnProperty(
|
|||||||
Node* name_index = var_entry.value();
|
Node* name_index = var_entry.value();
|
||||||
|
|
||||||
LoadPropertyFromFastObject(object, map, descriptors, name_index,
|
LoadPropertyFromFastObject(object, map, descriptors, name_index,
|
||||||
&var_details, var_value);
|
var_details, var_value);
|
||||||
Goto(&if_found);
|
Goto(&if_found);
|
||||||
}
|
}
|
||||||
BIND(&if_found_dict);
|
BIND(&if_found_dict);
|
||||||
{
|
{
|
||||||
Node* dictionary = var_meta_storage.value();
|
Node* dictionary = var_meta_storage.value();
|
||||||
Node* entry = var_entry.value();
|
Node* entry = var_entry.value();
|
||||||
LoadPropertyFromNameDictionary(dictionary, entry, &var_details, var_value);
|
LoadPropertyFromNameDictionary(dictionary, entry, var_details, var_value);
|
||||||
Goto(&if_found);
|
Goto(&if_found);
|
||||||
}
|
}
|
||||||
BIND(&if_found_global);
|
BIND(&if_found_global);
|
||||||
@ -6069,14 +6082,17 @@ void CodeStubAssembler::TryGetOwnProperty(
|
|||||||
Node* dictionary = var_meta_storage.value();
|
Node* dictionary = var_meta_storage.value();
|
||||||
Node* entry = var_entry.value();
|
Node* entry = var_entry.value();
|
||||||
|
|
||||||
LoadPropertyFromGlobalDictionary(dictionary, entry, &var_details, var_value,
|
LoadPropertyFromGlobalDictionary(dictionary, entry, var_details, var_value,
|
||||||
if_not_found);
|
if_not_found);
|
||||||
Goto(&if_found);
|
Goto(&if_found);
|
||||||
}
|
}
|
||||||
// Here we have details and value which could be an accessor.
|
// Here we have details and value which could be an accessor.
|
||||||
BIND(&if_found);
|
BIND(&if_found);
|
||||||
{
|
{
|
||||||
Node* value = CallGetterIfAccessor(var_value->value(), var_details.value(),
|
if (var_raw_value) {
|
||||||
|
var_raw_value->Bind(var_value->value());
|
||||||
|
}
|
||||||
|
Node* value = CallGetterIfAccessor(var_value->value(), var_details->value(),
|
||||||
context, receiver, if_bailout);
|
context, receiver, if_bailout);
|
||||||
var_value->Bind(value);
|
var_value->Bind(value);
|
||||||
Goto(if_found_value);
|
Goto(if_found_value);
|
||||||
|
@ -1304,6 +1304,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
|||||||
Node* instance_type, Node* unique_name,
|
Node* instance_type, Node* unique_name,
|
||||||
Label* if_found, Variable* var_value,
|
Label* if_found, Variable* var_value,
|
||||||
Label* if_not_found, Label* if_bailout);
|
Label* if_not_found, Label* if_bailout);
|
||||||
|
void TryGetOwnProperty(Node* context, Node* receiver, Node* object, Node* map,
|
||||||
|
Node* instance_type, Node* unique_name,
|
||||||
|
Label* if_found, Variable* var_value,
|
||||||
|
Variable* var_details, Variable* var_raw_value,
|
||||||
|
Label* if_not_found, Label* if_bailout);
|
||||||
|
|
||||||
Node* GetProperty(Node* context, Node* receiver, Handle<Name> name) {
|
Node* GetProperty(Node* context, Node* receiver, Handle<Name> name) {
|
||||||
return GetProperty(context, receiver, HeapConstant(name));
|
return GetProperty(context, receiver, HeapConstant(name));
|
||||||
|
@ -261,7 +261,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
|
|||||||
|
|
||||||
Label constant(this), field(this), normal(this, Label::kDeferred),
|
Label constant(this), field(this), normal(this, Label::kDeferred),
|
||||||
interceptor(this, Label::kDeferred), nonexistent(this),
|
interceptor(this, Label::kDeferred), nonexistent(this),
|
||||||
accessor(this, Label::kDeferred), global(this, Label::kDeferred);
|
accessor(this, Label::kDeferred), proxy(this, Label::kDeferred),
|
||||||
|
global(this, Label::kDeferred);
|
||||||
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field);
|
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field);
|
||||||
|
|
||||||
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
|
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
|
||||||
@ -276,6 +277,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
|
|||||||
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kAccessor)),
|
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kAccessor)),
|
||||||
&accessor);
|
&accessor);
|
||||||
|
|
||||||
|
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)), &proxy);
|
||||||
|
|
||||||
Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global,
|
Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global,
|
||||||
&interceptor);
|
&interceptor);
|
||||||
|
|
||||||
@ -362,6 +365,13 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
|
|||||||
exit_point->Return(CallJS(callable, p->context, getter, p->receiver));
|
exit_point->Return(CallJS(callable, p->context, getter, p->receiver));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIND(&proxy);
|
||||||
|
{
|
||||||
|
exit_point->ReturnCallStub(
|
||||||
|
Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
|
||||||
|
p->context, holder, p->name, p->receiver);
|
||||||
|
}
|
||||||
|
|
||||||
BIND(&global);
|
BIND(&global);
|
||||||
{
|
{
|
||||||
CSA_ASSERT(this, IsPropertyCell(holder));
|
CSA_ASSERT(this, IsPropertyCell(holder));
|
||||||
@ -1471,15 +1481,15 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
|
|||||||
|
|
||||||
Comment("key is unique name");
|
Comment("key is unique name");
|
||||||
Label if_found_on_receiver(this), if_property_dictionary(this),
|
Label if_found_on_receiver(this), if_property_dictionary(this),
|
||||||
lookup_prototype_chain(this);
|
lookup_prototype_chain(this), special_receiver(this);
|
||||||
VARIABLE(var_details, MachineRepresentation::kWord32);
|
VARIABLE(var_details, MachineRepresentation::kWord32);
|
||||||
VARIABLE(var_value, MachineRepresentation::kTagged);
|
VARIABLE(var_value, MachineRepresentation::kTagged);
|
||||||
|
|
||||||
// Receivers requiring non-standard accesses (interceptors, access
|
// Receivers requiring non-standard accesses (interceptors, access
|
||||||
// checks, strings and string wrappers, proxies) are handled in the runtime.
|
// checks, strings and string wrappers) are handled in the runtime.
|
||||||
GotoIf(Int32LessThanOrEqual(instance_type,
|
GotoIf(Int32LessThanOrEqual(instance_type,
|
||||||
Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
|
Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
|
||||||
slow);
|
&special_receiver);
|
||||||
|
|
||||||
// Check if the receiver has fast or slow properties.
|
// Check if the receiver has fast or slow properties.
|
||||||
Node* bitfield3 = LoadMapBitField3(receiver_map);
|
Node* bitfield3 = LoadMapBitField3(receiver_map);
|
||||||
@ -1600,6 +1610,16 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
|
|||||||
BIND(&return_undefined);
|
BIND(&return_undefined);
|
||||||
Return(UndefinedConstant());
|
Return(UndefinedConstant());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIND(&special_receiver);
|
||||||
|
{
|
||||||
|
GotoIfNot(Word32Equal(instance_type, Int32Constant(JS_PROXY_TYPE)), slow);
|
||||||
|
|
||||||
|
direct_exit.ReturnCallStub(
|
||||||
|
Builtins::CallableFor(isolate(), Builtins::kProxyGetProperty),
|
||||||
|
p->context, receiver /*holder is the same as receiver*/, p->name,
|
||||||
|
receiver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////// Stub cache access helpers.
|
//////////////////// Stub cache access helpers.
|
||||||
|
@ -53,6 +53,11 @@ Handle<Smi> LoadHandler::LoadAccessor(Isolate* isolate, int descriptor) {
|
|||||||
return handle(Smi::FromInt(config), isolate);
|
return handle(Smi::FromInt(config), isolate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Handle<Smi> LoadHandler::LoadProxy(Isolate* isolate) {
|
||||||
|
int config = KindBits::encode(kProxy);
|
||||||
|
return handle(Smi::FromInt(config), isolate);
|
||||||
|
}
|
||||||
|
|
||||||
Handle<Smi> LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) {
|
Handle<Smi> LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) {
|
||||||
int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(true) |
|
int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(true) |
|
||||||
DescriptorBits::encode(descriptor);
|
DescriptorBits::encode(descriptor);
|
||||||
|
@ -25,9 +25,10 @@ class LoadHandler {
|
|||||||
kConstant,
|
kConstant,
|
||||||
kAccessor,
|
kAccessor,
|
||||||
kInterceptor,
|
kInterceptor,
|
||||||
|
kProxy,
|
||||||
kNonExistent
|
kNonExistent
|
||||||
};
|
};
|
||||||
class KindBits : public BitField<Kind, 0, 3> {};
|
class KindBits : public BitField<Kind, 0, 4> {};
|
||||||
|
|
||||||
// Defines whether access rights check should be done on receiver object.
|
// Defines whether access rights check should be done on receiver object.
|
||||||
// Applicable to named property kinds only when loading value from prototype
|
// Applicable to named property kinds only when loading value from prototype
|
||||||
@ -113,6 +114,9 @@ class LoadHandler {
|
|||||||
// Creates a Smi-handler for calling a getter on a fast object.
|
// Creates a Smi-handler for calling a getter on a fast object.
|
||||||
static inline Handle<Smi> LoadAccessor(Isolate* isolate, int descriptor);
|
static inline Handle<Smi> LoadAccessor(Isolate* isolate, int descriptor);
|
||||||
|
|
||||||
|
// Creates a Smi-handler for calling a getter on a proxy.
|
||||||
|
static inline Handle<Smi> LoadProxy(Isolate* isolate);
|
||||||
|
|
||||||
// Creates a Smi-handler for loading an Api getter property from fast object.
|
// Creates a Smi-handler for loading an Api getter property from fast object.
|
||||||
static inline Handle<Smi> LoadApiGetter(Isolate* isolate, int descriptor);
|
static inline Handle<Smi> LoadApiGetter(Isolate* isolate, int descriptor);
|
||||||
|
|
||||||
|
36
src/ic/ic.cc
36
src/ic/ic.cc
@ -772,7 +772,7 @@ namespace {
|
|||||||
|
|
||||||
template <bool fill_array = true>
|
template <bool fill_array = true>
|
||||||
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
|
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
|
||||||
Handle<JSObject> holder, Handle<Name> name,
|
Handle<JSReceiver> holder, Handle<Name> name,
|
||||||
Handle<FixedArray> array, int first_index) {
|
Handle<FixedArray> array, int first_index) {
|
||||||
if (!holder.is_null() && holder->map() == *receiver_map) return 0;
|
if (!holder.is_null() && holder->map() == *receiver_map) return 0;
|
||||||
|
|
||||||
@ -813,7 +813,8 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
|
|||||||
: PrototypeIterator::END_AT_NULL;
|
: PrototypeIterator::END_AT_NULL;
|
||||||
for (PrototypeIterator iter(receiver_map, end); !iter.IsAtEnd();
|
for (PrototypeIterator iter(receiver_map, end); !iter.IsAtEnd();
|
||||||
iter.Advance()) {
|
iter.Advance()) {
|
||||||
Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
|
Handle<JSReceiver> current =
|
||||||
|
PrototypeIterator::GetCurrent<JSReceiver>(iter);
|
||||||
if (holder.is_identical_to(current)) break;
|
if (holder.is_identical_to(current)) break;
|
||||||
Handle<Map> current_map(current->map(), isolate);
|
Handle<Map> current_map(current->map(), isolate);
|
||||||
|
|
||||||
@ -850,7 +851,7 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
|
|||||||
// Returns -1 if the handler has to be compiled or the number of prototype
|
// Returns -1 if the handler has to be compiled or the number of prototype
|
||||||
// checks otherwise.
|
// checks otherwise.
|
||||||
int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
|
int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
|
||||||
Handle<JSObject> holder, Handle<Name> name) {
|
Handle<JSReceiver> holder, Handle<Name> name) {
|
||||||
return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
|
return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
|
||||||
Handle<FixedArray>(), 0);
|
Handle<FixedArray>(), 0);
|
||||||
}
|
}
|
||||||
@ -860,7 +861,7 @@ enum class HolderCellRequest {
|
|||||||
kHolder,
|
kHolder,
|
||||||
};
|
};
|
||||||
|
|
||||||
Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSObject> holder,
|
Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSReceiver> holder,
|
||||||
Handle<Name> name, HolderCellRequest request) {
|
Handle<Name> name, HolderCellRequest request) {
|
||||||
if (request == HolderCellRequest::kGlobalPropertyCell) {
|
if (request == HolderCellRequest::kGlobalPropertyCell) {
|
||||||
DCHECK(holder->IsJSGlobalObject());
|
DCHECK(holder->IsJSGlobalObject());
|
||||||
@ -877,7 +878,7 @@ Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSObject> holder,
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
|
Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
|
||||||
Handle<JSObject> holder,
|
Handle<JSReceiver> holder,
|
||||||
Handle<Name> name,
|
Handle<Name> name,
|
||||||
Handle<Smi> smi_handler) {
|
Handle<Smi> smi_handler) {
|
||||||
int checks_count =
|
int checks_count =
|
||||||
@ -925,7 +926,7 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
|
|||||||
Handle<Object> LoadIC::LoadFullChain(Handle<Map> receiver_map,
|
Handle<Object> LoadIC::LoadFullChain(Handle<Map> receiver_map,
|
||||||
Handle<Object> holder, Handle<Name> name,
|
Handle<Object> holder, Handle<Name> name,
|
||||||
Handle<Smi> smi_handler) {
|
Handle<Smi> smi_handler) {
|
||||||
Handle<JSObject> end; // null handle
|
Handle<JSReceiver> end; // null handle
|
||||||
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, end, name);
|
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, end, name);
|
||||||
DCHECK_LE(0, checks_count);
|
DCHECK_LE(0, checks_count);
|
||||||
|
|
||||||
@ -976,8 +977,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<Object> code;
|
Handle<Object> code;
|
||||||
if (lookup->state() == LookupIterator::JSPROXY ||
|
if (lookup->state() == LookupIterator::ACCESS_CHECK) {
|
||||||
lookup->state() == LookupIterator::ACCESS_CHECK) {
|
|
||||||
code = slow_stub();
|
code = slow_stub();
|
||||||
} else if (!lookup->IsFound()) {
|
} else if (!lookup->IsFound()) {
|
||||||
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
|
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
|
||||||
@ -1101,8 +1101,13 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<Map> map = receiver_map();
|
Handle<Map> map = receiver_map();
|
||||||
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
Handle<JSObject> holder;
|
||||||
bool receiver_is_holder = receiver.is_identical_to(holder);
|
bool receiver_is_holder;
|
||||||
|
if (lookup->state() != LookupIterator::JSPROXY) {
|
||||||
|
holder = lookup->GetHolder<JSObject>();
|
||||||
|
receiver_is_holder = receiver.is_identical_to(holder);
|
||||||
|
}
|
||||||
|
|
||||||
switch (lookup->state()) {
|
switch (lookup->state()) {
|
||||||
case LookupIterator::INTERCEPTOR: {
|
case LookupIterator::INTERCEPTOR: {
|
||||||
Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
|
Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
|
||||||
@ -1263,8 +1268,16 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
|||||||
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
||||||
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
|
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
|
||||||
return LoadHandler::LoadNonExistent(isolate());
|
return LoadHandler::LoadNonExistent(isolate());
|
||||||
|
case LookupIterator::JSPROXY: {
|
||||||
|
Handle<JSProxy> holder_proxy = lookup->GetHolder<JSProxy>();
|
||||||
|
bool receiver_is_holder_proxy = receiver.is_identical_to(holder_proxy);
|
||||||
|
Handle<Smi> smi_handler = LoadHandler::LoadProxy(isolate());
|
||||||
|
if (receiver_is_holder_proxy) {
|
||||||
|
return smi_handler;
|
||||||
|
}
|
||||||
|
return LoadFromPrototype(map, holder_proxy, lookup->name(), smi_handler);
|
||||||
|
}
|
||||||
case LookupIterator::ACCESS_CHECK:
|
case LookupIterator::ACCESS_CHECK:
|
||||||
case LookupIterator::JSPROXY:
|
|
||||||
case LookupIterator::NOT_FOUND:
|
case LookupIterator::NOT_FOUND:
|
||||||
case LookupIterator::TRANSITION:
|
case LookupIterator::TRANSITION:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -1721,6 +1734,7 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
|
|||||||
|
|
||||||
int checks_count =
|
int checks_count =
|
||||||
GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
|
GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
|
||||||
|
|
||||||
DCHECK_LE(0, checks_count);
|
DCHECK_LE(0, checks_count);
|
||||||
DCHECK(!receiver_map->IsJSGlobalObjectMap());
|
DCHECK(!receiver_map->IsJSGlobalObjectMap());
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ class LoadIC : public IC {
|
|||||||
// by given Smi-handler that encoded a load from the holder.
|
// by given Smi-handler that encoded a load from the holder.
|
||||||
// Can be used only if GetPrototypeCheckCount() returns non negative value.
|
// Can be used only if GetPrototypeCheckCount() returns non negative value.
|
||||||
Handle<Object> LoadFromPrototype(Handle<Map> receiver_map,
|
Handle<Object> LoadFromPrototype(Handle<Map> receiver_map,
|
||||||
Handle<JSObject> holder, Handle<Name> name,
|
Handle<JSReceiver> holder, Handle<Name> name,
|
||||||
Handle<Smi> smi_handler);
|
Handle<Smi> smi_handler);
|
||||||
|
|
||||||
// Creates a data handler that represents a load of a non-existent property.
|
// Creates a data handler that represents a load of a non-existent property.
|
||||||
|
@ -1105,6 +1105,22 @@ MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
|
|||||||
ASSIGN_RETURN_ON_EXCEPTION(
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
isolate, trap_result,
|
isolate, trap_result,
|
||||||
Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
|
Execution::Call(isolate, trap, handler, arraysize(args), args), Object);
|
||||||
|
|
||||||
|
MaybeHandle<Object> result =
|
||||||
|
JSProxy::CheckGetTrapResult(isolate, name, target, trap_result);
|
||||||
|
if (result.is_null()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 11. Return trap_result
|
||||||
|
return trap_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
MaybeHandle<Object> JSProxy::CheckGetTrapResult(Isolate* isolate,
|
||||||
|
Handle<Name> name,
|
||||||
|
Handle<JSReceiver> target,
|
||||||
|
Handle<Object> trap_result) {
|
||||||
// 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
|
// 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
|
||||||
PropertyDescriptor target_desc;
|
PropertyDescriptor target_desc;
|
||||||
Maybe<bool> target_found =
|
Maybe<bool> target_found =
|
||||||
@ -1141,8 +1157,7 @@ MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
|
|||||||
Object);
|
Object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 11. Return trap_result
|
return isolate->factory()->undefined_value();
|
||||||
return trap_result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -12594,7 +12609,12 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
|
|||||||
} else {
|
} else {
|
||||||
maybe_prototype =
|
maybe_prototype =
|
||||||
handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
|
handle(map->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
|
||||||
if (!maybe_prototype->IsJSObject()) return Handle<Cell>::null();
|
if (!maybe_prototype->IsJSReceiver()) return Handle<Cell>::null();
|
||||||
|
}
|
||||||
|
if (maybe_prototype->IsJSProxy()) {
|
||||||
|
Handle<Cell> cell = isolate->factory()->NewCell(
|
||||||
|
handle(Smi::FromInt(Map::kPrototypeChainValid), isolate));
|
||||||
|
return cell;
|
||||||
}
|
}
|
||||||
Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
|
Handle<JSObject> prototype = Handle<JSObject>::cast(maybe_prototype);
|
||||||
// Ensure the prototype is registered with its own prototypes so its cell
|
// Ensure the prototype is registered with its own prototypes so its cell
|
||||||
@ -12619,11 +12639,16 @@ Handle<Cell> Map::GetOrCreatePrototypeChainValidityCell(Handle<Map> map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSObject> prototype,
|
Handle<WeakCell> Map::GetOrCreatePrototypeWeakCell(Handle<JSReceiver> prototype,
|
||||||
Isolate* isolate) {
|
Isolate* isolate) {
|
||||||
DCHECK(!prototype.is_null());
|
DCHECK(!prototype.is_null());
|
||||||
|
if (prototype->IsJSProxy()) {
|
||||||
|
Handle<WeakCell> cell = isolate->factory()->NewWeakCell(prototype);
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
Handle<PrototypeInfo> proto_info =
|
Handle<PrototypeInfo> proto_info =
|
||||||
GetOrCreatePrototypeInfo(prototype, isolate);
|
GetOrCreatePrototypeInfo(Handle<JSObject>::cast(prototype), isolate);
|
||||||
Object* maybe_cell = proto_info->weak_cell();
|
Object* maybe_cell = proto_info->weak_cell();
|
||||||
// Return existing cell if it's already created.
|
// Return existing cell if it's already created.
|
||||||
if (maybe_cell->IsWeakCell()) {
|
if (maybe_cell->IsWeakCell()) {
|
||||||
|
@ -6296,6 +6296,11 @@ class JSProxy: public JSReceiver {
|
|||||||
Isolate* isolate, Handle<JSProxy> proxy, Handle<Name> name,
|
Isolate* isolate, Handle<JSProxy> proxy, Handle<Name> name,
|
||||||
Handle<Object> receiver, bool* was_found);
|
Handle<Object> receiver, bool* was_found);
|
||||||
|
|
||||||
|
static MaybeHandle<Object> CheckGetTrapResult(Isolate* isolate,
|
||||||
|
Handle<Name> name,
|
||||||
|
Handle<JSReceiver> target,
|
||||||
|
Handle<Object> trap_result);
|
||||||
|
|
||||||
// ES6 9.5.9
|
// ES6 9.5.9
|
||||||
MUST_USE_RESULT static Maybe<bool> SetProperty(Handle<JSProxy> proxy,
|
MUST_USE_RESULT static Maybe<bool> SetProperty(Handle<JSProxy> proxy,
|
||||||
Handle<Name> name,
|
Handle<Name> name,
|
||||||
|
@ -319,7 +319,7 @@ class Map : public HeapObject {
|
|||||||
// Returns a WeakCell object containing given prototype. The cell is cached
|
// Returns a WeakCell object containing given prototype. The cell is cached
|
||||||
// in PrototypeInfo which is created lazily.
|
// in PrototypeInfo which is created lazily.
|
||||||
static Handle<WeakCell> GetOrCreatePrototypeWeakCell(
|
static Handle<WeakCell> GetOrCreatePrototypeWeakCell(
|
||||||
Handle<JSObject> prototype, Isolate* isolate);
|
Handle<JSReceiver> prototype, Isolate* isolate);
|
||||||
|
|
||||||
Map* FindRootMap() const;
|
Map* FindRootMap() const;
|
||||||
Map* FindFieldOwner(int descriptor) const;
|
Map* FindFieldOwner(int descriptor) const;
|
||||||
|
@ -46,5 +46,30 @@ RUNTIME_FUNCTION(Runtime_JSProxyRevoke) {
|
|||||||
return isolate->heap()->undefined_value();
|
return isolate->heap()->undefined_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_GetPropertyWithReceiver) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
|
DCHECK_EQ(3, args.length());
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, holder, 0);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 2);
|
||||||
|
|
||||||
|
LookupIterator it =
|
||||||
|
LookupIterator::PropertyOrElement(isolate, receiver, name, holder);
|
||||||
|
RETURN_RESULT_OR_FAILURE(isolate, Object::GetProperty(&it));
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_CheckProxyGetTrapResult) {
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
RETURN_RESULT_OR_FAILURE(
|
||||||
|
isolate, JSProxy::CheckGetTrapResult(isolate, name, target, trap_result));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -460,11 +460,13 @@ namespace internal {
|
|||||||
F(PromiseStatus, 1, 1) \
|
F(PromiseStatus, 1, 1) \
|
||||||
F(ReportPromiseReject, 2, 1)
|
F(ReportPromiseReject, 2, 1)
|
||||||
|
|
||||||
#define FOR_EACH_INTRINSIC_PROXY(F) \
|
#define FOR_EACH_INTRINSIC_PROXY(F) \
|
||||||
F(IsJSProxy, 1, 1) \
|
F(IsJSProxy, 1, 1) \
|
||||||
F(JSProxyGetTarget, 1, 1) \
|
F(JSProxyGetTarget, 1, 1) \
|
||||||
F(JSProxyGetHandler, 1, 1) \
|
F(JSProxyGetHandler, 1, 1) \
|
||||||
F(JSProxyRevoke, 1, 1)
|
F(JSProxyRevoke, 1, 1) \
|
||||||
|
F(GetPropertyWithReceiver, 2, 1) \
|
||||||
|
F(CheckProxyGetTrapResult, 2, 1)
|
||||||
|
|
||||||
#define FOR_EACH_INTRINSIC_REGEXP(F) \
|
#define FOR_EACH_INTRINSIC_REGEXP(F) \
|
||||||
F(IsRegExp, 1, 1) \
|
F(IsRegExp, 1, 1) \
|
||||||
|
@ -207,6 +207,8 @@
|
|||||||
'builtins/builtins-promise-gen.cc',
|
'builtins/builtins-promise-gen.cc',
|
||||||
'builtins/builtins-promise-gen.h',
|
'builtins/builtins-promise-gen.h',
|
||||||
'builtins/builtins-proxy-gen.cc',
|
'builtins/builtins-proxy-gen.cc',
|
||||||
|
'builtins/builtins-proxy-helpers-gen.cc',
|
||||||
|
'builtins/builtins-proxy-helpers-gen.h',
|
||||||
'builtins/builtins-regexp-gen.cc',
|
'builtins/builtins-regexp-gen.cc',
|
||||||
'builtins/builtins-regexp-gen.h',
|
'builtins/builtins-regexp-gen.h',
|
||||||
'builtins/builtins-sharedarraybuffer-gen.cc',
|
'builtins/builtins-sharedarraybuffer-gen.cc',
|
||||||
|
@ -35,6 +35,12 @@
|
|||||||
assertThrows("proxy.property", Error);
|
assertThrows("proxy.property", Error);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
(function testThrowOnTrapNotCallable() {
|
||||||
|
var handler = new Proxy({}, {get: 'not_callable' });
|
||||||
|
var proxy = new Proxy({}, handler);
|
||||||
|
assertThrows("proxy.property", Error);
|
||||||
|
})();
|
||||||
|
|
||||||
(function testFallback() {
|
(function testFallback() {
|
||||||
var target = {property:"value"};
|
var target = {property:"value"};
|
||||||
var proxy = new Proxy(target, {});
|
var proxy = new Proxy(target, {});
|
||||||
@ -125,3 +131,83 @@
|
|||||||
"[[Get]](iterator, next)"
|
"[[Get]](iterator, next)"
|
||||||
], log);
|
], log);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
(function testGetterWithSideEffect() {
|
||||||
|
var obj = {
|
||||||
|
key: 0
|
||||||
|
}
|
||||||
|
assertEquals(obj.key, 0);
|
||||||
|
var p = new Proxy(obj, {});
|
||||||
|
var q = new Proxy(p, {
|
||||||
|
get(target, name) {
|
||||||
|
if (name != 'key') return Reflect.get(target, name);
|
||||||
|
target.key++;
|
||||||
|
return target.key;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals(0, p.key);
|
||||||
|
// Assert the trap is not called twice.
|
||||||
|
assertEquals(1, q.key);
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function testReceiverWithTrap() {
|
||||||
|
var obj = {};
|
||||||
|
var p = new Proxy(obj, {
|
||||||
|
get(target, name, receiver) {
|
||||||
|
if (name != 'key') return Reflect.get(target, name);
|
||||||
|
|
||||||
|
assertSame(target, obj);
|
||||||
|
assertSame(receiver, p);
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertEquals(42, p.key);
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function testReceiverWithoutTrap() {
|
||||||
|
var obj = {
|
||||||
|
get prop() {
|
||||||
|
assertSame(this, p);
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var p = new Proxy(obj, {});
|
||||||
|
assertEquals(42, p.prop);
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function testGetPropertyDetailsBailout() {
|
||||||
|
var obj = {
|
||||||
|
}
|
||||||
|
var p = new Proxy(obj, {
|
||||||
|
getOwnPropertyDescriptor() {
|
||||||
|
throw new Error('Error from proxy getOwnPropertyDescriptor trap');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var q = new Proxy(p, {
|
||||||
|
get(target, name) {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertThrows(function(){ q.prop }, Error,
|
||||||
|
'Error from proxy getOwnPropertyDescriptor trap');
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
(function testGetPropertyDetailsBailout2() {
|
||||||
|
var obj = {};
|
||||||
|
Object.defineProperty(obj, 'prop', {
|
||||||
|
value: 53,
|
||||||
|
configurable: false
|
||||||
|
});
|
||||||
|
var p = new Proxy(obj, {});
|
||||||
|
var q = new Proxy(p, {
|
||||||
|
get(target, name) {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertThrows(function(){ q.prop }, TypeError,
|
||||||
|
"'get' on proxy: property 'prop' is a read-only and non-configurable data" +
|
||||||
|
" property on the proxy target but the proxy did not return its actual" +
|
||||||
|
" value (expected '53' but got '42')");
|
||||||
|
})();
|
||||||
|
36
test/mjsunit/regress/regress-crbug-752712.js
Normal file
36
test/mjsunit/regress/regress-crbug-752712.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax
|
||||||
|
|
||||||
|
// Proxy get trap doesn't fail when the value returned by it
|
||||||
|
// is a number.
|
||||||
|
|
||||||
|
function __getProperties(obj, type) {
|
||||||
|
if(typeof obj === "undefined" || obj === null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
let properties = [];
|
||||||
|
for(let name of Object.getOwnPropertyNames(obj)) {
|
||||||
|
properties.push(name);
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
var number = 1;
|
||||||
|
|
||||||
|
(function testFailingInvariant() {
|
||||||
|
var obj = {};
|
||||||
|
var handler = {
|
||||||
|
get: function() {}
|
||||||
|
};
|
||||||
|
var proxy = new Proxy(obj, handler);
|
||||||
|
Object.defineProperty(handler, 'get', {
|
||||||
|
get: function() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertThrows(function(){ proxy.property; }, TypeError);
|
||||||
|
})();
|
21
test/mjsunit/regress/regress-crbug-752846.js
Normal file
21
test/mjsunit/regress/regress-crbug-752846.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax
|
||||||
|
|
||||||
|
// Check that the receiver of Runtime_GetPropertyWithReceiver can be
|
||||||
|
// a plain JS value.
|
||||||
|
|
||||||
|
var values = [
|
||||||
|
10,
|
||||||
|
false,
|
||||||
|
"test"
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let val of values) {
|
||||||
|
var proto = Object.getPrototypeOf(val);
|
||||||
|
|
||||||
|
var proxy = new Proxy({}, {});
|
||||||
|
Object.setPrototypeOf(proto, proxy);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user