[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:
parent
211d569a2b
commit
ddfbbc5537
1
AUTHORS
1
AUTHORS
@ -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>
|
||||
|
1
BUILD.gn
1
BUILD.gn
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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, \
|
||||
|
@ -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") \
|
||||
|
@ -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)};
|
||||
}
|
||||
);
|
||||
|
||||
})
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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',
|
||||
|
6
test/mjsunit/regress/regress-v8-7245.js
Normal file
6
test/mjsunit/regress/regress-v8-7245.js
Normal 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);
|
Loading…
Reference in New Issue
Block a user