[builtins] Port Proxy.revocable() to CSA

Bug: v8:7245
Change-Id: Ia8931037021b935e776230a6a50c580ad82efba8
Reviewed-on: https://chromium-review.googlesource.com/844065
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50394}
This commit is contained in:
Timothy Gu 2018-01-05 22:40:40 +08:00 committed by Commit Bot
parent 211d569a2b
commit ddfbbc5537
18 changed files with 195 additions and 58 deletions

View File

@ -135,6 +135,7 @@ Sanjoy Das <sanjoy@playingwithpointers.com>
Seo Sanghyeon <sanxiyn@gmail.com>
Stefan Penner <stefan.penner@gmail.com>
Sylvestre Ledru <sledru@mozilla.com>
Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Tobias Burnus <burnus@net-b.de>
Victor Costan <costan@gmail.com>
Vlad Burlik <vladbph@gmail.com>

View File

@ -592,7 +592,6 @@ action("js2c") {
"src/js/typedarray.js",
"src/js/messages.js",
"src/js/spread.js",
"src/js/proxy.js",
"src/debug/mirrors.js",
"src/debug/debug.js",
"src/debug/liveedit.js",

View File

@ -1086,6 +1086,31 @@ void Genesis::CreateJSProxyMaps() {
Map::Copy(proxy_callable_map, "constructor Proxy");
proxy_constructor_map->set_is_constructor(true);
native_context()->set_proxy_constructor_map(*proxy_constructor_map);
{
Handle<Map> map =
factory()->NewMap(JS_OBJECT_TYPE, JSProxyRevocableResult::kSize,
TERMINAL_FAST_ELEMENTS_KIND, 2);
Map::EnsureDescriptorSlack(map, 2);
{ // proxy
Descriptor d = Descriptor::DataField(factory()->proxy_string(),
JSProxyRevocableResult::kProxyIndex,
NONE, Representation::Tagged());
map->AppendDescriptor(&d);
}
{ // revoke
Descriptor d = Descriptor::DataField(factory()->revoke_string(),
JSProxyRevocableResult::kRevokeIndex,
NONE, Representation::Tagged());
map->AppendDescriptor(&d);
}
Map::SetPrototype(map, isolate()->initial_object_prototype());
map->SetConstructor(native_context()->object_function());
native_context()->set_proxy_revocable_result_map(*map);
}
}
namespace {
@ -3428,6 +3453,15 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
native_context()->set_proxy_function(*proxy_function);
InstallFunction(global, name, proxy_function, factory->Object_string());
SimpleInstallFunction(proxy_function, "revocable",
Builtins::kProxyRevocable, 2, true);
{ // Internal: ProxyRevoke
Handle<SharedFunctionInfo> info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kProxyRevoke, factory->empty_string(), 0);
native_context()->set_proxy_revoke_shared_fun(*info);
}
}
{ // -- R e f l e c t

View File

@ -838,6 +838,8 @@ namespace internal {
TFJ(ProxyConstructor, 0) \
TFJ(ProxyConstructor_ConstructStub, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
TFJ(ProxyRevocable, 2, kTarget, kHandler) \
TFJ(ProxyRevoke, 0) \
TFS(ProxyGetProperty, kProxy, kName, kReceiverValue) \
TFS(ProxyHasProperty, kProxy, kName) \
TFS(ProxySetProperty, kProxy, kName, kValue, kReceiverValue, kLanguageMode) \

View File

@ -189,25 +189,6 @@ Node* PromiseBuiltinsAssembler::NewPromiseCapability(Node* context,
return var_result.value();
}
void PromiseBuiltinsAssembler::InitializeFunctionContext(Node* native_context,
Node* context,
int slots) {
DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex);
StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset,
SmiConstant(slots));
Node* const empty_fn =
LoadContextElement(native_context, Context::CLOSURE_INDEX);
StoreContextElementNoWriteBarrier(context, Context::CLOSURE_INDEX, empty_fn);
StoreContextElementNoWriteBarrier(context, Context::PREVIOUS_INDEX,
UndefinedConstant());
StoreContextElementNoWriteBarrier(context, Context::EXTENSION_INDEX,
TheHoleConstant());
StoreContextElementNoWriteBarrier(context, Context::NATIVE_CONTEXT_INDEX,
native_context);
}
Node* PromiseBuiltinsAssembler::CreatePromiseContext(Node* native_context,
int slots) {
DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);

View File

@ -137,7 +137,6 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
void BranchIfFastPath(Node* native_context, Node* promise_fun, Node* promise,
Label* if_isunmodified, Label* if_ismodified);
void InitializeFunctionContext(Node* native_context, Node* context, int len);
Node* CreatePromiseContext(Node* native_context, int slots);
void PromiseFulfill(Node* context, Node* promise, Node* result,
v8::Promise::PromiseState status);

View File

@ -126,6 +126,107 @@ TF_BUILTIN(ProxyConstructor_ConstructStub, ProxiesCodeStubAssembler) {
ThrowTypeError(context, MessageTemplate::kProxyHandlerOrTargetRevoked);
}
Node* ProxiesCodeStubAssembler::CreateProxyRevokeFunctionContext(
Node* proxy, Node* native_context) {
Node* const context = Allocate(FixedArray::SizeFor(kProxyContextLength));
StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex);
InitializeFunctionContext(native_context, context, kProxyContextLength);
StoreContextElementNoWriteBarrier(context, kProxySlot, proxy);
return context;
}
Node* ProxiesCodeStubAssembler::AllocateProxyRevokeFunction(Node* proxy,
Node* context) {
Node* const native_context = LoadNativeContext(context);
Node* const proxy_context =
CreateProxyRevokeFunctionContext(proxy, native_context);
Node* const revoke_map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
Node* const revoke_info =
LoadContextElement(native_context, Context::PROXY_REVOKE_SHARED_FUN);
return AllocateFunctionWithMapAndContext(revoke_map, revoke_info,
proxy_context);
}
TF_BUILTIN(ProxyRevocable, ProxiesCodeStubAssembler) {
Node* const target = Parameter(Descriptor::kTarget);
Node* const handler = Parameter(Descriptor::kHandler);
Node* const context = Parameter(Descriptor::kContext);
Node* const native_context = LoadNativeContext(context);
Label throw_proxy_non_object(this, Label::kDeferred),
throw_proxy_handler_or_target_revoked(this, Label::kDeferred),
return_create_proxy(this);
GotoIf(TaggedIsSmi(target), &throw_proxy_non_object);
GotoIfNot(IsJSReceiver(target), &throw_proxy_non_object);
GotoIfRevokedProxy(target, &throw_proxy_handler_or_target_revoked);
GotoIf(TaggedIsSmi(handler), &throw_proxy_non_object);
GotoIfNot(IsJSReceiver(handler), &throw_proxy_non_object);
GotoIfRevokedProxy(handler, &throw_proxy_handler_or_target_revoked);
Node* const proxy = AllocateProxy(target, handler, context);
Node* const revoke = AllocateProxyRevokeFunction(proxy, context);
Node* const result = Allocate(JSProxyRevocableResult::kSize);
Node* const result_map = LoadContextElement(
native_context, Context::PROXY_REVOCABLE_RESULT_MAP_INDEX);
StoreMapNoWriteBarrier(result, result_map);
StoreObjectFieldRoot(result, JSProxyRevocableResult::kPropertiesOrHashOffset,
Heap::kEmptyFixedArrayRootIndex);
StoreObjectFieldRoot(result, JSProxyRevocableResult::kElementsOffset,
Heap::kEmptyFixedArrayRootIndex);
StoreObjectFieldNoWriteBarrier(result, JSProxyRevocableResult::kProxyOffset,
proxy);
StoreObjectFieldNoWriteBarrier(result, JSProxyRevocableResult::kRevokeOffset,
revoke);
Return(result);
BIND(&throw_proxy_non_object);
ThrowTypeError(context, MessageTemplate::kProxyNonObject);
BIND(&throw_proxy_handler_or_target_revoked);
ThrowTypeError(context, MessageTemplate::kProxyHandlerOrTargetRevoked);
}
// Proxy Revocation Functions
// https://tc39.github.io/ecma262/#sec-proxy-revocation-functions
TF_BUILTIN(ProxyRevoke, ProxiesCodeStubAssembler) {
Node* const context = Parameter(Descriptor::kContext);
// 1. Let p be F.[[RevocableProxy]].
Node* const proxy_slot = IntPtrConstant(kProxySlot);
Node* const proxy = LoadContextElement(context, proxy_slot);
Label revoke_called(this);
// 2. If p is null, ...
GotoIf(IsNull(proxy), &revoke_called);
// 3. Set F.[[RevocableProxy]] to null.
StoreContextElement(context, proxy_slot, NullConstant());
// 4. Assert: p is a Proxy object.
CSA_ASSERT(this, IsJSProxy(proxy));
// TODO(timothygu): Execute this step.
// 5. Set p.[[ProxyTarget]] to null.
// StoreObjectField(proxy, JSProxy::kTargetOffset, NullConstant());
// 6. Set p.[[ProxyHandler]] to null.
StoreObjectField(proxy, JSProxy::kHandlerOffset, NullConstant());
// 7. Return undefined.
Return(UndefinedConstant());
BIND(&revoke_called);
// 2. ... return undefined.
Return(UndefinedConstant());
}
TF_BUILTIN(CallProxy, ProxiesCodeStubAssembler) {
Node* argc = Parameter(Descriptor::kActualArgumentsCount);
Node* argc_ptr = ChangeInt32ToIntPtr(argc);

View File

@ -27,17 +27,26 @@ class ProxiesCodeStubAssembler : public CodeStubAssembler {
Node* receiver);
protected:
enum ProxyRevokeFunctionContextSlot {
kProxySlot = Context::MIN_CONTEXT_SLOTS,
kProxyContextLength,
};
void GotoIfRevokedProxy(Node* object, Label* if_proxy_revoked);
Node* AllocateProxy(Node* target, Node* handler, Node* context);
Node* AllocateJSArrayForCodeStubArguments(Node* context,
CodeStubArguments& args, Node* argc,
ParameterMode mode);
Node* AllocateProxyRevokeFunction(Node* proxy, Node* context);
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);
};
} // namespace internal

View File

@ -10685,5 +10685,23 @@ void CodeStubAssembler::PerformStackCheck(Node* context) {
BIND(&ok);
}
void CodeStubAssembler::InitializeFunctionContext(Node* native_context,
Node* context, int slots) {
DCHECK_GE(slots, Context::MIN_CONTEXT_SLOTS);
StoreMapNoWriteBarrier(context, Heap::kFunctionContextMapRootIndex);
StoreObjectFieldNoWriteBarrier(context, FixedArray::kLengthOffset,
SmiConstant(slots));
Node* const empty_fn =
LoadContextElement(native_context, Context::CLOSURE_INDEX);
StoreContextElementNoWriteBarrier(context, Context::CLOSURE_INDEX, empty_fn);
StoreContextElementNoWriteBarrier(context, Context::PREVIOUS_INDEX,
UndefinedConstant());
StoreContextElementNoWriteBarrier(context, Context::EXTENSION_INDEX,
TheHoleConstant());
StoreContextElementNoWriteBarrier(context, Context::NATIVE_CONTEXT_INDEX,
native_context);
}
} // namespace internal
} // namespace v8

View File

@ -1908,6 +1908,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Label* definitely_no_elements,
Label* possibly_elements);
void InitializeFunctionContext(Node* native_context, Node* context,
int slots);
private:
friend class CodeStubArguments;

View File

@ -316,6 +316,8 @@ enum ContextLookupFlags {
V(PROXY_CONSTRUCTOR_MAP_INDEX, Map, proxy_constructor_map) \
V(PROXY_FUNCTION_INDEX, JSFunction, proxy_function) \
V(PROXY_MAP_INDEX, Map, proxy_map) \
V(PROXY_REVOCABLE_RESULT_MAP_INDEX, Map, proxy_revocable_result_map) \
V(PROXY_REVOKE_SHARED_FUN, SharedFunctionInfo, proxy_revoke_shared_fun) \
V(PROMISE_GET_CAPABILITIES_EXECUTOR_SHARED_FUN, SharedFunctionInfo, \
promise_get_capabilities_executor_shared_fun) \
V(PROMISE_RESOLVE_SHARED_FUN, SharedFunctionInfo, \

View File

@ -146,6 +146,7 @@
V(promise_string, "promise") \
V(proto_string, "__proto__") \
V(prototype_string, "prototype") \
V(proxy_string, "proxy") \
V(Proxy_string, "Proxy") \
V(query_colon_string, "(?:)") \
V(RangeError_string, "RangeError") \
@ -155,6 +156,7 @@
V(reject_string, "reject") \
V(resolve_string, "resolve") \
V(return_string, "return") \
V(revoke_string, "revoke") \
V(script_string, "script") \
V(second_string, "second") \
V(setPrototypeOf_string, "setPrototypeOf") \

View File

@ -1,27 +0,0 @@
// Copyright 2015 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.
(function(global, utils) {
"use strict";
%CheckIsBootstrapping();
// ----------------------------------------------------------------------------
// Imports
//
var GlobalProxy = global.Proxy;
//----------------------------------------------------------------------------
//Set up non-enumerable properties of the Proxy object.
DEFINE_METHOD(
GlobalProxy,
revocable(target, handler) {
var p = new GlobalProxy(target, handler);
return {proxy: p, revoke: () => %JSProxyRevoke(p)};
}
);
})

View File

@ -4418,6 +4418,23 @@ class JSProxy: public JSReceiver {
DISALLOW_IMPLICIT_CONSTRUCTORS(JSProxy);
};
// JSProxyRevocableResult is just a JSObject with a specific initial map.
// This initial map adds in-object properties for "proxy" and "revoke".
// See https://tc39.github.io/ecma262/#sec-proxy.revocable
class JSProxyRevocableResult : public JSObject {
public:
// Offsets of object fields.
static const int kProxyOffset = JSObject::kHeaderSize;
static const int kRevokeOffset = kProxyOffset + kPointerSize;
static const int kSize = kRevokeOffset + kPointerSize;
// Indices of in-object properties.
static const int kProxyIndex = 0;
static const int kRevokeIndex = 1;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSProxyRevocableResult);
};
// The [Async-from-Sync Iterator] object
// (proposal-async-iteration/#sec-async-from-sync-iterator-objects)
// An object which wraps an ordinary Iterator and converts it to behave

View File

@ -38,14 +38,6 @@ RUNTIME_FUNCTION(Runtime_JSProxyGetTarget) {
}
RUNTIME_FUNCTION(Runtime_JSProxyRevoke) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
JSProxy::Revoke(proxy);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetPropertyWithReceiver) {
HandleScope scope(isolate);

View File

@ -480,7 +480,6 @@ namespace internal {
F(IsJSProxy, 1, 1) \
F(JSProxyGetTarget, 1, 1) \
F(JSProxyGetHandler, 1, 1) \
F(JSProxyRevoke, 1, 1) \
F(GetPropertyWithReceiver, 2, 1) \
F(CheckProxyHasTrap, 2, 1) \
F(SetPropertyWithReceiver, 5, 1) \

View File

@ -2360,7 +2360,6 @@
'js/typedarray.js',
'js/messages.js',
'js/spread.js',
'js/proxy.js',
'debug/mirrors.js',
'debug/debug.js',
'debug/liveedit.js',

View File

@ -0,0 +1,6 @@
// 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.
const { revoke } = Proxy.revocable({}, {});
assertEquals("", revoke.name);