Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 "use strict";
      6 
      7 // This file relies on the fact that the following declaration has been made
      8 // in runtime.js:
      9 // var $Object = global.Object;
     10 
     11 var $Proxy = new $Object();
     12 
     13 // -------------------------------------------------------------------
     14 
     15 function ProxyCreate(handler, proto) {
     16   if (!IS_SPEC_OBJECT(handler))
     17     throw MakeTypeError("handler_non_object", ["create"])
     18   if (IS_UNDEFINED(proto))
     19     proto = null
     20   else if (!(IS_SPEC_OBJECT(proto) || IS_NULL(proto)))
     21     throw MakeTypeError("proto_non_object", ["create"])
     22   return %CreateJSProxy(handler, proto)
     23 }
     24 
     25 function ProxyCreateFunction(handler, callTrap, constructTrap) {
     26   if (!IS_SPEC_OBJECT(handler))
     27     throw MakeTypeError("handler_non_object", ["create"])
     28   if (!IS_SPEC_FUNCTION(callTrap))
     29     throw MakeTypeError("trap_function_expected", ["createFunction", "call"])
     30   if (IS_UNDEFINED(constructTrap)) {
     31     constructTrap = DerivedConstructTrap(callTrap)
     32   } else if (IS_SPEC_FUNCTION(constructTrap)) {
     33     // Make sure the trap receives 'undefined' as this.
     34     var construct = constructTrap
     35     constructTrap = function() {
     36       return %Apply(construct, UNDEFINED, arguments, 0, %_ArgumentsLength());
     37     }
     38   } else {
     39     throw MakeTypeError("trap_function_expected",
     40                         ["createFunction", "construct"])
     41   }
     42   return %CreateJSFunctionProxy(
     43     handler, callTrap, constructTrap, $Function.prototype)
     44 }
     45 
     46 
     47 // -------------------------------------------------------------------
     48 
     49 function SetUpProxy() {
     50   %CheckIsBootstrapping()
     51 
     52   var global_proxy = %GlobalProxy(global);
     53   global_proxy.Proxy = $Proxy;
     54 
     55   // Set up non-enumerable properties of the Proxy object.
     56   InstallFunctions($Proxy, DONT_ENUM, [
     57     "create", ProxyCreate,
     58     "createFunction", ProxyCreateFunction
     59   ])
     60 }
     61 
     62 SetUpProxy();
     63 
     64 
     65 // -------------------------------------------------------------------
     66 // Proxy Builtins
     67 
     68 function DerivedConstructTrap(callTrap) {
     69   return function() {
     70     var proto = this.prototype
     71     if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype
     72     var obj = { __proto__: proto };
     73     var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength());
     74     return IS_SPEC_OBJECT(result) ? result : obj
     75   }
     76 }
     77 
     78 function DelegateCallAndConstruct(callTrap, constructTrap) {
     79   return function() {
     80     return %Apply(%_IsConstructCall() ? constructTrap : callTrap,
     81                   this, arguments, 0, %_ArgumentsLength())
     82   }
     83 }
     84 
     85 function DerivedGetTrap(receiver, name) {
     86   var desc = this.getPropertyDescriptor(name)
     87   if (IS_UNDEFINED(desc)) { return desc }
     88   if ('value' in desc) {
     89     return desc.value
     90   } else {
     91     if (IS_UNDEFINED(desc.get)) { return desc.get }
     92     // The proposal says: desc.get.call(receiver)
     93     return %_CallFunction(receiver, desc.get)
     94   }
     95 }
     96 
     97 function DerivedSetTrap(receiver, name, val) {
     98   var desc = this.getOwnPropertyDescriptor(name)
     99   if (desc) {
    100     if ('writable' in desc) {
    101       if (desc.writable) {
    102         desc.value = val
    103         this.defineProperty(name, desc)
    104         return true
    105       } else {
    106         return false
    107       }
    108     } else { // accessor
    109       if (desc.set) {
    110         // The proposal says: desc.set.call(receiver, val)
    111         %_CallFunction(receiver, val, desc.set)
    112         return true
    113       } else {
    114         return false
    115       }
    116     }
    117   }
    118   desc = this.getPropertyDescriptor(name)
    119   if (desc) {
    120     if ('writable' in desc) {
    121       if (desc.writable) {
    122         // fall through
    123       } else {
    124         return false
    125       }
    126     } else { // accessor
    127       if (desc.set) {
    128         // The proposal says: desc.set.call(receiver, val)
    129         %_CallFunction(receiver, val, desc.set)
    130         return true
    131       } else {
    132         return false
    133       }
    134     }
    135   }
    136   this.defineProperty(name, {
    137     value: val,
    138     writable: true,
    139     enumerable: true,
    140     configurable: true});
    141   return true;
    142 }
    143 
    144 function DerivedHasTrap(name) {
    145   return !!this.getPropertyDescriptor(name)
    146 }
    147 
    148 function DerivedHasOwnTrap(name) {
    149   return !!this.getOwnPropertyDescriptor(name)
    150 }
    151 
    152 function DerivedKeysTrap() {
    153   var names = this.getOwnPropertyNames()
    154   var enumerableNames = []
    155   for (var i = 0, count = 0; i < names.length; ++i) {
    156     var name = names[i]
    157     if (IS_SYMBOL(name)) continue
    158     var desc = this.getOwnPropertyDescriptor(TO_STRING_INLINE(name))
    159     if (!IS_UNDEFINED(desc) && desc.enumerable) {
    160       enumerableNames[count++] = names[i]
    161     }
    162   }
    163   return enumerableNames
    164 }
    165 
    166 function DerivedEnumerateTrap() {
    167   var names = this.getPropertyNames()
    168   var enumerableNames = []
    169   for (var i = 0, count = 0; i < names.length; ++i) {
    170     var name = names[i]
    171     if (IS_SYMBOL(name)) continue
    172     var desc = this.getPropertyDescriptor(TO_STRING_INLINE(name))
    173     if (!IS_UNDEFINED(desc)) {
    174       if (!desc.configurable) {
    175         throw MakeTypeError("proxy_prop_not_configurable",
    176             [this, "getPropertyDescriptor", name])
    177       }
    178       if (desc.enumerable) enumerableNames[count++] = names[i]
    179     }
    180   }
    181   return enumerableNames
    182 }
    183 
    184 function ProxyEnumerate(proxy) {
    185   var handler = %GetHandler(proxy)
    186   if (IS_UNDEFINED(handler.enumerate)) {
    187     return %Apply(DerivedEnumerateTrap, handler, [], 0, 0)
    188   } else {
    189     return ToNameArray(handler.enumerate(), "enumerate", false)
    190   }
    191 }
    192