Port proxy trap GetProperty to Torque
Also, fix CSA generator for call runtime with return type of object. Spec: https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver Bug: v8:6664 Change-Id: I61ce1fa72a498520dd811f034e182f060f115330 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1573042 Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Cr-Commit-Position: refs/heads/master@{#60995}
This commit is contained in:
parent
ad1cebe8f4
commit
596bea7249
1
BUILD.gn
1
BUILD.gn
@ -943,6 +943,7 @@ torque_files = [
|
||||
"src/builtins/object-fromentries.tq",
|
||||
"src/builtins/proxy.tq",
|
||||
"src/builtins/proxy-constructor.tq",
|
||||
"src/builtins/proxy-get-property.tq",
|
||||
"src/builtins/proxy-revocable.tq",
|
||||
"src/builtins/proxy-revoke.tq",
|
||||
"src/builtins/regexp.tq",
|
||||
|
@ -810,14 +810,12 @@ const kTypedArrayTooShort: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kTypedArrayTooShort';
|
||||
const kInvalidCountValue: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kInvalidCountValue';
|
||||
const kProxyNonObject: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kProxyNonObject';
|
||||
const kProxyHandlerOrTargetRevoked: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kProxyHandlerOrTargetRevoked';
|
||||
const kConstructorNotFunction: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kConstructorNotFunction';
|
||||
const kSymbolToString: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kSymbolToString';
|
||||
const kPropertyNotFunction: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kPropertyNotFunction';
|
||||
|
||||
const kMaxArrayIndex:
|
||||
constexpr uint32 generates 'JSArray::kMaxArrayIndex';
|
||||
@ -2355,6 +2353,8 @@ extern macro TaggedIsCallable(Object): bool;
|
||||
extern macro IsDetachedBuffer(JSArrayBuffer): bool;
|
||||
extern macro IsHeapNumber(HeapObject): bool;
|
||||
extern macro IsFixedArray(HeapObject): bool;
|
||||
extern macro IsName(HeapObject): bool;
|
||||
extern macro IsPrivateSymbol(HeapObject): bool;
|
||||
extern macro IsNumber(Object): bool;
|
||||
extern macro IsNumberNormalized(Number): bool;
|
||||
extern macro IsOddball(HeapObject): bool;
|
||||
@ -2425,6 +2425,14 @@ transitioning macro GetLengthProperty(implicit context: Context)(o: Object):
|
||||
}
|
||||
}
|
||||
|
||||
transitioning macro GetMethod(implicit context: Context)(
|
||||
o: Object, name: constexpr string): Callable labels IfNullOrUndefined {
|
||||
const value = GetProperty(o, name);
|
||||
if (value == Undefined || value == Null) goto IfNullOrUndefined;
|
||||
return Cast<Callable>(value)
|
||||
otherwise ThrowTypeError(kPropertyNotFunction, value, name, o);
|
||||
}
|
||||
|
||||
extern macro NumberToString(Number): String;
|
||||
extern macro IsOneByteStringInstanceType(InstanceType): bool;
|
||||
extern macro AllocateSeqOneByteString(implicit context: Context)(uint32):
|
||||
|
@ -870,7 +870,6 @@ namespace internal {
|
||||
TFJ(PromiseInternalResolve, 2, kReceiver, kPromise, kResolution) \
|
||||
\
|
||||
/* Proxy */ \
|
||||
TFS(ProxyGetProperty, kProxy, kName, kReceiverValue, kOnNonExistent) \
|
||||
TFS(ProxyHasProperty, kProxy, kName) \
|
||||
TFS(ProxySetProperty, kProxy, kName, kValue, kReceiverValue) \
|
||||
\
|
||||
|
@ -338,68 +338,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);
|
||||
Node* on_non_existent = Parameter(Descriptor::kOnNonExistent);
|
||||
|
||||
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, on_non_existent));
|
||||
}
|
||||
|
||||
BIND(&throw_proxy_handler_revoked);
|
||||
ThrowTypeError(context, MessageTemplate::kProxyRevoked, "get");
|
||||
}
|
||||
|
||||
TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
Node* proxy = Parameter(Descriptor::kProxy);
|
||||
@ -450,8 +388,8 @@ TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
|
||||
{
|
||||
// 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
|
||||
Label return_result(this);
|
||||
CheckGetSetTrapResult(context, target, proxy, name, value, &success,
|
||||
JSProxy::kSet);
|
||||
Return(CheckGetSetTrapResult(context, target, proxy, name, value,
|
||||
JSProxy::kSet));
|
||||
}
|
||||
|
||||
BIND(&failure);
|
||||
@ -487,21 +425,22 @@ TF_BUILTIN(ProxySetProperty, ProxiesCodeStubAssembler) {
|
||||
ThrowTypeError(context, MessageTemplate::kProxyRevoked, "set");
|
||||
}
|
||||
|
||||
void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
|
||||
Node* ProxiesCodeStubAssembler::CheckGetSetTrapResult(
|
||||
Node* context, Node* target, Node* proxy, Node* name, Node* trap_result,
|
||||
Label* check_passed, JSProxy::AccessKind access_kind) {
|
||||
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);
|
||||
Label if_found_value(this), check_in_runtime(this, Label::kDeferred),
|
||||
check_passed(this);
|
||||
|
||||
GotoIfNot(IsUniqueNameNoIndex(CAST(name)), &check_in_runtime);
|
||||
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, kReturnAccessorPair);
|
||||
&check_passed, &check_in_runtime, kReturnAccessorPair);
|
||||
|
||||
BIND(&if_found_value);
|
||||
{
|
||||
@ -513,7 +452,7 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
|
||||
// false, then:
|
||||
GotoIfNot(IsSetWord32(var_details.value(),
|
||||
PropertyDetails::kAttributesDontDeleteMask),
|
||||
check_passed);
|
||||
&check_passed);
|
||||
|
||||
// If IsDataDescriptor(targetDesc) is true and
|
||||
// targetDesc.[[Writable]] is false, then:
|
||||
@ -523,11 +462,11 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
|
||||
{
|
||||
Node* read_only = IsSetWord32(var_details.value(),
|
||||
PropertyDetails::kAttributesReadOnlyMask);
|
||||
GotoIfNot(read_only, check_passed);
|
||||
GotoIfNot(read_only, &check_passed);
|
||||
|
||||
// If SameValue(trapResult, targetDesc.[[Value]]) is false,
|
||||
// throw a TypeError exception.
|
||||
BranchIfSameValue(trap_result, var_value.value(), check_passed,
|
||||
BranchIfSameValue(trap_result, var_value.value(), &check_passed,
|
||||
&throw_non_configurable_data);
|
||||
}
|
||||
|
||||
@ -545,7 +484,7 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
|
||||
// defined it's set as null.
|
||||
GotoIf(IsUndefined(getter), &continue_check);
|
||||
GotoIf(IsNull(getter), &continue_check);
|
||||
Goto(check_passed);
|
||||
Goto(&check_passed);
|
||||
|
||||
// 10.b.i. If trapResult is not undefined, throw a TypeError exception.
|
||||
BIND(&continue_check);
|
||||
@ -558,14 +497,7 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
|
||||
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);
|
||||
Goto(&check_passed);
|
||||
}
|
||||
|
||||
BIND(&throw_non_configurable_data);
|
||||
@ -588,6 +520,16 @@ void ProxiesCodeStubAssembler::CheckGetSetTrapResult(
|
||||
ThrowTypeError(context, MessageTemplate::kProxySetFrozenAccessor, name);
|
||||
}
|
||||
}
|
||||
|
||||
BIND(&check_in_runtime);
|
||||
{
|
||||
CallRuntime(Runtime::kCheckProxyGetSetTrapResult, context, name, target,
|
||||
trap_result, SmiConstant(access_kind));
|
||||
Goto(&check_passed);
|
||||
}
|
||||
|
||||
BIND(&check_passed);
|
||||
return trap_result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,10 @@ class ProxiesCodeStubAssembler : public CodeStubAssembler {
|
||||
// TODO(v8:9120): Remove this once torque support exists
|
||||
Node* GetProxyConstructorJSNewTarget();
|
||||
|
||||
Node* CheckGetSetTrapResult(Node* context, Node* target, Node* proxy,
|
||||
Node* name, Node* trap_result,
|
||||
JSProxy::AccessKind access_kind);
|
||||
|
||||
protected:
|
||||
enum ProxyRevokeFunctionContextSlot {
|
||||
kProxySlot = Context::MIN_CONTEXT_SLOTS,
|
||||
@ -47,10 +51,6 @@ class ProxiesCodeStubAssembler : public CodeStubAssembler {
|
||||
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);
|
||||
|
||||
private:
|
||||
Node* CreateProxyRevokeFunctionContext(Node* proxy, Node* native_context);
|
||||
};
|
||||
|
67
src/builtins/proxy-get-property.tq
Normal file
67
src/builtins/proxy-get-property.tq
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright 2019 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-gen.h'
|
||||
|
||||
namespace proxy {
|
||||
|
||||
extern transitioning runtime
|
||||
GetPropertyWithReceiver(implicit context: Context)(Object, Name, Object, Smi):
|
||||
Object;
|
||||
|
||||
extern transitioning macro ProxiesCodeStubAssembler::CheckGetSetTrapResult(
|
||||
implicit context:
|
||||
Context)(Object, JSProxy, Name, Object, constexpr int31): 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
|
||||
transitioning builtin
|
||||
ProxyGetProperty(implicit context: Context)(
|
||||
proxy: JSProxy, name: Name, receiverValue: Object,
|
||||
onNonExistent: Smi): Object {
|
||||
// 1. Assert: IsPropertyKey(P) is true.
|
||||
assert(TaggedIsNotSmi(name));
|
||||
assert(IsName(name));
|
||||
assert(!IsPrivateSymbol(name));
|
||||
|
||||
// 2. Let handler be O.[[ProxyHandler]].
|
||||
const handler: Object = proxy.handler;
|
||||
|
||||
// 3. If handler is null, throw a TypeError exception.
|
||||
if (handler == Null) {
|
||||
ThrowTypeError(kProxyRevoked, 'get');
|
||||
}
|
||||
|
||||
// 4. Assert: Type(handler) is Object.
|
||||
const handlerJSReceiver = UnsafeCast<JSReceiver>(handler);
|
||||
|
||||
// 5. Let target be O.[[ProxyTarget]].
|
||||
const target = proxy.target;
|
||||
|
||||
// 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(handlerJSReceiver, 'get')
|
||||
otherwise return GetPropertyWithReceiver(
|
||||
target, name, receiverValue, onNonExistent);
|
||||
|
||||
// 8. Let trapResult be ? Call(trap, handler, « target, P, Receiver »).
|
||||
const trapResult =
|
||||
Call(context, trap, handlerJSReceiver, target, name, receiverValue);
|
||||
|
||||
// 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
|
||||
// 10. If targetDesc is not undefined and targetDesc.[[Configurable]] is
|
||||
// false, then
|
||||
// a. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]]
|
||||
// is false, then
|
||||
// i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a
|
||||
// TypeError exception.
|
||||
// b. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Get]]
|
||||
// is undefined, then
|
||||
// i. If trapResult is not undefined, throw a TypeError exception.
|
||||
// 11. Return trapResult.
|
||||
return CheckGetSetTrapResult(target, proxy, name, trapResult, kProxyGet);
|
||||
}
|
||||
}
|
@ -19,4 +19,16 @@ namespace proxy {
|
||||
Cast<JSReceiver>(proxy.handler) otherwise return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const kProxyNonObject: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kProxyNonObject';
|
||||
const kProxyHandlerOrTargetRevoked: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kProxyHandlerOrTargetRevoked';
|
||||
const kProxyRevoked: constexpr MessageTemplate
|
||||
generates 'MessageTemplate::kProxyRevoked';
|
||||
|
||||
const kProxyGet: constexpr int31
|
||||
generates 'JSProxy::AccessKind::kGet';
|
||||
const kProxySet: constexpr int31
|
||||
generates 'JSProxy::AccessKind::kSet';
|
||||
}
|
||||
|
@ -580,12 +580,16 @@ void CSAGenerator::EmitInstruction(const CallRuntimeInstruction& instruction,
|
||||
PreCallableExceptionPreparation(instruction.catch_block);
|
||||
Stack<std::string> pre_call_stack = *stack;
|
||||
if (result_types.size() == 1) {
|
||||
std::string generated_type = result_types[0]->GetGeneratedTNodeTypeName();
|
||||
stack->Push(result_name);
|
||||
out_ << " " << result_name
|
||||
<< " = TORQUE_CAST(CodeStubAssembler(state_).CallRuntime(Runtime::k"
|
||||
out_ << " " << result_name << " = ";
|
||||
if (generated_type != "Object") out_ << "TORQUE_CAST(";
|
||||
out_ << "CodeStubAssembler(state_).CallRuntime(Runtime::k"
|
||||
<< instruction.runtime_function->ExternalName() << ", ";
|
||||
PrintCommaSeparatedList(out_, arguments);
|
||||
out_ << "));\n";
|
||||
out_ << ")";
|
||||
if (generated_type != "Object") out_ << ")";
|
||||
out_ << "; \n";
|
||||
out_ << " USE(" << result_name << ");\n";
|
||||
} else {
|
||||
DCHECK_EQ(0, result_types.size());
|
||||
|
Loading…
Reference in New Issue
Block a user