proxy.js 5.77 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
(function(global, utils) {
yangguo's avatar
yangguo committed
6

7 8
"use strict";

yangguo's avatar
yangguo committed
9
%CheckIsBootstrapping();
10

11 12 13
// ----------------------------------------------------------------------------
// Imports

14
var GlobalFunction = global.Function;
yangguo's avatar
yangguo committed
15
var GlobalObject = global.Object;
16
var MakeTypeError;
17 18 19
var ToNameArray;

utils.Import(function(from) {
20
  MakeTypeError = from.MakeTypeError;
21 22 23 24
  ToNameArray = from.ToNameArray;
});

//----------------------------------------------------------------------------
25

26
function ProxyCreate(handler, proto) {
27
  if (!IS_SPEC_OBJECT(handler))
28
    throw MakeTypeError(kProxyHandlerNonObject, "create")
29 30
  if (IS_UNDEFINED(proto))
    proto = null
31
  else if (!(IS_SPEC_OBJECT(proto) || IS_NULL(proto)))
32
    throw MakeTypeError(kProxyProtoNonObject)
33 34
  return %CreateJSProxy(handler, proto)
}
35

36
function ProxyCreateFunction(handler, callTrap, constructTrap) {
37
  if (!IS_SPEC_OBJECT(handler))
38
    throw MakeTypeError(kProxyHandlerNonObject, "createFunction")
39
  if (!IS_CALLABLE(callTrap))
40
    throw MakeTypeError(kProxyTrapFunctionExpected, "call")
41
  if (IS_UNDEFINED(constructTrap)) {
42
    constructTrap = DerivedConstructTrap(callTrap)
43
  } else if (IS_CALLABLE(constructTrap)) {
44 45 46
    // Make sure the trap receives 'undefined' as this.
    var construct = constructTrap
    constructTrap = function() {
47
      return %Apply(construct, UNDEFINED, arguments, 0, %_ArgumentsLength());
48 49
    }
  } else {
50
    throw MakeTypeError(kProxyTrapFunctionExpected, "construct")
51 52
  }
  return %CreateJSFunctionProxy(
53
    handler, callTrap, constructTrap, GlobalFunction.prototype)
54
}
55

56 57
// -------------------------------------------------------------------
// Proxy Builtins
58

59 60 61
function DerivedConstructTrap(callTrap) {
  return function() {
    var proto = this.prototype
62
    if (!IS_SPEC_OBJECT(proto)) proto = GlobalObject.prototype
63
    var obj = { __proto__: proto };
64
    var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength());
65 66 67 68
    return IS_SPEC_OBJECT(result) ? result : obj
  }
}

69 70 71 72 73 74 75
function DelegateCallAndConstruct(callTrap, constructTrap) {
  return function() {
    return %Apply(%_IsConstructCall() ? constructTrap : callTrap,
                  this, arguments, 0, %_ArgumentsLength())
  }
}

76 77
function DerivedGetTrap(receiver, name) {
  var desc = this.getPropertyDescriptor(name)
78
  if (IS_UNDEFINED(desc)) { return desc }
79 80 81
  if ('value' in desc) {
    return desc.value
  } else {
82 83 84
    if (IS_UNDEFINED(desc.get)) { return desc.get }
    // The proposal says: desc.get.call(receiver)
    return %_CallFunction(receiver, desc.get)
85 86
  }
}
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133

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)
        %_CallFunction(receiver, val, desc.set)
        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)
        %_CallFunction(receiver, val, desc.set)
        return true
      } else {
        return false
      }
    }
  }
  this.defineProperty(name, {
    value: val,
    writable: true,
    enumerable: true,
    configurable: true});
  return true;
}
134 135 136 137

function DerivedHasTrap(name) {
  return !!this.getPropertyDescriptor(name)
}
138

139 140 141 142
function DerivedHasOwnTrap(name) {
  return !!this.getOwnPropertyDescriptor(name)
}

143 144 145 146 147
function DerivedKeysTrap() {
  var names = this.getOwnPropertyNames()
  var enumerableNames = []
  for (var i = 0, count = 0; i < names.length; ++i) {
    var name = names[i]
148
    if (IS_SYMBOL(name)) continue
149
    var desc = this.getOwnPropertyDescriptor(TO_STRING(name))
150
    if (!IS_UNDEFINED(desc) && desc.enumerable) {
151 152 153 154 155
      enumerableNames[count++] = names[i]
    }
  }
  return enumerableNames
}
156 157 158 159 160 161

function DerivedEnumerateTrap() {
  var names = this.getPropertyNames()
  var enumerableNames = []
  for (var i = 0, count = 0; i < names.length; ++i) {
    var name = names[i]
162
    if (IS_SYMBOL(name)) continue
163
    var desc = this.getPropertyDescriptor(TO_STRING(name))
164 165
    if (!IS_UNDEFINED(desc)) {
      if (!desc.configurable) {
166 167
        throw MakeTypeError(kProxyPropNotConfigurable,
                            this, name, "getPropertyDescriptor")
168 169
      }
      if (desc.enumerable) enumerableNames[count++] = names[i]
170 171 172 173 174 175 176 177 178 179
    }
  }
  return enumerableNames
}

function ProxyEnumerate(proxy) {
  var handler = %GetHandler(proxy)
  if (IS_UNDEFINED(handler.enumerate)) {
    return %Apply(DerivedEnumerateTrap, handler, [], 0, 0)
  } else {
180
    return ToNameArray(handler.enumerate(), "enumerate", false)
181 182
  }
}
yangguo's avatar
yangguo committed
183 184 185 186 187 188 189

//-------------------------------------------------------------------

var Proxy = new GlobalObject();
%AddNamedProperty(global, "Proxy", Proxy, DONT_ENUM);

//Set up non-enumerable properties of the Proxy object.
190
utils.InstallFunctions(Proxy, DONT_ENUM, [
yangguo's avatar
yangguo committed
191 192 193 194
  "create", ProxyCreate,
  "createFunction", ProxyCreateFunction
])

195 196 197 198 199 200 201 202 203
// -------------------------------------------------------------------
// Exports

utils.Export(function(to) {
  to.ProxyDelegateCallAndConstruct = DelegateCallAndConstruct;
  to.ProxyDerivedHasOwnTrap = DerivedHasOwnTrap;
  to.ProxyDerivedKeysTrap = DerivedKeysTrap;
});

204 205 206 207 208 209
%InstallToContext([
  "derived_get_trap", DerivedGetTrap,
  "derived_has_trap", DerivedHasTrap,
  "derived_set_trap", DerivedSetTrap,
  "proxy_enumerate", ProxyEnumerate,
]);
210

211
})