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:
parent
327190f4eb
commit
a77323416a
@ -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) \
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user