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