1 // Copyright 2014 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 #include "src/runtime/runtime-utils.h"
6 
7 #include "src/arguments.h"
8 #include "src/elements.h"
9 #include "src/factory.h"
10 #include "src/isolate-inl.h"
11 #include "src/objects-inl.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 
17 // ES6 9.5.13 [[Call]] (thisArgument, argumentsList)
RUNTIME_FUNCTION(Runtime_JSProxyCall)18 RUNTIME_FUNCTION(Runtime_JSProxyCall) {
19   HandleScope scope(isolate);
20   DCHECK_LE(2, args.length());
21   // thisArgument == receiver
22   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
23   CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, args.length() - 1);
24   Handle<String> trap_name = isolate->factory()->apply_string();
25   // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
26   Handle<Object> handler(proxy->handler(), isolate);
27   // 2. If handler is null, throw a TypeError exception.
28   if (proxy->IsRevoked()) {
29     THROW_NEW_ERROR_RETURN_FAILURE(
30         isolate, NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
31   }
32   // 3. Assert: Type(handler) is Object.
33   DCHECK(handler->IsJSReceiver());
34   // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
35   Handle<JSReceiver> target(proxy->target(), isolate);
36   // 5. Let trap be ? GetMethod(handler, "apply").
37   Handle<Object> trap;
38   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
39       isolate, trap,
40       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name));
41   // 6. If trap is undefined, then
42   int const arguments_length = args.length() - 2;
43   if (trap->IsUndefined(isolate)) {
44     // 6.a. Return Call(target, thisArgument, argumentsList).
45     ScopedVector<Handle<Object>> argv(arguments_length);
46     for (int i = 0; i < arguments_length; ++i) {
47       argv[i] = args.at<Object>(i + 1);
48     }
49     RETURN_RESULT_OR_FAILURE(
50         isolate, Execution::Call(isolate, target, receiver, arguments_length,
51                                  argv.start()));
52   }
53   // 7. Let argArray be CreateArrayFromList(argumentsList).
54   Handle<JSArray> arg_array = isolate->factory()->NewJSArray(
55       FAST_ELEMENTS, arguments_length, arguments_length);
56   ElementsAccessor* accessor = arg_array->GetElementsAccessor();
57   {
58     DisallowHeapAllocation no_gc;
59     for (int i = 0; i < arguments_length; i++) {
60       accessor->Set(arg_array, i, args[i + 1]);
61     }
62   }
63   // 8. Return Call(trap, handler, «target, thisArgument, argArray»).
64   Handle<Object> trap_args[] = {target, receiver, arg_array};
65   RETURN_RESULT_OR_FAILURE(
66       isolate,
67       Execution::Call(isolate, trap, handler, arraysize(trap_args), trap_args));
68 }
69 
70 
71 // 9.5.14 [[Construct]] (argumentsList, newTarget)
RUNTIME_FUNCTION(Runtime_JSProxyConstruct)72 RUNTIME_FUNCTION(Runtime_JSProxyConstruct) {
73   HandleScope scope(isolate);
74   DCHECK_LE(3, args.length());
75   CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, args.length() - 2);
76   CONVERT_ARG_HANDLE_CHECKED(Object, new_target, args.length() - 1);
77   Handle<String> trap_name = isolate->factory()->construct_string();
78 
79   // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
80   Handle<Object> handler(proxy->handler(), isolate);
81   // 2. If handler is null, throw a TypeError exception.
82   if (proxy->IsRevoked()) {
83     THROW_NEW_ERROR_RETURN_FAILURE(
84         isolate, NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
85   }
86   // 3. Assert: Type(handler) is Object.
87   DCHECK(handler->IsJSReceiver());
88   // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
89   Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
90   // 5. Let trap be ? GetMethod(handler, "construct").
91   Handle<Object> trap;
92   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
93       isolate, trap,
94       Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name));
95   // 6. If trap is undefined, then
96   int const arguments_length = args.length() - 3;
97   if (trap->IsUndefined(isolate)) {
98     // 6.a. Assert: target has a [[Construct]] internal method.
99     DCHECK(target->IsConstructor());
100     // 6.b. Return Construct(target, argumentsList, newTarget).
101     ScopedVector<Handle<Object>> argv(arguments_length);
102     for (int i = 0; i < arguments_length; ++i) {
103       argv[i] = args.at<Object>(i + 1);
104     }
105     RETURN_RESULT_OR_FAILURE(
106         isolate, Execution::New(isolate, target, new_target, arguments_length,
107                                 argv.start()));
108   }
109   // 7. Let argArray be CreateArrayFromList(argumentsList).
110   Handle<JSArray> arg_array = isolate->factory()->NewJSArray(
111       FAST_ELEMENTS, arguments_length, arguments_length);
112   ElementsAccessor* accessor = arg_array->GetElementsAccessor();
113   {
114     DisallowHeapAllocation no_gc;
115     for (int i = 0; i < arguments_length; i++) {
116       accessor->Set(arg_array, i, args[i + 1]);
117     }
118   }
119   // 8. Let newObj be ? Call(trap, handler, «target, argArray, newTarget »).
120   Handle<Object> new_object;
121   Handle<Object> trap_args[] = {target, arg_array, new_target};
122   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
123       isolate, new_object,
124       Execution::Call(isolate, trap, handler, arraysize(trap_args), trap_args));
125   // 9. If Type(newObj) is not Object, throw a TypeError exception.
126   if (!new_object->IsJSReceiver()) {
127     THROW_NEW_ERROR_RETURN_FAILURE(
128         isolate,
129         NewTypeError(MessageTemplate::kProxyConstructNonObject, new_object));
130   }
131   // 10. Return newObj.
132   return *new_object;
133 }
134 
135 
RUNTIME_FUNCTION(Runtime_IsJSProxy)136 RUNTIME_FUNCTION(Runtime_IsJSProxy) {
137   SealHandleScope shs(isolate);
138   DCHECK(args.length() == 1);
139   CONVERT_ARG_CHECKED(Object, obj, 0);
140   return isolate->heap()->ToBoolean(obj->IsJSProxy());
141 }
142 
143 
RUNTIME_FUNCTION(Runtime_JSProxyGetHandler)144 RUNTIME_FUNCTION(Runtime_JSProxyGetHandler) {
145   SealHandleScope shs(isolate);
146   DCHECK(args.length() == 1);
147   CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
148   return proxy->handler();
149 }
150 
151 
RUNTIME_FUNCTION(Runtime_JSProxyGetTarget)152 RUNTIME_FUNCTION(Runtime_JSProxyGetTarget) {
153   SealHandleScope shs(isolate);
154   DCHECK(args.length() == 1);
155   CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
156   return proxy->target();
157 }
158 
159 
RUNTIME_FUNCTION(Runtime_JSProxyRevoke)160 RUNTIME_FUNCTION(Runtime_JSProxyRevoke) {
161   HandleScope scope(isolate);
162   DCHECK(args.length() == 1);
163   CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
164   JSProxy::Revoke(proxy);
165   return isolate->heap()->undefined_value();
166 }
167 
168 }  // namespace internal
169 }  // namespace v8
170