Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(285)

Side by Side Diff: src/builtins/builtins-api.cc

Issue 2178943002: [builtins] move remaining builtins into separate files. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/builtins/builtins.cc ('k') | src/builtins/builtins-call.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
11 namespace v8 {
12 namespace internal {
13
14 namespace {
15
16 // Returns the holder JSObject if the function can legally be called with this
17 // receiver. Returns nullptr if the call is illegal.
18 // TODO(dcarney): CallOptimization duplicates this logic, merge.
19 JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info,
20 JSObject* receiver) {
21 Object* recv_type = info->signature();
22 // No signature, return holder.
23 if (!recv_type->IsFunctionTemplateInfo()) return receiver;
24 FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type);
25
26 // Check the receiver. Fast path for receivers with no hidden prototypes.
27 if (signature->IsTemplateFor(receiver)) return receiver;
28 if (!receiver->map()->has_hidden_prototype()) return nullptr;
29 for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype,
30 PrototypeIterator::END_AT_NON_HIDDEN);
31 !iter.IsAtEnd(); iter.Advance()) {
32 JSObject* current = iter.GetCurrent<JSObject>();
33 if (signature->IsTemplateFor(current)) return current;
34 }
35 return nullptr;
36 }
37
38 template <bool is_construct>
39 MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(
40 Isolate* isolate, Handle<HeapObject> function,
41 Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data,
42 Handle<Object> receiver, BuiltinArguments args) {
43 Handle<JSObject> js_receiver;
44 JSObject* raw_holder;
45 if (is_construct) {
46 DCHECK(args.receiver()->IsTheHole(isolate));
47 if (fun_data->instance_template()->IsUndefined(isolate)) {
48 v8::Local<ObjectTemplate> templ =
49 ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate),
50 ToApiHandle<v8::FunctionTemplate>(fun_data));
51 fun_data->set_instance_template(*Utils::OpenHandle(*templ));
52 }
53 Handle<ObjectTemplateInfo> instance_template(
54 ObjectTemplateInfo::cast(fun_data->instance_template()), isolate);
55 ASSIGN_RETURN_ON_EXCEPTION(
56 isolate, js_receiver,
57 ApiNatives::InstantiateObject(instance_template,
58 Handle<JSReceiver>::cast(new_target)),
59 Object);
60 args[0] = *js_receiver;
61 DCHECK_EQ(*js_receiver, *args.receiver());
62
63 raw_holder = *js_receiver;
64 } else {
65 DCHECK(receiver->IsJSReceiver());
66
67 if (!receiver->IsJSObject()) {
68 // This function cannot be called with the given receiver. Abort!
69 THROW_NEW_ERROR(
70 isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
71 }
72
73 js_receiver = Handle<JSObject>::cast(receiver);
74
75 if (!fun_data->accept_any_receiver() &&
76 js_receiver->IsAccessCheckNeeded() &&
77 !isolate->MayAccess(handle(isolate->context()), js_receiver)) {
78 isolate->ReportFailedAccessCheck(js_receiver);
79 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
80 }
81
82 raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver);
83
84 if (raw_holder == nullptr) {
85 // This function cannot be called with the given receiver. Abort!
86 THROW_NEW_ERROR(
87 isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object);
88 }
89 }
90
91 Object* raw_call_data = fun_data->call_code();
92 if (!raw_call_data->IsUndefined(isolate)) {
93 DCHECK(raw_call_data->IsCallHandlerInfo());
94 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
95 Object* callback_obj = call_data->callback();
96 v8::FunctionCallback callback =
97 v8::ToCData<v8::FunctionCallback>(callback_obj);
98 Object* data_obj = call_data->data();
99
100 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*js_receiver)));
101
102 FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder,
103 *new_target, &args[0] - 1,
104 args.length() - 1);
105
106 Handle<Object> result = custom.Call(callback);
107
108 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
109 if (result.is_null()) {
110 if (is_construct) return js_receiver;
111 return isolate->factory()->undefined_value();
112 }
113 // Rebox the result.
114 result->VerifyApiCallResultType();
115 if (!is_construct || result->IsJSObject()) return handle(*result, isolate);
116 }
117
118 return js_receiver;
119 }
120
121 } // anonymous namespace
122
123 BUILTIN(HandleApiCall) {
124 HandleScope scope(isolate);
125 Handle<JSFunction> function = args.target<JSFunction>();
126 Handle<Object> receiver = args.receiver();
127 Handle<HeapObject> new_target = args.new_target();
128 Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(),
129 isolate);
130 if (new_target->IsJSReceiver()) {
131 RETURN_RESULT_OR_FAILURE(
132 isolate, HandleApiCallHelper<true>(isolate, function, new_target,
133 fun_data, receiver, args));
134 } else {
135 RETURN_RESULT_OR_FAILURE(
136 isolate, HandleApiCallHelper<false>(isolate, function, new_target,
137 fun_data, receiver, args));
138 }
139 }
140
141 namespace {
142
143 class RelocatableArguments : public BuiltinArguments, public Relocatable {
144 public:
145 RelocatableArguments(Isolate* isolate, int length, Object** arguments)
146 : BuiltinArguments(length, arguments), Relocatable(isolate) {}
147
148 virtual inline void IterateInstance(ObjectVisitor* v) {
149 if (length() == 0) return;
150 v->VisitPointers(lowest_address(), highest_address() + 1);
151 }
152
153 private:
154 DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
155 };
156
157 } // namespace
158
159 MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate,
160 Handle<HeapObject> function,
161 Handle<Object> receiver,
162 int argc,
163 Handle<Object> args[]) {
164 DCHECK(function->IsFunctionTemplateInfo() ||
165 (function->IsJSFunction() &&
166 JSFunction::cast(*function)->shared()->IsApiFunction()));
167
168 // Do proper receiver conversion for non-strict mode api functions.
169 if (!receiver->IsJSReceiver()) {
170 if (function->IsFunctionTemplateInfo() ||
171 is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) {
172 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver,
173 Object::ConvertReceiver(isolate, receiver),
174 Object);
175 }
176 }
177
178 Handle<FunctionTemplateInfo> fun_data =
179 function->IsFunctionTemplateInfo()
180 ? Handle<FunctionTemplateInfo>::cast(function)
181 : handle(JSFunction::cast(*function)->shared()->get_api_func_data(),
182 isolate);
183 Handle<HeapObject> new_target = isolate->factory()->undefined_value();
184 // Construct BuiltinArguments object:
185 // new target, function, arguments reversed, receiver.
186 const int kBufferSize = 32;
187 Object* small_argv[kBufferSize];
188 Object** argv;
189 const int frame_argc = argc + BuiltinArguments::kNumExtraArgsWithReceiver;
190 if (frame_argc <= kBufferSize) {
191 argv = small_argv;
192 } else {
193 argv = new Object*[frame_argc];
194 }
195 int cursor = frame_argc - 1;
196 argv[cursor--] = *receiver;
197 for (int i = 0; i < argc; ++i) {
198 argv[cursor--] = *args[i];
199 }
200 DCHECK(cursor == BuiltinArguments::kArgcOffset);
201 argv[BuiltinArguments::kArgcOffset] = Smi::FromInt(frame_argc);
202 argv[BuiltinArguments::kTargetOffset] = *function;
203 argv[BuiltinArguments::kNewTargetOffset] = *new_target;
204 MaybeHandle<Object> result;
205 {
206 RelocatableArguments arguments(isolate, frame_argc, &argv[frame_argc - 1]);
207 result = HandleApiCallHelper<false>(isolate, function, new_target, fun_data,
208 receiver, arguments);
209 }
210 if (argv != small_argv) delete[] argv;
211 return result;
212 }
213
214 // Helper function to handle calls to non-function objects created through the
215 // API. The object can be called as either a constructor (using new) or just as
216 // a function (without new).
217 MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
218 Isolate* isolate, bool is_construct_call, BuiltinArguments args) {
219 Handle<Object> receiver = args.receiver();
220
221 // Get the object called.
222 JSObject* obj = JSObject::cast(*receiver);
223
224 // Set the new target.
225 HeapObject* new_target;
226 if (is_construct_call) {
227 // TODO(adamk): This should be passed through in args instead of
228 // being patched in here. We need to set a non-undefined value
229 // for v8::FunctionCallbackInfo::IsConstructCall() to get the
230 // right answer.
231 new_target = obj;
232 } else {
233 new_target = isolate->heap()->undefined_value();
234 }
235
236 // Get the invocation callback from the function descriptor that was
237 // used to create the called object.
238 DCHECK(obj->map()->is_callable());
239 JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
240 // TODO(ishell): turn this back to a DCHECK.
241 CHECK(constructor->shared()->IsApiFunction());
242 Object* handler =
243 constructor->shared()->get_api_func_data()->instance_call_handler();
244 DCHECK(!handler->IsUndefined(isolate));
245 // TODO(ishell): remove this debugging code.
246 CHECK(handler->IsCallHandlerInfo());
247 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
248 Object* callback_obj = call_data->callback();
249 v8::FunctionCallback callback =
250 v8::ToCData<v8::FunctionCallback>(callback_obj);
251
252 // Get the data for the call and perform the callback.
253 Object* result;
254 {
255 HandleScope scope(isolate);
256 LOG(isolate, ApiObjectAccess("call non-function", obj));
257
258 FunctionCallbackArguments custom(isolate, call_data->data(), constructor,
259 obj, new_target, &args[0] - 1,
260 args.length() - 1);
261 Handle<Object> result_handle = custom.Call(callback);
262 if (result_handle.is_null()) {
263 result = isolate->heap()->undefined_value();
264 } else {
265 result = *result_handle;
266 }
267 }
268 // Check for exceptions and return result.
269 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
270 return result;
271 }
272
273 // Handle calls to non-function objects created through the API. This delegate
274 // function is used when the call is a normal function call.
275 BUILTIN(HandleApiCallAsFunction) {
276 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
277 }
278
279 // Handle calls to non-function objects created through the API. This delegate
280 // function is used when the call is a construct call.
281 BUILTIN(HandleApiCallAsConstructor) {
282 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
283 }
284
285 } // namespace internal
286 } // namespace v8
OLDNEW
« no previous file with comments | « src/builtins/builtins.cc ('k') | src/builtins/builtins-call.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698