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 global.Proxy = new $Object(); 31 32 var $Proxy = global.Proxy 33 34 $Proxy.create = function(handler, proto) { 35 if (!IS_SPEC_OBJECT(handler)) 36 throw MakeTypeError("handler_non_object", ["create"]) 37 if (IS_UNDEFINED(proto)) 38 proto = null 39 else if (!(IS_SPEC_OBJECT(proto) || proto === null)) 40 throw MakeTypeError("proto_non_object", ["create"]) 41 return %CreateJSProxy(handler, proto) 42 } 43 44 $Proxy.createFunction = function(handler, callTrap, constructTrap) { 45 if (!IS_SPEC_OBJECT(handler)) 46 throw MakeTypeError("handler_non_object", ["create"]) 47 if (!IS_SPEC_FUNCTION(callTrap)) 48 throw MakeTypeError("trap_function_expected", ["createFunction", "call"]) 49 if (IS_UNDEFINED(constructTrap)) { 50 constructTrap = DerivedConstructTrap(callTrap) 51 } else if (IS_SPEC_FUNCTION(constructTrap)) { 52 // Make sure the trap receives 'undefined' as this. 53 var construct = constructTrap 54 constructTrap = function() { 55 return %Apply(construct, void 0, arguments, 0, %_ArgumentsLength()); 56 } 57 } else { 58 throw MakeTypeError("trap_function_expected", 59 ["createFunction", "construct"]) 60 } 61 return %CreateJSFunctionProxy( 62 handler, callTrap, constructTrap, $Function.prototype) 63 } 64 65 66 67 //////////////////////////////////////////////////////////////////////////////// 68 // Builtins 69 //////////////////////////////////////////////////////////////////////////////// 70 71 function DerivedConstructTrap(callTrap) { 72 return function() { 73 var proto = this.prototype 74 if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype 75 var obj = new $Object() 76 obj.__proto__ = proto 77 var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength()); 78 return IS_SPEC_OBJECT(result) ? result : obj 79 } 80 } 81 82 function DelegateCallAndConstruct(callTrap, constructTrap) { 83 return function() { 84 return %Apply(%_IsConstructCall() ? constructTrap : callTrap, 85 this, arguments, 0, %_ArgumentsLength()) 86 } 87 } 88 89 function DerivedGetTrap(receiver, name) { 90 var desc = this.getPropertyDescriptor(name) 91 if (IS_UNDEFINED(desc)) { return desc } 92 if ('value' in desc) { 93 return desc.value 94 } else { 95 if (IS_UNDEFINED(desc.get)) { return desc.get } 96 // The proposal says: desc.get.call(receiver) 97 return %_CallFunction(receiver, desc.get) 98 } 99 } 100 101 function DerivedSetTrap(receiver, name, val) { 102 var desc = this.getOwnPropertyDescriptor(name) 103 if (desc) { 104 if ('writable' in desc) { 105 if (desc.writable) { 106 desc.value = val 107 this.defineProperty(name, desc) 108 return true 109 } else { 110 return false 111 } 112 } else { // accessor 113 if (desc.set) { 114 // The proposal says: desc.set.call(receiver, val) 115 %_CallFunction(receiver, val, desc.set) 116 return true 117 } else { 118 return false 119 } 120 } 121 } 122 desc = this.getPropertyDescriptor(name) 123 if (desc) { 124 if ('writable' in desc) { 125 if (desc.writable) { 126 // fall through 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 this.defineProperty(name, { 141 value: val, 142 writable: true, 143 enumerable: true, 144 configurable: true}); 145 return true; 146 } 147 148 function DerivedHasTrap(name) { 149 return !!this.getPropertyDescriptor(name) 150 } 151 152 function DerivedHasOwnTrap(name) { 153 return !!this.getOwnPropertyDescriptor(name) 154 } 155 156 function DerivedKeysTrap() { 157 var names = this.getOwnPropertyNames() 158 var enumerableNames = [] 159 for (var i = 0, count = 0; i < names.length; ++i) { 160 var name = names[i] 161 var desc = this.getOwnPropertyDescriptor(TO_STRING_INLINE(name)) 162 if (!IS_UNDEFINED(desc) && desc.enumerable) { 163 enumerableNames[count++] = names[i] 164 } 165 } 166 return enumerableNames 167 } 168 169 function DerivedEnumerateTrap() { 170 var names = this.getPropertyNames() 171 var enumerableNames = [] 172 for (var i = 0, count = 0; i < names.length; ++i) { 173 var name = names[i] 174 var desc = this.getPropertyDescriptor(TO_STRING_INLINE(name)) 175 if (!IS_UNDEFINED(desc) && desc.enumerable) { 176 enumerableNames[count++] = names[i] 177 } 178 } 179 return enumerableNames 180 } 181 182 function ProxyEnumerate(proxy) { 183 var handler = %GetHandler(proxy) 184 if (IS_UNDEFINED(handler.enumerate)) { 185 return %Apply(DerivedEnumerateTrap, handler, [], 0, 0) 186 } else { 187 return ToStringArray(handler.enumerate(), "enumerate") 188 } 189 } 190