Commit 7ceaf727 authored by verwaest's avatar verwaest Committed by Commit bot

[Proxies] Support constructable proxy as new.target (reland)

BUG=v8:1543, v8:3330, v8:3931
LOG=n

Review URL: https://codereview.chromium.org/1481773003

Cr-Commit-Position: refs/heads/master@{#32370}
parent 1779136f
......@@ -1754,10 +1754,9 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r0 : the number of arguments (not including the receiver)
// -- r1 : the constructor to call (checked to be a JSFunction)
// -- r3 : the new target (checked to be a JSFunction)
// -- r3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertFunction(r1);
__ AssertFunction(r3);
// Calling convention for function specific ConstructStubs require
// r2 to contain either an AllocationSite or undefined.
......
......@@ -1740,10 +1740,9 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x0 : the number of arguments (not including the receiver)
// -- x1 : the constructor to call (checked to be a JSFunction)
// -- x3 : the new target (checked to be a JSFunction)
// -- x3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertFunction(x1);
__ AssertFunction(x3);
// Calling convention for function specific ConstructStubs require
// x2 to contain either an AllocationSite or undefined.
......
......@@ -1608,10 +1608,9 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edx : the new target (checked to be a JSFunction)
// -- edx : the new target (checked to be a constructor)
// -- edi : the constructor to call (checked to be a JSFunction)
// -----------------------------------
__ AssertFunction(edx);
__ AssertFunction(edi);
// Calling convention for function specific ConstructStubs require
......
......@@ -1769,10 +1769,9 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the constructor to call (checked to be a JSFunction)
// -- a3 : the new target (checked to be a JSFunction)
// -- a3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertFunction(a1);
__ AssertFunction(a3);
// Calling convention for function specific ConstructStubs require
// a2 to contain either an AllocationSite or undefined.
......
......@@ -1762,10 +1762,9 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a0 : the number of arguments (not including the receiver)
// -- a1 : the constructor to call (checked to be a JSFunction)
// -- a3 : the new target (checked to be a JSFunction)
// -- a3 : the new target (checked to be a constructor)
// -----------------------------------
__ AssertFunction(a1);
__ AssertFunction(a3);
// Calling convention for function specific ConstructStubs require
// a2 to contain either an AllocationSite or undefined.
......
......@@ -4694,6 +4694,51 @@ Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
}
// static
MaybeHandle<Context> JSProxy::GetFunctionRealm(Handle<JSProxy> proxy) {
DCHECK(proxy->map()->is_constructor());
if (JSProxy::IsRevoked(proxy)) {
THROW_NEW_ERROR(proxy->GetIsolate(),
NewTypeError(MessageTemplate::kProxyRevoked), Context);
}
// TODO(verwaest): Get rid of JSFunctionProxies.
Object* target = proxy->IsJSFunctionProxy()
? JSFunctionProxy::cast(*proxy)->construct_trap()
: proxy->target();
return JSReceiver::GetFunctionRealm(handle(JSReceiver::cast(target)));
}
// static
MaybeHandle<Context> JSFunction::GetFunctionRealm(Handle<JSFunction> function) {
DCHECK(function->map()->is_constructor());
return handle(function->context()->native_context());
}
// static
MaybeHandle<Context> JSObject::GetFunctionRealm(Handle<JSObject> object) {
DCHECK(object->map()->is_constructor());
DCHECK(!object->IsJSFunction());
return handle(object->GetCreationContext());
}
// static
MaybeHandle<Context> JSReceiver::GetFunctionRealm(Handle<JSReceiver> receiver) {
if (receiver->IsJSProxy()) {
return JSProxy::GetFunctionRealm(Handle<JSProxy>::cast(receiver));
}
if (receiver->IsJSFunction()) {
return JSFunction::GetFunctionRealm(Handle<JSFunction>::cast(receiver));
}
return JSObject::GetFunctionRealm(Handle<JSObject>::cast(receiver));
}
Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) {
Isolate* isolate = it->isolate();
HandleScope scope(isolate);
......@@ -12222,6 +12267,8 @@ Handle<Map> JSFunction::EnsureDerivedHasInitialMap(
DCHECK(!constructor->shared()->is_generator());
// Fetch or allocate prototype.
// TODO(verwaest): In case of non-instance prototype, use the
// intrinsicDefaultProto instead.
Handle<Object> prototype;
if (new_target->has_instance_prototype()) {
prototype = handle(new_target->instance_prototype(), isolate);
......
......@@ -1800,6 +1800,8 @@ class JSReceiver: public HeapObject {
MUST_USE_RESULT static MaybeHandle<Object> OrdinaryToPrimitive(
Handle<JSReceiver> receiver, OrdinaryToPrimitiveHint hint);
static MaybeHandle<Context> GetFunctionRealm(Handle<JSReceiver> receiver);
// Implementation of [[HasProperty]], ECMA-262 5th edition, section 8.12.6.
MUST_USE_RESULT static Maybe<bool> HasProperty(LookupIterator* it);
MUST_USE_RESULT static inline Maybe<bool> HasProperty(
......@@ -1955,6 +1957,8 @@ class JSObject: public JSReceiver {
// Gets global object properties.
inline GlobalDictionary* global_dictionary();
static MaybeHandle<Context> GetFunctionRealm(Handle<JSObject> object);
// [elements]: The elements (properties with names that are integers).
//
// Elements can be in two general modes: fast and slow. Each mode
......@@ -7201,6 +7205,8 @@ class JSFunction: public JSObject {
inline JSObject* global_proxy();
inline Context* native_context();
static MaybeHandle<Context> GetFunctionRealm(Handle<JSFunction> function);
// [code]: The generated code object for this function. Executed
// when the function is invoked, e.g. foo() or new foo(). See
// [[Call]] and [[Construct]] description in ECMA-262, section
......@@ -9495,6 +9501,8 @@ class JSProxy: public JSReceiver {
// [hash]: The hash code property (undefined if not initialized yet).
DECL_ACCESSORS(hash, Object)
static MaybeHandle<Context> GetFunctionRealm(Handle<JSProxy> proxy);
inline bool has_handler();
DECLARE_CAST(JSProxy)
......
......@@ -1007,25 +1007,55 @@ RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
}
static MaybeHandle<Map> GetDerivedMap(Isolate* isolate,
Handle<JSFunction> constructor,
Handle<JSReceiver> new_target) {
JSFunction::EnsureHasInitialMap(constructor);
DCHECK_NE(JS_FUNCTION_TYPE, constructor->initial_map()->instance_type());
if (new_target->IsJSProxy()) {
Handle<JSProxy> new_target_proxy = Handle<JSProxy>::cast(new_target);
Handle<Object> prototype;
Handle<String> prototype_string = isolate->factory()->prototype_string();
ASSIGN_RETURN_ON_EXCEPTION(
isolate, prototype,
JSReceiver::GetProperty(new_target_proxy, prototype_string), Map);
Handle<Map> constructor_initial_map(constructor->initial_map());
Handle<Map> map = Map::CopyInitialMap(constructor_initial_map);
if (!prototype->IsJSReceiver()) {
Handle<Context> context;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, context, JSProxy::GetFunctionRealm(new_target_proxy), Map);
DCHECK(context->IsNativeContext());
// TODO(verwaest): Use the intrinsicDefaultProto instead.
prototype = handle(context->initial_object_prototype(), isolate);
}
if (map->prototype() != *prototype) {
Map::SetPrototype(map, prototype, FAST_PROTOTYPE);
}
map->SetConstructor(*constructor);
return map;
}
return JSFunction::EnsureDerivedHasInitialMap(
Handle<JSFunction>::cast(new_target), constructor);
}
static Object* Runtime_NewObjectHelper(Isolate* isolate,
Handle<JSFunction> constructor,
Handle<JSReceiver> new_target,
Handle<AllocationSite> site) {
// TODO(verwaest): new_target could be a proxy. Read new.target.prototype in
// that case.
Handle<JSFunction> original_function = Handle<JSFunction>::cast(new_target);
// The function should be compiled for the optimization hints to be
// The constructor should be compiled for the optimization hints to be
// available.
Compiler::Compile(constructor, CLEAR_EXCEPTION);
JSFunction::EnsureHasInitialMap(constructor);
DCHECK_NE(JS_FUNCTION_TYPE, constructor->initial_map()->instance_type());
// TODO(verwaest): original_function could have non-instance-prototype
// (non-JSReceiver), requiring fallback to the intrinsicDefaultProto.
Handle<Map> initial_map =
JSFunction::EnsureDerivedHasInitialMap(original_function, constructor);
Handle<Map> initial_map;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, initial_map, GetDerivedMap(isolate, constructor, new_target));
Handle<JSObject> result =
isolate->factory()->NewJSObjectFromMap(initial_map, NOT_TENURED, site);
......
......@@ -1804,10 +1804,9 @@ void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) {
void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rax : the number of arguments (not including the receiver)
// -- rdx : the new target (checked to be a JSFunction)
// -- rdx : the new target (checked to be a constructor)
// -- rdi : the constructor to call (checked to be a JSFunction)
// -----------------------------------
__ AssertFunction(rdx);
__ AssertFunction(rdi);
// Calling convention for function specific ConstructStubs require
......
// 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.
// Flags: --allow-natives-syntax --harmony-proxies --harmony-reflect
function CreateConstructableProxy(handler) {
return Proxy.createFunction(handler, function() {}, function() {});
}
(function() {
var prototype = { x: 1 };
var log = [];
var proxy = CreateConstructableProxy({
get(k) {
log.push("get trap");
return prototype;
}});
var o = Reflect.construct(Number, [100], proxy);
assertEquals(["get trap"], log);
assertTrue(Object.getPrototypeOf(o) === prototype);
assertEquals(100, Number.prototype.valueOf.call(o));
})();
(function() {
var prototype = { x: 1 };
var log = [];
var proxy = CreateConstructableProxy({
get(k) {
log.push("get trap");
return 10;
}});
var o = Reflect.construct(Number, [100], proxy);
assertEquals(["get trap"], log);
assertTrue(Object.getPrototypeOf(o) === Object.prototype);
assertEquals(100, Number.prototype.valueOf.call(o));
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment