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 34var $Proxy = new $Object(); 35 36// ------------------------------------------------------------------- 37 38function 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) || IS_NULL(proto))) 44 throw MakeTypeError("proto_non_object", ["create"]) 45 return %CreateJSProxy(handler, proto) 46} 47 48function 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, UNDEFINED, 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 72function 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 84SetUpProxy(); 85 86 87// ------------------------------------------------------------------- 88// Proxy Builtins 89 90function 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 100function DelegateCallAndConstruct(callTrap, constructTrap) { 101 return function() { 102 return %Apply(%_IsConstructCall() ? constructTrap : callTrap, 103 this, arguments, 0, %_ArgumentsLength()) 104 } 105} 106 107function 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 119function 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 166function DerivedHasTrap(name) { 167 return !!this.getPropertyDescriptor(name) 168} 169 170function DerivedHasOwnTrap(name) { 171 return !!this.getOwnPropertyDescriptor(name) 172} 173 174function 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 188function 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 206function 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