1160a7b0747492f3f735353d9582521f3314bf4dfdanno@chromium.org// Copyright 2011 the V8 project authors. All rights reserved.
23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// Use of this source code is governed by a BSD-style license that can be
33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// found in the LICENSE file.
4160a7b0747492f3f735353d9582521f3314bf4dfdanno@chromium.org
5f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.org"use strict";
6f7a588466d1e61e14fec951e5f10c7cec501b3b4jkummerow@chromium.org
7e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// This file relies on the fact that the following declaration has been made
8e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// in runtime.js:
9e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// var $Object = global.Object;
107304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org
11e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.orgvar $Proxy = new $Object();
12e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org
13e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// -------------------------------------------------------------------
147304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org
1572204d59e7fb1b8a0e9012e1fac5ef160351e8e4danno@chromium.orgfunction ProxyCreate(handler, proto) {
16d6076d96a1411932548838e5960b594564264010erik.corry@gmail.com  if (!IS_SPEC_OBJECT(handler))
17d6076d96a1411932548838e5960b594564264010erik.corry@gmail.com    throw MakeTypeError("handler_non_object", ["create"])
18394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  if (IS_UNDEFINED(proto))
19394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    proto = null
20690083842e7c67a362017dae50909d4bb0b2a9c2mstarzinger@chromium.org  else if (!(IS_SPEC_OBJECT(proto) || IS_NULL(proto)))
21394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    throw MakeTypeError("proto_non_object", ["create"])
227304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org  return %CreateJSProxy(handler, proto)
237304bcac06a6a63b9f3dcebac2eeceada87ca146vegorov@chromium.org}
24ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org
2572204d59e7fb1b8a0e9012e1fac5ef160351e8e4danno@chromium.orgfunction ProxyCreateFunction(handler, callTrap, constructTrap) {
2634e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  if (!IS_SPEC_OBJECT(handler))
2734e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org    throw MakeTypeError("handler_non_object", ["create"])
2834e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  if (!IS_SPEC_FUNCTION(callTrap))
2934e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org    throw MakeTypeError("trap_function_expected", ["createFunction", "call"])
3034e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  if (IS_UNDEFINED(constructTrap)) {
31394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    constructTrap = DerivedConstructTrap(callTrap)
32c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com  } else if (IS_SPEC_FUNCTION(constructTrap)) {
33394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    // Make sure the trap receives 'undefined' as this.
34394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    var construct = constructTrap
35394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    constructTrap = function() {
36690083842e7c67a362017dae50909d4bb0b2a9c2mstarzinger@chromium.org      return %Apply(construct, UNDEFINED, arguments, 0, %_ArgumentsLength());
37c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com    }
38c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com  } else {
3934e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org    throw MakeTypeError("trap_function_expected",
4034e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org                        ["createFunction", "construct"])
4134e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  }
4234e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  return %CreateJSFunctionProxy(
43394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    handler, callTrap, constructTrap, $Function.prototype)
4434e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org}
45ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org
46e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org
47e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// -------------------------------------------------------------------
48e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org
49e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.orgfunction SetUpProxy() {
50e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org  %CheckIsBootstrapping()
51e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org
5258a725587734a6889c689668fd01f0157ed749a6machenbach@chromium.org  var global_proxy = %GlobalProxy(global);
5358a725587734a6889c689668fd01f0157ed749a6machenbach@chromium.org  global_proxy.Proxy = $Proxy;
54e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org
55e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org  // Set up non-enumerable properties of the Proxy object.
56e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org  InstallFunctions($Proxy, DONT_ENUM, [
57e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org    "create", ProxyCreate,
58e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org    "createFunction", ProxyCreateFunction
59e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org  ])
60e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org}
61e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org
62e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.orgSetUpProxy();
63ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org
64ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org
65e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// -------------------------------------------------------------------
66e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// Proxy Builtins
67ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org
68c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.comfunction DerivedConstructTrap(callTrap) {
69c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com  return function() {
70c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com    var proto = this.prototype
71c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com    if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype
72750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org    var obj = { __proto__: proto };
73c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com    var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength());
74c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com    return IS_SPEC_OBJECT(result) ? result : obj
75c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com  }
76c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com}
77c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com
7834e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.orgfunction DelegateCallAndConstruct(callTrap, constructTrap) {
7934e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  return function() {
8034e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org    return %Apply(%_IsConstructCall() ? constructTrap : callTrap,
8134e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org                  this, arguments, 0, %_ArgumentsLength())
8234e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org  }
8334e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org}
8434e60787ea1e76f3ee49e859f71f036170c21f0elrn@chromium.org
85ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.orgfunction DerivedGetTrap(receiver, name) {
86ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org  var desc = this.getPropertyDescriptor(name)
87d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org  if (IS_UNDEFINED(desc)) { return desc }
88ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org  if ('value' in desc) {
89ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org    return desc.value
90ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org  } else {
91d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    if (IS_UNDEFINED(desc.get)) { return desc.get }
92d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    // The proposal says: desc.get.call(receiver)
93d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    return %_CallFunction(receiver, desc.get)
94ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org  }
95ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org}
96d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org
97d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.orgfunction DerivedSetTrap(receiver, name, val) {
98d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org  var desc = this.getOwnPropertyDescriptor(name)
99d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org  if (desc) {
100d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    if ('writable' in desc) {
101d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      if (desc.writable) {
102d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        desc.value = val
103d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        this.defineProperty(name, desc)
104d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        return true
105d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      } else {
106d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        return false
107d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      }
108d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    } else { // accessor
109d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      if (desc.set) {
110d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        // The proposal says: desc.set.call(receiver, val)
111d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        %_CallFunction(receiver, val, desc.set)
112d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        return true
113d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      } else {
114d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        return false
115d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      }
116d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    }
117d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org  }
118d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org  desc = this.getPropertyDescriptor(name)
119d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org  if (desc) {
120d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    if ('writable' in desc) {
121d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      if (desc.writable) {
122d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        // fall through
123d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      } else {
124d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        return false
125d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      }
126d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    } else { // accessor
127d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      if (desc.set) {
128d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        // The proposal says: desc.set.call(receiver, val)
129d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        %_CallFunction(receiver, val, desc.set)
130d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        return true
131d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      } else {
132d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org        return false
133d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org      }
134d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    }
135d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org  }
136d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org  this.defineProperty(name, {
137d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    value: val,
138d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    writable: true,
139d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    enumerable: true,
140d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org    configurable: true});
141d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org  return true;
142d2be901879306d8ff27e78e37783028d581d46fcricow@chromium.org}
143d6076d96a1411932548838e5960b594564264010erik.corry@gmail.com
144d6076d96a1411932548838e5960b594564264010erik.corry@gmail.comfunction DerivedHasTrap(name) {
145d6076d96a1411932548838e5960b594564264010erik.corry@gmail.com  return !!this.getPropertyDescriptor(name)
146d6076d96a1411932548838e5960b594564264010erik.corry@gmail.com}
147030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org
1489fa09679c31dd1fc79a07ed24431b6951227240aricow@chromium.orgfunction DerivedHasOwnTrap(name) {
1499fa09679c31dd1fc79a07ed24431b6951227240aricow@chromium.org  return !!this.getOwnPropertyDescriptor(name)
1509fa09679c31dd1fc79a07ed24431b6951227240aricow@chromium.org}
1519fa09679c31dd1fc79a07ed24431b6951227240aricow@chromium.org
152030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.orgfunction DerivedKeysTrap() {
153030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  var names = this.getOwnPropertyNames()
154030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  var enumerableNames = []
155030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  for (var i = 0, count = 0; i < names.length; ++i) {
156030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    var name = names[i]
157750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org    if (IS_SYMBOL(name)) continue
158394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    var desc = this.getOwnPropertyDescriptor(TO_STRING_INLINE(name))
159394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    if (!IS_UNDEFINED(desc) && desc.enumerable) {
160030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org      enumerableNames[count++] = names[i]
161030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org    }
162030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  }
163030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org  return enumerableNames
164030d38ee536bc25856546e75fdac60d1a0c42bddwhesse@chromium.org}
165394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com
166394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.comfunction DerivedEnumerateTrap() {
167394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  var names = this.getPropertyNames()
168394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  var enumerableNames = []
169394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  for (var i = 0, count = 0; i < names.length; ++i) {
170394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    var name = names[i]
171750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org    if (IS_SYMBOL(name)) continue
172394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    var desc = this.getPropertyDescriptor(TO_STRING_INLINE(name))
173ba72ec861b69b67139c93fc6dd56f4a73c9b3135jkummerow@chromium.org    if (!IS_UNDEFINED(desc)) {
174ba72ec861b69b67139c93fc6dd56f4a73c9b3135jkummerow@chromium.org      if (!desc.configurable) {
175ba72ec861b69b67139c93fc6dd56f4a73c9b3135jkummerow@chromium.org        throw MakeTypeError("proxy_prop_not_configurable",
176ba72ec861b69b67139c93fc6dd56f4a73c9b3135jkummerow@chromium.org            [this, "getPropertyDescriptor", name])
177ba72ec861b69b67139c93fc6dd56f4a73c9b3135jkummerow@chromium.org      }
178ba72ec861b69b67139c93fc6dd56f4a73c9b3135jkummerow@chromium.org      if (desc.enumerable) enumerableNames[count++] = names[i]
179394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    }
180394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  }
181394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  return enumerableNames
182394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com}
183394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com
184394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.comfunction ProxyEnumerate(proxy) {
185394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  var handler = %GetHandler(proxy)
186394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  if (IS_UNDEFINED(handler.enumerate)) {
187394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com    return %Apply(DerivedEnumerateTrap, handler, [], 0, 0)
188394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  } else {
189750145ab1b720c97adf2b548cc8fbd28c8b8e06dulan@chromium.org    return ToNameArray(handler.enumerate(), "enumerate", false)
190394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com  }
191394dbcf9009cf5203b6d85e8b515fcff072040f3erik.corry@gmail.com}
192