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/builtins/builtins.h"
6 :
7 : #include "src/api-arguments.h"
8 : #include "src/api-natives.h"
9 : #include "src/builtins/builtins-utils.h"
10 : #include "src/counters.h"
11 : #include "src/log.h"
12 : #include "src/objects-inl.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 51812111 : JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
25 : JSObject* receiver) {
26 : Object* recv_type = info->signature();
27 : // No signature, return holder.
28 51812110 : if (!recv_type->IsFunctionTemplateInfo()) return receiver;
29 : FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
30 :
31 : // Check the receiver. Fast path for receivers with no hidden prototypes.
32 9961 : if (signature->IsTemplateFor(receiver)) return receiver;
33 7537 : if (!receiver->map()->has_hidden_prototype()) return nullptr;
34 7378 : for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype,
35 : PrototypeIterator::END_AT_NON_HIDDEN);
36 18 : !iter.IsAtEnd(); iter.Advance()) {
37 7360 : JSObject* current = iter.GetCurrent<JSObject>();
38 7360 : if (signature->IsTemplateFor(current)) return current;
39 : }
40 18 : return nullptr;
41 : }
42 :
43 : template <bool is_construct>
44 51868803 : MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(
45 51866376 : Isolate* isolate, Handle<HeapObject> function,
46 : Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
47 : Handle<Object> receiver, BuiltinArguments args) {
48 : Handle<JSObject> js_receiver;
49 : JSObject* raw_holder;
50 : if (is_construct) {
51 : DCHECK(args.receiver()->IsTheHole(isolate));
52 56682 : if (fun_data->instance_template()->IsUndefined(isolate)) {
53 : v8::Local<ObjectTemplate> templ =
54 : ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
55 2711 : ToApiHandle<v8::FunctionTemplate>(fun_data));
56 : fun_data->set_instance_template(*Utils::OpenHandle(*templ));
57 : }
58 : Handle<ObjectTemplateInfo> instance_template(
59 : ObjectTemplateInfo::cast(fun_data->instance_template()), isolate);
60 113364 : ASSIGN_RETURN_ON_EXCEPTION(
61 : isolate, js_receiver,
62 : ApiNatives::InstantiateObject(instance_template,
63 : Handle<JSReceiver>::cast(new_target)),
64 : Object);
65 56682 : args[0] = *js_receiver;
66 : DCHECK_EQ(*js_receiver, *args.receiver());
67 :
68 : raw_holder = *js_receiver;
69 : } else {
70 : DCHECK(receiver->IsJSReceiver());
71 :
72 51812119 : if (!receiver->IsJSObject()) {
73 : // This function cannot be called with the given receiver. Abort!
74 0 : THROW_NEW_ERROR(
75 : isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
76 : }
77 :
78 : js_receiver = Handle<JSObject>::cast(receiver);
79 :
80 51812260 : if (!fun_data->accept_any_receiver() &&
81 : js_receiver->IsAccessCheckNeeded() &&
82 68 : !isolate->MayAccess(handle(isolate->context()), js_receiver)) {
83 8 : isolate->ReportFailedAccessCheck(js_receiver);
84 8 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
85 : return isolate->factory()->undefined_value();
86 : }
87 :
88 51812111 : raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
89 :
90 51812112 : if (raw_holder == nullptr) {
91 : // This function cannot be called with the given receiver. Abort!
92 390 : THROW_NEW_ERROR(
93 : isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
94 : }
95 : }
96 :
97 : Object* raw_call_data = fun_data->call_code();
98 51868599 : if (!raw_call_data->IsUndefined(isolate)) {
99 : DCHECK(raw_call_data->IsCallHandlerInfo());
100 : CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
101 : Object* callback_obj = call_data->callback();
102 : v8::FunctionCallback callback =
103 : v8::ToCData<v8::FunctionCallback>(callback_obj);
104 : Object* data_obj = call_data->data();
105 :
106 51866308 : LOG(isolate, ApiObjectAccess("call", JSObject::cast(*js_receiver)));
107 :
108 : FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder,
109 : *new_target, &args[0] - 1,
110 103677982 : args.length() - 1);
111 :
112 51866308 : Handle<Object> result = custom.Call(callback);
113 :
114 51866308 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
115 51850982 : if (result.is_null()) {
116 : if (is_construct) return js_receiver;
117 : return isolate->factory()->undefined_value();
118 : }
119 : // Rebox the result.
120 : result->VerifyApiCallResultType();
121 51505 : if (!is_construct || result->IsJSObject()) return handle(*result, isolate);
122 : }
123 :
124 : return js_receiver;
125 : }
126 :
127 : } // anonymous namespace
128 :
129 155594547 : BUILTIN(HandleApiCall) {
130 : HandleScope scope(isolate);
131 : Handle<JSFunction> function = args.target();
132 51864849 : Handle<Object> receiver = args.receiver();
133 : Handle<HeapObject> new_target = args.new_target();
134 : Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(),
135 : isolate);
136 51864849 : if (new_target->IsJSReceiver()) {
137 164826 : RETURN_RESULT_OR_FAILURE(
138 : isolate, HandleApiCallHelper<true>(isolate, function, new_target,
139 : fun_data, receiver, args));
140 : } else {
141 155414266 : RETURN_RESULT_OR_FAILURE(
142 : isolate, HandleApiCallHelper<false>(isolate, function, new_target,
143 : fun_data, receiver, args));
144 : }
145 : }
146 :
147 : namespace {
148 :
149 3953 : class RelocatableArguments : public BuiltinArguments, public Relocatable {
150 : public:
151 : RelocatableArguments(Isolate* isolate, int length, Object** arguments)
152 3953 : : BuiltinArguments(length, arguments), Relocatable(isolate) {}
153 :
154 87 : virtual inline void IterateInstance(RootVisitor* v) {
155 174 : if (length() == 0) return;
156 : v->VisitRootPointers(Root::kRelocatable, lowest_address(),
157 261 : highest_address() + 1);
158 : }
159 :
160 : private:
161 : DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
162 : };
163 :
164 : } // namespace
165 :
166 3953 : MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
167 : bool is_construct,
168 : Handle<HeapObject> function,
169 : Handle<Object> receiver,
170 : int argc, Handle<Object> args[],
171 : Handle<HeapObject> new_target) {
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 7021 : if (!is_construct && !receiver->IsJSReceiver()) {
178 608 : if (function->IsFunctionTemplateInfo() ||
179 : is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
180 650 : ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
181 : Object::ConvertReceiver(isolate, receiver),
182 : Object);
183 : }
184 : }
185 :
186 : Handle<FunctionTemplateInfo> fun_data =
187 : function->IsFunctionTemplateInfo()
188 : ? Handle<FunctionTemplateInfo>::cast(function)
189 : : handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
190 7434 : isolate);
191 : // Construct BuiltinArguments object:
192 : // new target, function, arguments reversed, receiver.
193 : const int kBufferSize = 32;
194 : Object* small_argv[kBufferSize];
195 : Object** argv;
196 3953 : const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver;
197 3953 : if (frame_argc <= kBufferSize) {
198 : argv = small_argv;
199 : } else {
200 0 : argv = new Object*[frame_argc];
201 : }
202 3953 : int cursor = frame_argc - 1;
203 7906 : argv[cursor--] = *receiver;
204 5027 : for (int i = 0; i < argc; ++i) {
205 2148 : argv[cursor--] = *args[i];
206 : }
207 : DCHECK(cursor == BuiltinArguments::kArgcOffset);
208 3953 : argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc);
209 3953 : argv[BuiltinArguments::kTargetOffset] = *function;
210 3953 : argv[BuiltinArguments::kNewTargetOffset] = *new_target;
211 : MaybeHandle<Object> result;
212 : {
213 3953 : RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
214 3953 : if (is_construct) {
215 : result = HandleApiCallHelper<true>(isolate, function, new_target,
216 885 : fun_data, receiver, arguments);
217 : } else {
218 : result = HandleApiCallHelper<false>(isolate, function, new_target,
219 3068 : fun_data, receiver, arguments);
220 : }
221 : }
222 3953 : if (argv != small_argv) delete[] argv;
223 3953 : return result;
224 : }
225 :
226 : // Helper function to handle calls to non-function objects created through the
227 : // API. The object can be called as either a constructor (using new) or just as
228 : // a function (without new).
229 339 : MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
230 339 : Isolate* isolate, bool is_construct_call, BuiltinArguments args) {
231 : Handle<Object> receiver = args.receiver();
232 :
233 : // Get the object called.
234 : JSObject* obj = JSObject::cast(*receiver);
235 :
236 : // Set the new target.
237 : HeapObject* new_target;
238 339 : if (is_construct_call) {
239 : // TODO(adamk): This should be passed through in args instead of
240 : // being patched in here. We need to set a non-undefined value
241 : // for v8::FunctionCallbackInfo::IsConstructCall() to get the
242 : // right answer.
243 : new_target = obj;
244 : } else {
245 248 : new_target = isolate->heap()->undefined_value();
246 : }
247 :
248 : // Get the invocation callback from the function descriptor that was
249 : // used to create the called object.
250 : DCHECK(obj->map()->is_callable());
251 339 : JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
252 : // TODO(ishell): turn this back to a DCHECK.
253 339 : CHECK(constructor->shared()->IsApiFunction());
254 : Object* handler =
255 : constructor->shared()->get_api_func_data()->instance_call_handler();
256 : DCHECK(!handler->IsUndefined(isolate));
257 : // TODO(ishell): remove this debugging code.
258 339 : CHECK(handler->IsCallHandlerInfo());
259 : CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
260 : Object* callback_obj = call_data->callback();
261 : v8::FunctionCallback callback =
262 : v8::ToCData<v8::FunctionCallback>(callback_obj);
263 :
264 : // Get the data for the call and perform the callback.
265 : Object* result;
266 : {
267 : HandleScope scope(isolate);
268 339 : LOG(isolate, ApiObjectAccess("call non-function", obj));
269 :
270 : FunctionCallbackArguments custom(isolate, call_data->data(), constructor,
271 : obj, new_target, &args[0] - 1,
272 339 : args.length() - 1);
273 339 : Handle<Object> result_handle = custom.Call(callback);
274 339 : if (result_handle.is_null()) {
275 28 : result = isolate->heap()->undefined_value();
276 : } else {
277 : result = *result_handle;
278 : }
279 : }
280 : // Check for exceptions and return result.
281 339 : RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
282 : return result;
283 : }
284 :
285 : // Handle calls to non-function objects created through the API. This delegate
286 : // function is used when the call is a normal function call.
287 496 : BUILTIN(HandleApiCallAsFunction) {
288 248 : return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
289 : }
290 :
291 : // Handle calls to non-function objects created through the API. This delegate
292 : // function is used when the call is a construct call.
293 182 : BUILTIN(HandleApiCallAsConstructor) {
294 91 : return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
295 : }
296 :
297 : } // namespace internal
298 : } // namespace v8
|