[runtime] [proxy] implement [[Construct]]
LOG=N BUG=v8:1543 Review URL: https://codereview.chromium.org/1509603005 Cr-Commit-Position: refs/heads/master@{#32718}
This commit is contained in:
parent
02320548a5
commit
a2d5641bc4
@ -1749,8 +1749,14 @@ void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -----------------------------------
|
||||
|
||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
// Call into the Runtime for Proxy [[Construct]].
|
||||
__ Push(r1);
|
||||
__ Push(r3);
|
||||
// Include the pushed new_target, constructor and the receiver.
|
||||
__ add(r0, r0, Operand(3));
|
||||
// Tail-call to the runtime.
|
||||
__ JumpToExternalReference(
|
||||
ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
|
||||
}
|
||||
|
||||
|
||||
@ -1771,15 +1777,17 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||
__ CompareObjectType(r1, r4, r5, JS_FUNCTION_TYPE);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
||||
RelocInfo::CODE_TARGET, eq);
|
||||
__ cmp(r5, Operand(JS_PROXY_TYPE));
|
||||
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||
eq);
|
||||
|
||||
// Check if target has a [[Construct]] internal method.
|
||||
__ ldrb(r2, FieldMemOperand(r4, Map::kBitFieldOffset));
|
||||
__ tst(r2, Operand(1 << Map::kIsConstructor));
|
||||
__ b(eq, &non_constructor);
|
||||
|
||||
// Only dispatch to proxies after checking whether they are constructors.
|
||||
__ cmp(r5, Operand(JS_PROXY_TYPE));
|
||||
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||
eq);
|
||||
|
||||
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||
{
|
||||
// Overwrite the original receiver with the (original) target.
|
||||
|
@ -1741,8 +1741,14 @@ void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -----------------------------------
|
||||
|
||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
// Call into the Runtime for Proxy [[Construct]].
|
||||
__ Push(x1);
|
||||
__ Push(x3);
|
||||
// Include the pushed new_target, constructor and the receiver.
|
||||
__ Add(x0, x0, 3);
|
||||
// Tail-call to the runtime.
|
||||
__ JumpToExternalReference(
|
||||
ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
|
||||
}
|
||||
|
||||
|
||||
@ -1763,14 +1769,16 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||
__ CompareObjectType(x1, x4, x5, JS_FUNCTION_TYPE);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
||||
RelocInfo::CODE_TARGET, eq);
|
||||
__ Cmp(x5, JS_PROXY_TYPE);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||
eq);
|
||||
|
||||
// Check if target has a [[Construct]] internal method.
|
||||
__ Ldrb(x2, FieldMemOperand(x4, Map::kBitFieldOffset));
|
||||
__ TestAndBranchIfAllClear(x2, 1 << Map::kIsConstructor, &non_constructor);
|
||||
|
||||
// Only dispatch to proxies after checking whether they are constructors.
|
||||
__ Cmp(x5, JS_PROXY_TYPE);
|
||||
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||
eq);
|
||||
|
||||
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||
{
|
||||
// Overwrite the original receiver with the (original) target.
|
||||
|
@ -1603,13 +1603,21 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
||||
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : the number of arguments (not including the receiver)
|
||||
// -- edi : the constructor to call (checked to be a JSProxy)
|
||||
// -- edx : the new target (either the same as the constructor or
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -- edi : the constructor to call (checked to be a JSProxy)
|
||||
// -----------------------------------
|
||||
|
||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
// Call into the Runtime for Proxy [[Construct]].
|
||||
__ PopReturnAddressTo(ecx);
|
||||
__ Push(edi);
|
||||
__ Push(edx);
|
||||
__ PushReturnAddressFrom(ecx);
|
||||
// Include the pushed new_target, constructor and the receiver.
|
||||
__ add(eax, Immediate(3));
|
||||
// Tail-call to the runtime.
|
||||
__ JumpToExternalReference(
|
||||
ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
|
||||
}
|
||||
|
||||
|
||||
@ -1630,14 +1638,16 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
__ CmpInstanceType(ecx, JS_PROXY_TYPE);
|
||||
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// Check if target has a [[Construct]] internal method.
|
||||
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
|
||||
__ j(zero, &non_constructor, Label::kNear);
|
||||
|
||||
// Only dispatch to proxies after checking whether they are constructors.
|
||||
__ CmpInstanceType(ecx, JS_PROXY_TYPE);
|
||||
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||
{
|
||||
// Overwrite the original receiver with the (original) target.
|
||||
|
@ -208,6 +208,8 @@ class CallSite {
|
||||
T(ProxyTargetNonObject, "Proxy target is non-object") \
|
||||
T(ProxyTargetPropNotConfigurable, \
|
||||
"Proxy target property '%' is not configurable") \
|
||||
T(ProxyTrapConstructMustReturnObject, \
|
||||
"Construct trap must return Object, but got ''%s'.") \
|
||||
T(ProxyTrapFunctionExpected, \
|
||||
"Proxy.createFunction called with non-function for '%' trap") \
|
||||
T(ProxyTrapResultMustInclude, "Trap result must include %.") \
|
||||
|
@ -1761,8 +1761,14 @@ void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -----------------------------------
|
||||
|
||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
// Call into the Runtime for Proxy [[Construct]].
|
||||
__ Push(a1);
|
||||
__ Push(a3);
|
||||
// Include the pushed new_target, constructor and the receiver.
|
||||
__ Addu(a0, a0, Operand(3));
|
||||
// Tail-call to the runtime.
|
||||
__ JumpToExternalReference(
|
||||
ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
|
||||
}
|
||||
|
||||
|
||||
@ -1784,14 +1790,16 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||
__ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
|
||||
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
||||
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
|
||||
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||
eq, t2, Operand(JS_PROXY_TYPE));
|
||||
|
||||
// Check if target has a [[Construct]] internal method.
|
||||
__ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
|
||||
__ And(t2, t2, Operand(1 << Map::kIsCallable));
|
||||
__ Branch(&non_constructor, eq, t2, Operand(zero_reg));
|
||||
|
||||
// Only dispatch to proxies after checking whether they are constructors.
|
||||
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||
eq, t2, Operand(JS_PROXY_TYPE));
|
||||
|
||||
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||
{
|
||||
// Overwrite the original receiver with the (original) target.
|
||||
|
@ -1752,8 +1752,14 @@ void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -----------------------------------
|
||||
|
||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
// Call into the Runtime for Proxy [[Construct]].
|
||||
__ Push(a1);
|
||||
__ Push(a3);
|
||||
// Include the pushed new_target, constructor and the receiver.
|
||||
__ Daddu(a0, a0, Operand(3));
|
||||
// Tail-call to the runtime.
|
||||
__ JumpToExternalReference(
|
||||
ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
|
||||
}
|
||||
|
||||
|
||||
@ -1775,14 +1781,16 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||
__ lbu(t2, FieldMemOperand(t1, Map::kInstanceTypeOffset));
|
||||
__ Jump(masm->isolate()->builtins()->ConstructFunction(),
|
||||
RelocInfo::CODE_TARGET, eq, t2, Operand(JS_FUNCTION_TYPE));
|
||||
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||
eq, t2, Operand(JS_PROXY_TYPE));
|
||||
|
||||
// Check if target has a [[Construct]] internal method.
|
||||
__ lbu(t2, FieldMemOperand(t1, Map::kBitFieldOffset));
|
||||
__ And(t2, t2, Operand(1 << Map::kIsCallable));
|
||||
__ Branch(&non_constructor, eq, t2, Operand(zero_reg));
|
||||
|
||||
// Only dispatch to proxies after checking whether they are constructors.
|
||||
__ Jump(masm->isolate()->builtins()->ConstructProxy(), RelocInfo::CODE_TARGET,
|
||||
eq, t2, Operand(JS_PROXY_TYPE));
|
||||
|
||||
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||
{
|
||||
// Overwrite the original receiver with the (original) target.
|
||||
|
@ -1764,8 +1764,14 @@ void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -----------------------------------
|
||||
|
||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
// Call into the Runtime for Proxy [[Construct]].
|
||||
__ Push(r4);
|
||||
__ Push(r6);
|
||||
// Include the pushed new_target, constructor and the receiver.
|
||||
__ addi(r3, r3, Operand(3));
|
||||
// Tail-call to the runtime.
|
||||
__ JumpToExternalReference(
|
||||
ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,6 +73,75 @@ RUNTIME_FUNCTION(Runtime_JSProxyCall) {
|
||||
}
|
||||
|
||||
|
||||
// 9.5.14 [[Construct]] (argumentsList, newTarget)
|
||||
RUNTIME_FUNCTION(Runtime_JSProxyConstruct) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_LE(3, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, args.length() - 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, new_target, args.length() - 1);
|
||||
Handle<String> trap_name = isolate->factory()->construct_string();
|
||||
|
||||
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
|
||||
Handle<Object> handler(proxy->handler(), isolate);
|
||||
// 2. If handler is null, throw a TypeError exception.
|
||||
if (proxy->IsRevoked()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
|
||||
}
|
||||
// 3. Assert: Type(handler) is Object.
|
||||
DCHECK(handler->IsJSReceiver());
|
||||
// 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
|
||||
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
|
||||
// 5. Let trap be ? GetMethod(handler, "construct").
|
||||
Handle<Object> trap;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, trap,
|
||||
Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name));
|
||||
// 6. If trap is undefined, then
|
||||
int const arguments_length = args.length() - 3;
|
||||
if (trap->IsUndefined()) {
|
||||
// 6.a. Assert: target has a [[Construct]] internal method.
|
||||
DCHECK(target->IsConstructor());
|
||||
// 6.b. Return Construct(target, argumentsList, newTarget).
|
||||
ScopedVector<Handle<Object>> argv(arguments_length);
|
||||
for (int i = 0; i < arguments_length; ++i) {
|
||||
argv[i] = args.at<Object>(i + 1);
|
||||
}
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, Execution::New(isolate, target, new_target,
|
||||
arguments_length, argv.start()));
|
||||
return *result;
|
||||
}
|
||||
// 7. Let argArray be CreateArrayFromList(argumentsList).
|
||||
Handle<JSArray> arg_array = isolate->factory()->NewJSArray(
|
||||
FAST_ELEMENTS, arguments_length, arguments_length);
|
||||
ElementsAccessor* accessor = arg_array->GetElementsAccessor();
|
||||
{
|
||||
DisallowHeapAllocation no_gc;
|
||||
FixedArrayBase* elements = arg_array->elements();
|
||||
for (int i = 0; i < arguments_length; i++) {
|
||||
accessor->Set(elements, i, args[i + 1]);
|
||||
}
|
||||
}
|
||||
// 8. Let newObj be ? Call(trap, handler, «target, argArray, newTarget »).
|
||||
Handle<Object> new_object;
|
||||
Handle<Object> trap_args[] = {target, arg_array, new_target};
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, new_object,
|
||||
Execution::Call(isolate, trap, handler, arraysize(trap_args), trap_args));
|
||||
// 9. If Type(newObj) is not Object, throw a TypeError exception.
|
||||
if (!new_object->IsJSReceiver()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate,
|
||||
NewTypeError(MessageTemplate::kProxyTrapConstructMustReturnObject,
|
||||
new_object));
|
||||
}
|
||||
// 10. Return newObj.
|
||||
return *new_object;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_IsJSProxy) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
|
@ -542,6 +542,7 @@ namespace internal {
|
||||
#define FOR_EACH_INTRINSIC_PROXY(F) \
|
||||
F(IsJSProxy, 1, 1) \
|
||||
F(JSProxyCall, -1 /* >= 2 */, 1) \
|
||||
F(JSProxyConstruct, -1 /* >= 3 */, 1) \
|
||||
F(GetHandler, 1, 1) \
|
||||
F(RevokeProxy, 1, 1)
|
||||
|
||||
|
@ -1807,13 +1807,20 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
||||
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : the number of arguments (not including the receiver)
|
||||
// -- rdi : the constructor to call (checked to be a JSProxy)
|
||||
// -- rdx : the new target (either the same as the constructor or
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -- rdi : the constructor to call (checked to be a JSProxy)
|
||||
// -----------------------------------
|
||||
|
||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
// Call into the Runtime for Proxy [[Construct]].
|
||||
__ PopReturnAddressTo(kScratchRegister);
|
||||
__ Push(rdi);
|
||||
__ Push(rdx);
|
||||
__ PushReturnAddressFrom(kScratchRegister);
|
||||
// Include the pushed new_target, constructor and the receiver.
|
||||
__ addp(rax, Immediate(3));
|
||||
__ JumpToExternalReference(
|
||||
ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()), 1);
|
||||
}
|
||||
|
||||
|
||||
@ -1835,15 +1842,17 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
__ CmpInstanceType(rcx, JS_PROXY_TYPE);
|
||||
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// Check if target has a [[Construct]] internal method.
|
||||
__ testb(FieldOperand(rcx, Map::kBitFieldOffset),
|
||||
Immediate(1 << Map::kIsConstructor));
|
||||
__ j(zero, &non_constructor, Label::kNear);
|
||||
|
||||
// Only dispatch to proxies after checking whether they are constructors.
|
||||
__ CmpInstanceType(rcx, JS_PROXY_TYPE);
|
||||
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||
{
|
||||
// Overwrite the original receiver with the (original) target.
|
||||
|
@ -1603,13 +1603,21 @@ void Builtins::Generate_ConstructFunction(MacroAssembler* masm) {
|
||||
void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : the number of arguments (not including the receiver)
|
||||
// -- edi : the constructor to call (checked to be a JSProxy)
|
||||
// -- edx : the new target (either the same as the constructor or
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -- edi : the constructor to call (checked to be a JSProxy)
|
||||
// -----------------------------------
|
||||
|
||||
// TODO(neis): This doesn't match the ES6 spec for [[Construct]] on proxies.
|
||||
__ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
|
||||
// Call into the Runtime for Proxy [[Construct]].
|
||||
__ PopReturnAddressTo(ecx);
|
||||
__ Push(edi);
|
||||
__ Push(edx);
|
||||
__ PushReturnAddressFrom(ecx);
|
||||
// Include the pushed new_target, constructor and the receiver.
|
||||
__ add(eax, Immediate(3));
|
||||
// Tail-call to the runtime.
|
||||
__ JumpToExternalReference(
|
||||
ExternalReference(Runtime::kJSProxyConstruct, masm->isolate()));
|
||||
}
|
||||
|
||||
|
||||
@ -1617,9 +1625,9 @@ void Builtins::Generate_ConstructProxy(MacroAssembler* masm) {
|
||||
void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : the number of arguments (not including the receiver)
|
||||
// -- edi : the constructor to call (can be any Object)
|
||||
// -- edx : the new target (either the same as the constructor or
|
||||
// the JSFunction on which new was invoked initially)
|
||||
// -- edi : the constructor to call (can be any Object)
|
||||
// -----------------------------------
|
||||
|
||||
// Check if target is a Smi.
|
||||
@ -1630,14 +1638,16 @@ void Builtins::Generate_Construct(MacroAssembler* masm) {
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx);
|
||||
__ j(equal, masm->isolate()->builtins()->ConstructFunction(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
__ CmpInstanceType(ecx, JS_PROXY_TYPE);
|
||||
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// Check if target has a [[Construct]] internal method.
|
||||
__ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor);
|
||||
__ j(zero, &non_constructor, Label::kNear);
|
||||
|
||||
// Only dispatch to proxies after checking whether they are constructors.
|
||||
__ CmpInstanceType(ecx, JS_PROXY_TYPE);
|
||||
__ j(equal, masm->isolate()->builtins()->ConstructProxy(),
|
||||
RelocInfo::CODE_TARGET);
|
||||
|
||||
// Called Construct on an exotic Object with a [[Construct]] internal method.
|
||||
{
|
||||
// Overwrite the original receiver with the (original) target.
|
||||
|
@ -5,7 +5,7 @@
|
||||
// Flags: --allow-natives-syntax --harmony-proxies --harmony-reflect
|
||||
|
||||
function CreateConstructableProxy(handler) {
|
||||
return Proxy.createFunction(handler, function() {}, function() {});
|
||||
return new Proxy(function(){}, handler);
|
||||
}
|
||||
|
||||
(function() {
|
||||
|
158
test/mjsunit/harmony/proxies-construct.js
Normal file
158
test/mjsunit/harmony/proxies-construct.js
Normal file
@ -0,0 +1,158 @@
|
||||
// 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: --harmony-proxies --harmony-reflect
|
||||
|
||||
(function testNonConstructable() {
|
||||
var proxy = new Proxy({},{});
|
||||
assertThrows(function(){ new proxy() }, TypeError);
|
||||
|
||||
var proxy2 = new Proxy(proxy, {});
|
||||
assertThrows(function(){ proxy2() }, TypeError);
|
||||
})();
|
||||
|
||||
(function testFailingConstructRevoked() {
|
||||
var pair = Proxy.revocable(Array, {});
|
||||
var instance = new pair.proxy();
|
||||
pair.revoke();
|
||||
assertThrows(function(){ new pair.proxy() }, TypeError);
|
||||
})();
|
||||
|
||||
(function testFailingGetTrap() {
|
||||
var handler = {
|
||||
get() {
|
||||
throw TypeError();
|
||||
}
|
||||
}
|
||||
var proxy = new Proxy({},{});
|
||||
var proxy2 = new Proxy({}, proxy);
|
||||
assertThrows(function(){ new proxy2() }, TypeError);
|
||||
})();
|
||||
|
||||
(function testConstructFallback() {
|
||||
var called = false;
|
||||
function Target() {
|
||||
called = true;
|
||||
this.property1 = 'value1';
|
||||
};
|
||||
Target.prototype = {};
|
||||
var proxy = new Proxy(Target, {});
|
||||
|
||||
assertFalse(called);
|
||||
var instance = new proxy();
|
||||
assertTrue(called);
|
||||
assertEquals('value1', instance.property1);
|
||||
assertSame(Target.prototype, Reflect.getPrototypeOf(instance));
|
||||
|
||||
var proxy2 = new Proxy(proxy, {});
|
||||
called = false;
|
||||
var instance2 = new proxy2();
|
||||
assertTrue(called);
|
||||
assertEquals('value1', instance2.property1);
|
||||
assertSame(Target.prototype, Reflect.getPrototypeOf(instance));
|
||||
})();
|
||||
|
||||
(function testConstructTrapDirectReturn() {
|
||||
function Target(a, b) {
|
||||
this.sum = a + b;
|
||||
};
|
||||
var handler = {
|
||||
construct(t, c, args) {
|
||||
return { sum: 42 };
|
||||
}
|
||||
};
|
||||
var proxy = new Proxy(Target, handler);
|
||||
assertEquals(42, (new proxy(1, 2)).sum);
|
||||
})();
|
||||
|
||||
(function testConstructTrap() {
|
||||
function Target(arg1, arg2) {
|
||||
this.arg1 = arg1;
|
||||
this.arg2 = arg2;
|
||||
}
|
||||
var seen_target, seen_arguments, seen_new_target;
|
||||
var handler = {
|
||||
construct(target, args, new_target) {
|
||||
seen_target = target;
|
||||
seen_arguments = args;
|
||||
seen_new_target = new_target;
|
||||
return Reflect.construct(target, args, new_target);
|
||||
}
|
||||
}
|
||||
var proxy = new Proxy(Target, handler);
|
||||
var instance = new proxy('a', 'b');
|
||||
assertEquals(Target, seen_target);
|
||||
assertEquals(['a','b'], seen_arguments);
|
||||
assertEquals(proxy, seen_new_target);
|
||||
assertEquals('a', instance.arg1);
|
||||
assertEquals('b', instance.arg2);
|
||||
|
||||
var instance2 = Reflect.construct(proxy, ['a1', 'b1'], Array);
|
||||
assertEquals(Target, seen_target);
|
||||
assertEquals(['a1', 'b1'], seen_arguments);
|
||||
assertEquals(Array, seen_new_target);
|
||||
assertEquals('a1', instance2.arg1);
|
||||
assertEquals('b1', instance2.arg2);
|
||||
})();
|
||||
|
||||
(function testConstructCrossRealm() {
|
||||
var realm1 = Realm.create();
|
||||
var handler = {
|
||||
construct(target, args, new_target) {
|
||||
return args;
|
||||
}
|
||||
};
|
||||
var OtherProxy = Realm.eval(realm1, "Proxy");
|
||||
var otherArrayPrototype = Realm.eval(realm1, 'Array.prototype');
|
||||
|
||||
// Proxy and handler are from this realm.
|
||||
var proxy = new Proxy(Array, handler);
|
||||
var result = new proxy();
|
||||
assertSame(Array.prototype, Reflect.getPrototypeOf(result));
|
||||
|
||||
// Proxy is from this realm, handler is from realm1.
|
||||
var otherProxy = new OtherProxy(Array, handler);
|
||||
var otherResult = new otherProxy();
|
||||
assertSame(Array.prototype, Reflect.getPrototypeOf(otherResult));
|
||||
|
||||
// Proxy and handler are from realm1.
|
||||
var otherProxy2 = Realm.eval(realm1, 'new Proxy('+
|
||||
'Array, { construct(target, args, new_target) { return args }} )');
|
||||
var otherResult2 = new otherProxy2();
|
||||
assertSame(Array.prototype, Reflect.getPrototypeOf(otherResult2));
|
||||
})();
|
||||
|
||||
(function testReflectConstructCrossReal() {
|
||||
var realm1 = Realm.create();
|
||||
var realm2 = Realm.create();
|
||||
var realm3 = Realm.create();
|
||||
var realm4 = Realm.create();
|
||||
|
||||
var argsRealm1 = Realm.eval(realm1, '[]');
|
||||
var ProxyRealm2 = Realm.eval(realm2, 'Proxy');
|
||||
var constructorRealm3 = Realm.eval(realm3, '(function(){})');
|
||||
var handlerRealm4 = Realm.eval(realm4,
|
||||
'({ construct(target, args, new_target) {return args} })');
|
||||
|
||||
var proxy = new ProxyRealm2(constructorRealm3, handlerRealm4);
|
||||
|
||||
// Check that the arguments array returned by handlerRealm4 is created in the
|
||||
// realm of the Reflect.construct function.
|
||||
var result = Reflect.construct(proxy, argsRealm1);
|
||||
assertSame(Array.prototype, Reflect.getPrototypeOf(result));
|
||||
|
||||
var ReflectConstructRealm1 = Realm.eval(realm1, 'Reflect.construct');
|
||||
var result2 = ReflectConstructRealm1(proxy, argsRealm1);
|
||||
assertSame(Realm.eval(realm1, 'Array.prototype'),
|
||||
Reflect.getPrototypeOf(result2));
|
||||
|
||||
var result3 = ReflectConstructRealm1(proxy, []);
|
||||
assertSame(Realm.eval(realm1, 'Array.prototype'),
|
||||
Reflect.getPrototypeOf(result3));
|
||||
|
||||
var ReflectConstructRealm2 = Realm.eval(realm2, 'Reflect.construct');
|
||||
var result4 = ReflectConstructRealm2(proxy, argsRealm1);
|
||||
assertSame(Realm.eval(realm2, 'Array.prototype'),
|
||||
Reflect.getPrototypeOf(result4));
|
||||
})();
|
@ -87,7 +87,6 @@
|
||||
|
||||
# Proxy tests rely on non ES6 version of Proxies
|
||||
# TODO(neis,cbruni): figure out which Proxy tests can be reused
|
||||
'es6/classes-proxy' : [SKIP],
|
||||
'es6/regress/regress-cr493566': [SKIP],
|
||||
'for-in-opt': [SKIP],
|
||||
'harmony/proxies-example-membrane': [SKIP],
|
||||
|
Loading…
Reference in New Issue
Block a user