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
13namespace v8 {
14namespace internal {
15
16
17// ES6 9.5.13 [[Call]] (thisArgument, argumentsList)
18RUNTIME_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(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)
72RUNTIME_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(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
136RUNTIME_FUNCTION(Runtime_IsJSProxy) {
137  SealHandleScope shs(isolate);
138  DCHECK_EQ(1, args.length());
139  CONVERT_ARG_CHECKED(Object, obj, 0);
140  return isolate->heap()->ToBoolean(obj->IsJSProxy());
141}
142
143
144RUNTIME_FUNCTION(Runtime_JSProxyGetHandler) {
145  SealHandleScope shs(isolate);
146  DCHECK_EQ(1, args.length());
147  CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
148  return proxy->handler();
149}
150
151
152RUNTIME_FUNCTION(Runtime_JSProxyGetTarget) {
153  SealHandleScope shs(isolate);
154  DCHECK_EQ(1, args.length());
155  CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
156  return proxy->target();
157}
158
159
160RUNTIME_FUNCTION(Runtime_JSProxyRevoke) {
161  HandleScope scope(isolate);
162  DCHECK_EQ(1, args.length());
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