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