Add GetPropertyWithReceiver stub for proxy get trap

GetPropertyWithReceiver is similar to GetProperty, except that additional receiver parameter is used in TryPrototypeChainLookup to support GetPropertyWithReceiver stub.
We only use this stub in ProxyGetProperty builtin for now.

Bug: v8:8958
Change-Id: Ied60e4f6ee6e09bca2f161048b481a0bf37a78a7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1676879
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62431}
This commit is contained in:
Z Nguyen-Huu 2019-06-27 12:11:25 -07:00 committed by Commit Bot
parent 327190f4eb
commit a77323416a
7 changed files with 84 additions and 17 deletions

View File

@ -1142,6 +1142,7 @@ namespace internal {
ASM(StackCheck, Dummy) \
ASM(DoubleToI, Dummy) \
TFC(GetProperty, GetProperty) \
TFS(GetPropertyWithReceiver, kObject, kKey, kReceiver, kOnNonExistent) \
TFS(SetProperty, kReceiver, kKey, kValue) \
TFS(SetPropertyInLiteral, kReceiver, kKey, kValue) \
ASM(MemCopyUint8Uint8, CCall) \

View File

@ -908,6 +908,8 @@ TF_BUILTIN(GetProperty, CodeStubAssembler) {
Node* object = Parameter(Descriptor::kObject);
Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext);
// TODO(duongn): consider tailcalling to GetPropertyWithReceiver(object,
// object, key, OnNonExistent::kReturnUndefined).
Label if_notfound(this), if_proxy(this, Label::kDeferred),
if_slow(this, Label::kDeferred);
@ -933,7 +935,7 @@ TF_BUILTIN(GetProperty, CodeStubAssembler) {
Goto(if_bailout);
};
TryPrototypeChainLookup(object, key, lookup_property_in_holder,
TryPrototypeChainLookup(object, object, key, lookup_property_in_holder,
lookup_element_in_holder, &if_notfound, &if_slow,
&if_proxy);
@ -956,6 +958,71 @@ TF_BUILTIN(GetProperty, CodeStubAssembler) {
}
}
// ES6 [[Get]] operation with Receiver.
TF_BUILTIN(GetPropertyWithReceiver, CodeStubAssembler) {
Node* object = Parameter(Descriptor::kObject);
Node* key = Parameter(Descriptor::kKey);
Node* context = Parameter(Descriptor::kContext);
Node* receiver = Parameter(Descriptor::kReceiver);
Node* on_non_existent = Parameter(Descriptor::kOnNonExistent);
Label if_notfound(this), if_proxy(this, Label::kDeferred),
if_slow(this, Label::kDeferred);
CodeStubAssembler::LookupInHolder lookup_property_in_holder =
[=](Node* receiver, Node* holder, Node* holder_map,
Node* holder_instance_type, Node* unique_name, Label* next_holder,
Label* if_bailout) {
VARIABLE(var_value, MachineRepresentation::kTagged);
Label if_found(this);
TryGetOwnProperty(context, receiver, holder, holder_map,
holder_instance_type, unique_name, &if_found,
&var_value, next_holder, if_bailout);
BIND(&if_found);
Return(var_value.value());
};
CodeStubAssembler::LookupInHolder lookup_element_in_holder =
[=](Node* receiver, Node* holder, Node* holder_map,
Node* holder_instance_type, Node* index, Label* next_holder,
Label* if_bailout) {
// Not supported yet.
Use(next_holder);
Goto(if_bailout);
};
TryPrototypeChainLookup(receiver, object, key, lookup_property_in_holder,
lookup_element_in_holder, &if_notfound, &if_slow,
&if_proxy);
BIND(&if_notfound);
Label throw_reference_error(this);
GotoIf(WordEqual(on_non_existent,
SmiConstant(OnNonExistent::kThrowReferenceError)),
&throw_reference_error);
CSA_ASSERT(this, WordEqual(on_non_existent,
SmiConstant(OnNonExistent::kReturnUndefined)));
Return(UndefinedConstant());
BIND(&throw_reference_error);
Return(CallRuntime(Runtime::kThrowReferenceError, context, key));
BIND(&if_slow);
TailCallRuntime(Runtime::kGetPropertyWithReceiver, context, object, key,
receiver, on_non_existent);
BIND(&if_proxy);
{
// Convert the {key} to a Name first.
Node* name = CallBuiltin(Builtins::kToName, context, key);
// The {object} is a JSProxy instance, look up the {name} on it, passing
// {object} both as receiver and holder. If {name} is absent we can safely
// return undefined from here.
TailCallBuiltin(Builtins::kProxyGetProperty, context, object, name,
receiver, on_non_existent);
}
}
// ES6 [[Set]] operation.
TF_BUILTIN(SetProperty, CodeStubAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));

View File

@ -6,9 +6,8 @@
namespace proxy {
extern transitioning runtime
GetPropertyWithReceiver(implicit context: Context)(Object, Name, Object, Smi):
Object;
extern transitioning builtin GetPropertyWithReceiver(
implicit context: Context)(Object, Name, Object, Smi): Object;
// ES #sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver
// https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver
@ -40,7 +39,6 @@ namespace proxy {
// 6. Let trap be ? GetMethod(handler, "get").
// 7. If trap is undefined, then (see 7.a below).
// 7.a. Return ? target.[[Get]](P, Receiver).
// TODO(mslekova): Introduce GetPropertyWithReceiver stub
const trap: Callable = GetMethod(handler, 'get')
otherwise return GetPropertyWithReceiver(
target, name, receiverValue, onNonExistent);

View File

@ -9856,15 +9856,16 @@ void CodeStubAssembler::BranchIfMaybeSpecialIndex(TNode<String> name_string,
}
void CodeStubAssembler::TryPrototypeChainLookup(
Node* receiver, Node* key, const LookupInHolder& lookup_property_in_holder,
Node* receiver, Node* object, Node* key,
const LookupInHolder& lookup_property_in_holder,
const LookupInHolder& lookup_element_in_holder, Label* if_end,
Label* if_bailout, Label* if_proxy) {
// Ensure receiver is JSReceiver, otherwise bailout.
Label if_objectisnotsmi(this);
Branch(TaggedIsSmi(receiver), if_bailout, &if_objectisnotsmi);
Branch(TaggedIsSmi(object), if_bailout, &if_objectisnotsmi);
BIND(&if_objectisnotsmi);
Node* map = LoadMap(receiver);
Node* map = LoadMap(object);
Node* instance_type = LoadMapInstanceType(map);
{
Label if_objectisreceiver(this);
@ -9874,9 +9875,7 @@ void CodeStubAssembler::TryPrototypeChainLookup(
if_bailout);
BIND(&if_objectisreceiver);
if (if_proxy) {
GotoIf(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), if_proxy);
}
GotoIf(InstanceTypeEqual(instance_type, JS_PROXY_TYPE), if_proxy);
}
VARIABLE(var_index, MachineType::PointerRepresentation());
@ -9888,7 +9887,7 @@ void CodeStubAssembler::TryPrototypeChainLookup(
BIND(&if_iskeyunique);
{
VARIABLE(var_holder, MachineRepresentation::kTagged, receiver);
VARIABLE(var_holder, MachineRepresentation::kTagged, object);
VARIABLE(var_holder_map, MachineRepresentation::kTagged, map);
VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32,
instance_type);
@ -9934,7 +9933,7 @@ void CodeStubAssembler::TryPrototypeChainLookup(
}
BIND(&if_keyisindex);
{
VARIABLE(var_holder, MachineRepresentation::kTagged, receiver);
VARIABLE(var_holder, MachineRepresentation::kTagged, object);
VARIABLE(var_holder_map, MachineRepresentation::kTagged, map);
VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32,
instance_type);
@ -12706,7 +12705,7 @@ TNode<Oddball> CodeStubAssembler::HasProperty(SloppyTNode<Context> context,
&return_true, &return_false, next_holder, if_bailout);
};
TryPrototypeChainLookup(object, key, lookup_property_in_holder,
TryPrototypeChainLookup(object, object, key, lookup_property_in_holder,
lookup_element_in_holder, &return_false,
&call_runtime, &if_proxy);

View File

@ -2999,11 +2999,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// If it can't handle the case {receiver}/{key} case then the control goes
// to {if_bailout}.
// If {if_proxy} is nullptr, proxies go to if_bailout.
void TryPrototypeChainLookup(Node* receiver, Node* key,
void TryPrototypeChainLookup(Node* receiver, Node* object, Node* key,
const LookupInHolder& lookup_property_in_holder,
const LookupInHolder& lookup_element_in_holder,
Label* if_end, Label* if_bailout,
Label* if_proxy = nullptr);
Label* if_proxy);
// Instanceof helpers.
// Returns true if {object} has {prototype} somewhere in it's prototype

View File

@ -548,6 +548,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
Goto(&to_name_failed);
BIND(&to_name_failed);
// TODO(duongn): use GetPropertyWithReceiver builtin once
// |lookup_element_in_holder| supports elements.
exit_point->ReturnCallRuntime(Runtime::kGetPropertyWithReceiver,
p->context, holder, p->name, p->receiver,
SmiConstant(on_nonexistent));

View File

@ -17,5 +17,5 @@ for (let val of values) {
var proto = Object.getPrototypeOf(val);
var proxy = new Proxy({}, {});
Object.setPrototypeOf(proto, proxy);
Object.setPrototypeOf(proxy, proto);
}