Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 "use strict";
     29 
     30 // This file relies on the fact that the following declaration has been made
     31 // in runtime.js:
     32 // var $Object = global.Object;
     33 
     34 var $Proxy = new $Object();
     35 
     36 // -------------------------------------------------------------------
     37 
     38 function ProxyCreate(handler, proto) {
     39   if (!IS_SPEC_OBJECT(handler))
     40     throw MakeTypeError("handler_non_object", ["create"])
     41   if (IS_UNDEFINED(proto))
     42     proto = null
     43   else if (!(IS_SPEC_OBJECT(proto) || proto === null))
     44     throw MakeTypeError("proto_non_object", ["create"])
     45   return %CreateJSProxy(handler, proto)
     46 }
     47 
     48 function ProxyCreateFunction(handler, callTrap, constructTrap) {
     49   if (!IS_SPEC_OBJECT(handler))
     50     throw MakeTypeError("handler_non_object", ["create"])
     51   if (!IS_SPEC_FUNCTION(callTrap))
     52     throw MakeTypeError("trap_function_expected", ["createFunction", "call"])
     53   if (IS_UNDEFINED(constructTrap)) {
     54     constructTrap = DerivedConstructTrap(callTrap)
     55   } else if (IS_SPEC_FUNCTION(constructTrap)) {
     56     // Make sure the trap receives 'undefined' as this.
     57     var construct = constructTrap
     58     constructTrap = function() {
     59       return %Apply(construct, void 0, arguments, 0, %_ArgumentsLength());
     60     }
     61   } else {
     62     throw MakeTypeError("trap_function_expected",
     63                         ["createFunction", "construct"])
     64   }
     65   return %CreateJSFunctionProxy(
     66     handler, callTrap, constructTrap, $Function.prototype)
     67 }
     68 
     69 
     70 // -------------------------------------------------------------------
     71 
     72 function SetUpProxy() {
     73   %CheckIsBootstrapping()
     74 
     75   global.Proxy = $Proxy;
     76 
     77   // Set up non-enumerable properties of the Proxy object.
     78   InstallFunctions($Proxy, DONT_ENUM, [
     79     "create", ProxyCreate,
     80     "createFunction", ProxyCreateFunction
     81   ])
     82 }
     83 
     84 SetUpProxy();
     85 
     86 
     87 // -------------------------------------------------------------------
     88 // Proxy Builtins
     89 
     90 function DerivedConstructTrap(callTrap) {
     91   return function() {
     92     var proto = this.prototype
     93     if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype
     94     var obj = { __proto__: proto };
     95     var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength());
     96     return IS_SPEC_OBJECT(result) ? result : obj
     97   }
     98 }
     99 
    100 function DelegateCallAndConstruct(callTrap, constructTrap) {
    101   return function() {
    102     return %Apply(%_IsConstructCall() ? constructTrap : callTrap,
    103                   this, arguments, 0, %_ArgumentsLength())
    104   }
    105 }
    106 
    107 function DerivedGetTrap(receiver, name) {
    108   var desc = this.getPropertyDescriptor(name)
    109   if (IS_UNDEFINED(desc)) { return desc }
    110   if ('value' in desc) {
    111     return desc.value
    112   } else {
    113     if (IS_UNDEFINED(desc.get)) { return desc.get }
    114     // The proposal says: desc.get.call(receiver)
    115     return %_CallFunction(receiver, desc.get)
    116   }
    117 }
    118 
    119 function DerivedSetTrap(receiver, name, val) {
    120   var desc = this.getOwnPropertyDescriptor(name)
    121   if (desc) {
    122     if ('writable' in desc) {
    123       if (desc.writable) {
    124         desc.value = val
    125         this.defineProperty(name, desc)
    126         return true
    127       } else {
    128         return false
    129       }
    130     } else { // accessor
    131       if (desc.set) {
    132         // The proposal says: desc.set.call(receiver, val)
    133         %_CallFunction(receiver, val, desc.set)
    134         return true
    135       } else {
    136         return false
    137       }
    138     }
    139   }
    140   desc = this.getPropertyDescriptor(name)
    141   if (desc) {
    142     if ('writable' in desc) {
    143       if (desc.writable) {
    144         // fall through
    145       } else {
    146         return false
    147       }
    148     } else { // accessor
    149       if (desc.set) {
    150         // The proposal says: desc.set.call(receiver, val)
    151         %_CallFunction(receiver, val, desc.set)
    152         return true
    153       } else {
    154         return false
    155       }
    156     }
    157   }
    158   this.defineProperty(name, {
    159     value: val,
    160     writable: true,
    161     enumerable: true,
    162     configurable: true});
    163   return true;
    164 }
    165 
    166 function DerivedHasTrap(name) {
    167   return !!this.getPropertyDescriptor(name)
    168 }
    169 
    170 function DerivedHasOwnTrap(name) {
    171   return !!this.getOwnPropertyDescriptor(name)
    172 }
    173 
    174 function DerivedKeysTrap() {
    175   var names = this.getOwnPropertyNames()
    176   var enumerableNames = []
    177   for (var i = 0, count = 0; i < names.length; ++i) {
    178     var name = names[i]
    179     if (IS_SYMBOL(name)) continue
    180     var desc = this.getOwnPropertyDescriptor(TO_STRING_INLINE(name))
    181     if (!IS_UNDEFINED(desc) && desc.enumerable) {
    182       enumerableNames[count++] = names[i]
    183     }
    184   }
    185   return enumerableNames
    186 }
    187 
    188 function DerivedEnumerateTrap() {
    189   var names = this.getPropertyNames()
    190   var enumerableNames = []
    191   for (var i = 0, count = 0; i < names.length; ++i) {
    192     var name = names[i]
    193     if (IS_SYMBOL(name)) continue
    194     var desc = this.getPropertyDescriptor(TO_STRING_INLINE(name))
    195     if (!IS_UNDEFINED(desc)) {
    196       if (!desc.configurable) {
    197         throw MakeTypeError("proxy_prop_not_configurable",
    198             [this, "getPropertyDescriptor", name])
    199       }
    200       if (desc.enumerable) enumerableNames[count++] = names[i]
    201     }
    202   }
    203   return enumerableNames
    204 }
    205 
    206 function ProxyEnumerate(proxy) {
    207   var handler = %GetHandler(proxy)
    208   if (IS_UNDEFINED(handler.enumerate)) {
    209     return %Apply(DerivedEnumerateTrap, handler, [], 0, 0)
    210   } else {
    211     return ToNameArray(handler.enumerate(), "enumerate", false)
    212   }
    213 }
    214