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