Line data Source code
1 : // Copyright 2016 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/api-arguments-inl.h"
6 : #include "src/api-natives.h"
7 : #include "src/builtins/builtins-utils-inl.h"
8 : #include "src/builtins/builtins.h"
9 : #include "src/counters.h"
10 : #include "src/log.h"
11 : #include "src/objects-inl.h"
12 : #include "src/objects/templates.h"
13 : #include "src/prototype.h"
14 : #include "src/visitors.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 : namespace {
20 :
21 : // Returns the holder JSObject if the function can legally be called with this
22 : // receiver. Returns nullptr if the call is illegal.
23 : // TODO(dcarney): CallOptimization duplicates this logic, merge.
24 2381080 : JSReceiver GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo info,
25 : JSReceiver receiver) {
26 : Object recv_type = info->signature();
27 : // No signature, return holder.
28 2381080 : if (!recv_type->IsFunctionTemplateInfo()) return receiver;
29 : // A Proxy cannot have been created from the signature template.
30 3839 : if (!receiver->IsJSObject()) return JSReceiver();
31 :
32 : JSObject js_obj_receiver = JSObject::cast(receiver);
33 3839 : FunctionTemplateInfo signature = FunctionTemplateInfo::cast(recv_type);
34 :
35 : // Check the receiver. Fast path for receivers with no hidden prototypes.
36 3839 : if (signature->IsTemplateFor(js_obj_receiver)) return receiver;
37 621 : if (!js_obj_receiver->map()->has_hidden_prototype()) return JSReceiver();
38 109 : for (PrototypeIterator iter(isolate, js_obj_receiver, kStartAtPrototype,
39 : PrototypeIterator::END_AT_NON_HIDDEN);
40 10 : !iter.IsAtEnd(); iter.Advance()) {
41 : JSObject current = iter.GetCurrent<JSObject>();
42 89 : if (signature->IsTemplateFor(current)) return current;
43 : }
44 10 : return JSReceiver();
45 : }
46 :
47 : template <bool is_construct>
48 2681738 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> HandleApiCallHelper(
49 : Isolate* isolate, Handle<HeapObject> function,
50 : Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
51 : Handle<Object> receiver, BuiltinArguments args) {
52 : Handle<JSReceiver> js_receiver;
53 : JSReceiver raw_holder;
54 : if (is_construct) {
55 : DCHECK(args.receiver()->IsTheHole(isolate));
56 601327 : if (fun_data->GetInstanceTemplate()->IsUndefined(isolate)) {
57 : v8::Local<ObjectTemplate> templ =
58 : ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
59 351 : ToApiHandle<v8::FunctionTemplate>(fun_data));
60 351 : FunctionTemplateInfo::SetInstanceTemplate(isolate, fun_data,
61 : Utils::OpenHandle(*templ));
62 : }
63 : Handle<ObjectTemplateInfo> instance_template(
64 300665 : ObjectTemplateInfo::cast(fun_data->GetInstanceTemplate()), isolate);
65 601323 : ASSIGN_RETURN_ON_EXCEPTION(
66 : isolate, js_receiver,
67 : ApiNatives::InstantiateObject(isolate, instance_template,
68 : Handle<JSReceiver>::cast(new_target)),
69 : Object);
70 : args.set_at(0, *js_receiver);
71 : DCHECK_EQ(*js_receiver, *args.receiver());
72 :
73 300658 : raw_holder = *js_receiver;
74 : } else {
75 : DCHECK(receiver->IsJSReceiver());
76 : js_receiver = Handle<JSReceiver>::cast(receiver);
77 :
78 2381138 : if (!fun_data->accept_any_receiver() &&
79 : js_receiver->IsAccessCheckNeeded()) {
80 : // Proxies never need access checks.
81 : DCHECK(js_receiver->IsJSObject());
82 57 : Handle<JSObject> js_obj_receiver = Handle<JSObject>::cast(js_receiver);
83 57 : if (!isolate->MayAccess(handle(isolate->context(), isolate),
84 : js_obj_receiver)) {
85 7 : isolate->ReportFailedAccessCheck(js_obj_receiver);
86 7 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
87 2 : return isolate->factory()->undefined_value();
88 : }
89 : }
90 :
91 2381069 : raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
92 :
93 2381079 : if (raw_holder.is_null()) {
94 : // This function cannot be called with the given receiver. Abort!
95 1084 : THROW_NEW_ERROR(
96 : isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
97 : }
98 : }
99 :
100 : Object raw_call_data = fun_data->call_code();
101 2681195 : if (!raw_call_data->IsUndefined(isolate)) {
102 : DCHECK(raw_call_data->IsCallHandlerInfo());
103 : CallHandlerInfo call_data = CallHandlerInfo::cast(raw_call_data);
104 2676186 : Object data_obj = call_data->data();
105 :
106 : FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder,
107 : *new_target, args.address_of_arg_at(1),
108 5352372 : args.length() - 1);
109 2676174 : Handle<Object> result = custom.Call(call_data);
110 :
111 2676183 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
112 2647305 : if (result.is_null()) {
113 721 : if (is_construct) return js_receiver;
114 1218653 : return isolate->factory()->undefined_value();
115 : }
116 : // Rebox the result.
117 : result->VerifyApiCallResultType();
118 275217 : if (!is_construct || result->IsJSReceiver())
119 1427654 : return handle(*result, isolate);
120 : }
121 :
122 5287 : return js_receiver;
123 : }
124 :
125 : } // anonymous namespace
126 :
127 12852827 : BUILTIN(HandleApiCall) {
128 : HandleScope scope(isolate);
129 : Handle<JSFunction> function = args.target();
130 2566558 : Handle<Object> receiver = args.receiver();
131 : Handle<HeapObject> new_target = args.new_target();
132 : Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(),
133 : isolate);
134 2566559 : if (new_target->IsJSReceiver()) {
135 619643 : RETURN_RESULT_OR_FAILURE(
136 : isolate, HandleApiCallHelper<true>(isolate, function, new_target,
137 : fun_data, receiver, args));
138 : } else {
139 4542472 : RETURN_RESULT_OR_FAILURE(
140 : isolate, HandleApiCallHelper<false>(isolate, function, new_target,
141 : fun_data, receiver, args));
142 : }
143 : }
144 :
145 : namespace {
146 :
147 230372 : class RelocatableArguments : public BuiltinArguments, public Relocatable {
148 : public:
149 : RelocatableArguments(Isolate* isolate, int length, Address* arguments)
150 115185 : : BuiltinArguments(length, arguments), Relocatable(isolate) {}
151 :
152 66 : inline void IterateInstance(RootVisitor* v) override {
153 66 : if (length() == 0) return;
154 : v->VisitRootPointers(Root::kRelocatable, nullptr, first_slot(),
155 132 : last_slot() + 1);
156 : }
157 :
158 : private:
159 : DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
160 : };
161 :
162 : } // namespace
163 :
164 115395 : MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
165 : bool is_construct,
166 : Handle<HeapObject> function,
167 : Handle<Object> receiver,
168 : int argc, Handle<Object> args[],
169 : Handle<HeapObject> new_target) {
170 : RuntimeCallTimerScope timer(isolate,
171 115395 : RuntimeCallCounterId::kInvokeApiFunction);
172 : DCHECK(function->IsFunctionTemplateInfo() ||
173 : (function->IsJSFunction() &&
174 : JSFunction::cast(*function)->shared()->IsApiFunction()));
175 :
176 : // Do proper receiver conversion for non-strict mode api functions.
177 230018 : if (!is_construct && !receiver->IsJSReceiver()) {
178 228 : if (function->IsFunctionTemplateInfo() ||
179 : is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
180 264 : ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
181 : Object::ConvertReceiver(isolate, receiver),
182 : Object);
183 : }
184 : }
185 :
186 115395 : if (function->IsFunctionTemplateInfo()) {
187 : Handle<FunctionTemplateInfo> info =
188 : Handle<FunctionTemplateInfo>::cast(function);
189 : // If we need to break at function entry, go the long way. Instantiate the
190 : // function, use the DebugBreakTrampoline, and call it through JS.
191 102728 : if (info->BreakAtEntry()) {
192 : DCHECK(!is_construct);
193 : DCHECK(new_target->IsUndefined(isolate));
194 : Handle<JSFunction> function;
195 420 : ASSIGN_RETURN_ON_EXCEPTION(isolate, function,
196 : ApiNatives::InstantiateFunction(
197 : info, MaybeHandle<v8::internal::Name>()),
198 : Object);
199 210 : Handle<Code> trampoline = BUILTIN_CODE(isolate, DebugBreakTrampoline);
200 210 : function->set_code(*trampoline);
201 210 : return Execution::Call(isolate, function, receiver, argc, args);
202 : }
203 : }
204 :
205 : Handle<FunctionTemplateInfo> fun_data =
206 : function->IsFunctionTemplateInfo()
207 : ? Handle<FunctionTemplateInfo>::cast(function)
208 : : handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
209 127854 : isolate);
210 : // Construct BuiltinArguments object:
211 : // new target, function, arguments reversed, receiver.
212 : const int kBufferSize = 32;
213 : Address small_argv[kBufferSize];
214 : Address* argv;
215 115187 : const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver;
216 115187 : if (frame_argc <= kBufferSize) {
217 : argv = small_argv;
218 : } else {
219 0 : argv = new Address[frame_argc];
220 : }
221 115185 : int cursor = frame_argc - 1;
222 230370 : argv[cursor--] = receiver->ptr();
223 117379 : for (int i = 0; i < argc; ++i) {
224 2194 : argv[cursor--] = args[i]->ptr();
225 : }
226 : DCHECK_EQ(cursor, BuiltinArguments::kPaddingOffset);
227 : argv[BuiltinArguments::kPaddingOffset] =
228 115185 : ReadOnlyRoots(isolate).the_hole_value()->ptr();
229 115185 : argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc)->ptr();
230 115185 : argv[BuiltinArguments::kTargetOffset] = function->ptr();
231 115185 : argv[BuiltinArguments::kNewTargetOffset] = new_target->ptr();
232 : MaybeHandle<Object> result;
233 : {
234 115185 : RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
235 115185 : if (is_construct) {
236 : result = HandleApiCallHelper<true>(isolate, function, new_target,
237 773 : fun_data, receiver, arguments);
238 : } else {
239 : result = HandleApiCallHelper<false>(isolate, function, new_target,
240 114412 : fun_data, receiver, arguments);
241 : }
242 : }
243 115186 : if (argv != small_argv) delete[] argv;
244 115186 : return result;
245 : }
246 :
247 : // Helper function to handle calls to non-function objects created through the
248 : // API. The object can be called as either a constructor (using new) or just as
249 : // a function (without new).
250 232 : V8_WARN_UNUSED_RESULT static Object HandleApiCallAsFunctionOrConstructor(
251 : Isolate* isolate, bool is_construct_call, BuiltinArguments args) {
252 : Handle<Object> receiver = args.receiver();
253 :
254 : // Get the object called.
255 : JSObject obj = JSObject::cast(*receiver);
256 :
257 : // Set the new target.
258 : HeapObject new_target;
259 232 : if (is_construct_call) {
260 : // TODO(adamk): This should be passed through in args instead of
261 : // being patched in here. We need to set a non-undefined value
262 : // for v8::FunctionCallbackInfo::IsConstructCall() to get the
263 : // right answer.
264 18 : new_target = obj;
265 : } else {
266 214 : new_target = ReadOnlyRoots(isolate).undefined_value();
267 : }
268 :
269 : // Get the invocation callback from the function descriptor that was
270 : // used to create the called object.
271 : DCHECK(obj->map()->is_callable());
272 232 : JSFunction constructor = JSFunction::cast(obj->map()->GetConstructor());
273 : DCHECK(constructor->shared()->IsApiFunction());
274 : Object handler =
275 232 : constructor->shared()->get_api_func_data()->GetInstanceCallHandler();
276 : DCHECK(!handler->IsUndefined(isolate));
277 : CallHandlerInfo call_data = CallHandlerInfo::cast(handler);
278 :
279 : // Get the data for the call and perform the callback.
280 : Object result;
281 : {
282 : HandleScope scope(isolate);
283 232 : LOG(isolate, ApiObjectAccess("call non-function", obj));
284 : FunctionCallbackArguments custom(isolate, call_data->data(), constructor,
285 : obj, new_target, args.address_of_arg_at(1),
286 464 : args.length() - 1);
287 232 : Handle<Object> result_handle = custom.Call(call_data);
288 232 : if (result_handle.is_null()) {
289 : result = ReadOnlyRoots(isolate).undefined_value();
290 : } else {
291 : result = *result_handle;
292 : }
293 : }
294 : // Check for exceptions and return result.
295 232 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
296 220 : return result;
297 : }
298 :
299 : // Handle calls to non-function objects created through the API. This delegate
300 : // function is used when the call is a normal function call.
301 428 : BUILTIN(HandleApiCallAsFunction) {
302 214 : return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
303 : }
304 :
305 : // Handle calls to non-function objects created through the API. This delegate
306 : // function is used when the call is a construct call.
307 36 : BUILTIN(HandleApiCallAsConstructor) {
308 18 : return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
309 : }
310 :
311 : } // namespace internal
312 120216 : } // namespace v8
|