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:
Z Duong Nguyen-Huu 2019-04-24 10:29:13 -07:00 committed by Commit Bot
parent ad1cebe8f4
commit 596bea7249
8 changed files with 125 additions and 92 deletions

View File

@ -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",

View File

@ -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):

View File

@ -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) \
\

View File

@ -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;
}
}

View File

@ -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);
};

View 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);
}
}

View File

@ -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';
}

View File

@ -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());