blob: 3885e408add350acff7d74276a48a28f7eb8cb5c [file] [log] [blame]
// 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;
var GlobalFunction = global.Function;
var GlobalObject = global.Object;
var MakeTypeError;
var ToNameArray;
utils.Import(function(from) {
MakeTypeError = from.MakeTypeError;
ToNameArray = from.ToNameArray;
});
//----------------------------------------------------------------------------
function ProxyCreate(target, handler) {
if (!%_IsConstructCall()) {
throw MakeTypeError(kConstructorNotFunction, "Proxy");
}
return %CreateJSProxy(target, handler);
}
function ProxyCreateFunction(handler, callTrap, constructTrap) {
if (!IS_SPEC_OBJECT(handler))
throw MakeTypeError(kProxyHandlerNonObject, "createFunction")
if (!IS_CALLABLE(callTrap))
throw MakeTypeError(kProxyTrapFunctionExpected, "call")
if (IS_UNDEFINED(constructTrap)) {
constructTrap = DerivedConstructTrap(callTrap)
} else if (IS_CALLABLE(constructTrap)) {
// Make sure the trap receives 'undefined' as this.
var construct = constructTrap
constructTrap = function() {
return %Apply(construct, UNDEFINED, arguments, 0, %_ArgumentsLength());
}
} else {
throw MakeTypeError(kProxyTrapFunctionExpected, "construct")
}
return %CreateJSFunctionProxy(
{}, handler, callTrap, constructTrap, GlobalFunction.prototype)
}
// -------------------------------------------------------------------
// Proxy Builtins
function DerivedConstructTrap(callTrap) {
return function() {
var proto = this.prototype
if (!IS_SPEC_OBJECT(proto)) proto = GlobalObject.prototype
var obj = { __proto__: proto };
var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength());
return IS_SPEC_OBJECT(result) ? result : obj
}
}
function DelegateCallAndConstruct(callTrap, constructTrap) {
return function() {
return %Apply(%_IsConstructCall() ? constructTrap : callTrap,
this, arguments, 0, %_ArgumentsLength())
}
}
function DerivedGetTrap(receiver, name) {
var desc = this.getPropertyDescriptor(name)
if (IS_UNDEFINED(desc)) { return desc }
if ('value' in desc) {
return desc.value
} else {
if (IS_UNDEFINED(desc.get)) { return desc.get }
// The proposal says: desc.get.call(receiver)
return %_Call(desc.get, receiver)
}
}
function DerivedSetTrap(receiver, name, val) {
var desc = this.getOwnPropertyDescriptor(name)
if (desc) {
if ('writable' in desc) {
if (desc.writable) {
desc.value = val
this.defineProperty(name, desc)
return true
} else {
return false
}
} else { // accessor
if (desc.set) {
// The proposal says: desc.set.call(receiver, val)
%_Call(desc.set, receiver, val)
return true
} else {
return false
}
}
}
desc = this.getPropertyDescriptor(name)
if (desc) {
if ('writable' in desc) {
if (desc.writable) {
// fall through
} else {
return false
}
} else { // accessor
if (desc.set) {
// The proposal says: desc.set.call(receiver, val)
%_Call(desc.set, receiver, val)
return true
} else {
return false
}
}
}
this.defineProperty(name, {
value: val,
writable: true,
enumerable: true,
configurable: true});
return true;
}
function DerivedHasTrap(name) {
return !!this.getPropertyDescriptor(name)
}
function DerivedHasOwnTrap(name) {
return !!this.getOwnPropertyDescriptor(name)
}
function DerivedKeysTrap() {
var names = this.getOwnPropertyNames()
var enumerableNames = []
for (var i = 0, count = 0; i < names.length; ++i) {
var name = names[i]
if (IS_SYMBOL(name)) continue
var desc = this.getOwnPropertyDescriptor(TO_STRING(name))
if (!IS_UNDEFINED(desc) && desc.enumerable) {
enumerableNames[count++] = names[i]
}
}
return enumerableNames
}
function DerivedEnumerateTrap() {
var names = this.getPropertyNames()
var enumerableNames = []
for (var i = 0, count = 0; i < names.length; ++i) {
var name = names[i]
if (IS_SYMBOL(name)) continue
var desc = this.getPropertyDescriptor(TO_STRING(name))
if (!IS_UNDEFINED(desc)) {
if (!desc.configurable) {
throw MakeTypeError(kProxyPropNotConfigurable,
this, name, "getPropertyDescriptor")
}
if (desc.enumerable) enumerableNames[count++] = names[i]
}
}
return enumerableNames
}
function ProxyEnumerate(proxy) {
var handler = %GetHandler(proxy)
if (IS_UNDEFINED(handler.enumerate)) {
return %Apply(DerivedEnumerateTrap, handler, [], 0, 0)
} else {
return ToNameArray(handler.enumerate(), "enumerate", false)
}
}
//-------------------------------------------------------------------
%SetCode(GlobalProxy, ProxyCreate);
//Set up non-enumerable properties of the Proxy object.
utils.InstallFunctions(GlobalProxy, DONT_ENUM, [
"createFunction", ProxyCreateFunction
]);
// -------------------------------------------------------------------
// Exports
utils.Export(function(to) {
to.ProxyDelegateCallAndConstruct = DelegateCallAndConstruct;
to.ProxyDerivedHasOwnTrap = DerivedHasOwnTrap;
to.ProxyDerivedKeysTrap = DerivedKeysTrap;
});
%InstallToContext([
"derived_get_trap", DerivedGetTrap,
"derived_has_trap", DerivedHasTrap,
"derived_set_trap", DerivedSetTrap,
"proxy_enumerate", ProxyEnumerate,
]);
})