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