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

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

Issue 895053002: Move the contents of api-natives.js to c++ (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 10 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/api-natives.h ('k') | src/apinatives.js » ('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 2015 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-natives.h"
6 #include "src/isolate-inl.h"
7
8 namespace v8 {
9 namespace internal {
10
11 namespace {
12
13 // Transform getter or setter into something DefineAccessor can handle.
14 Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
15 Handle<Object> component) {
16 if (component->IsUndefined()) return isolate->factory()->undefined_value();
17 Handle<FunctionTemplateInfo> info =
18 Handle<FunctionTemplateInfo>::cast(component);
19 // TODO(dcarney): instantiate directly.
20 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
21 }
22
23
24 MaybeHandle<Object> DefineApiAccessorProperty(
25 Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
26 Handle<Object> getter, Handle<Object> setter, Smi* attribute) {
27 DCHECK(PropertyDetails::AttributesField::is_valid(
28 static_cast<PropertyAttributes>(attribute->value())));
29 RETURN_ON_EXCEPTION(
30 isolate, JSObject::DefineAccessor(
31 object, name, InstantiateAccessorComponent(isolate, getter),
32 InstantiateAccessorComponent(isolate, setter),
33 static_cast<PropertyAttributes>(attribute->value())),
34 Object);
35 return object;
36 }
37
38
39 MaybeHandle<Object> AddPropertyForTemplate(Isolate* isolate,
40 Handle<JSObject> object,
41 Handle<Object> key,
42 Handle<Object> value,
43 Smi* unchecked_attributes) {
44 DCHECK((unchecked_attributes->value() &
45 ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
46 // Compute attributes.
47 PropertyAttributes attributes =
48 static_cast<PropertyAttributes>(unchecked_attributes->value());
49
50 #ifdef DEBUG
51 bool duplicate;
52 if (key->IsName()) {
53 LookupIterator it(object, Handle<Name>::cast(key),
54 LookupIterator::OWN_SKIP_INTERCEPTOR);
55 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
56 DCHECK(maybe.has_value);
57 duplicate = it.IsFound();
58 } else {
59 uint32_t index = 0;
60 key->ToArrayIndex(&index);
61 Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index);
62 if (!maybe.has_value) return MaybeHandle<Object>();
63 duplicate = maybe.value;
64 }
65 if (duplicate) {
66 Handle<Object> args[1] = {key};
67 THROW_NEW_ERROR(isolate, NewTypeError("duplicate_template_property",
68 HandleVector(args, 1)),
69 Object);
70 }
71 #endif
72
73 RETURN_ON_EXCEPTION(
74 isolate, Runtime::DefineObjectProperty(object, key, value, attributes),
75 Object);
76 return object;
77 }
78
79
80 void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
81 Handle<Map> old_map(object->map());
82 // Copy map so it won't interfere constructor's initial map.
83 Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
84 new_map->set_is_access_check_needed(false);
85 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
86 }
87
88
89 void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
90 Handle<Map> old_map(object->map());
91 // Copy map so it won't interfere constructor's initial map.
92 Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
93 new_map->set_is_access_check_needed(true);
94 JSObject::MigrateToMap(object, new_map);
95 }
96
97
98 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
99 Handle<ObjectTemplateInfo> data);
100
101
102 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
103 Handle<FunctionTemplateInfo> data,
104 Handle<Name> name = Handle<Name>());
105
106
107 MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data,
108 Handle<Name> name = Handle<Name>()) {
109 if (data->IsFunctionTemplateInfo()) {
110 return InstantiateFunction(isolate,
111 Handle<FunctionTemplateInfo>::cast(data), name);
112 } else if (data->IsObjectTemplateInfo()) {
113 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data));
114 } else {
115 // TODO(dcarney): CHECK data is JSObject or Primitive.
116 return data;
117 }
118 }
119
120
121 class AccessCheckDisableScope {
122 public:
123 AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
124 : isolate_(isolate),
125 disabled_(obj->map()->is_access_check_needed()),
126 obj_(obj) {
127 if (disabled_) {
128 DisableAccessChecks(isolate_, obj_);
129 }
130 }
131 ~AccessCheckDisableScope() {
132 if (disabled_) {
133 EnableAccessChecks(isolate_, obj_);
134 }
135 }
136
137 private:
138 Isolate* isolate_;
139 const bool disabled_;
140 Handle<JSObject> obj_;
141 };
142
143
144 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
145 Handle<TemplateInfo> data) {
146 auto property_list = handle(data->property_list(), isolate);
147 if (property_list->IsUndefined()) return obj;
148 // TODO(dcarney): just use a FixedArray here.
149 NeanderArray properties(property_list);
150 if (properties.length() == 0) return obj;
151 HandleScope scope(isolate);
152 // Disable access checks while instantiating the object.
153 AccessCheckDisableScope access_check_scope(isolate, obj);
154 for (int i = 0; i < properties.length();) {
155 int length = Smi::cast(properties.get(i))->value();
156 if (length == 3) {
157 auto name = handle(Name::cast(properties.get(i + 1)), isolate);
158 auto prop_data = handle(properties.get(i + 2), isolate);
159 auto attributes = Smi::cast(properties.get(i + 3));
160 Handle<Object> value;
161 ASSIGN_RETURN_ON_EXCEPTION(
162 isolate, value, Instantiate(isolate, prop_data, name), JSObject);
163 RETURN_ON_EXCEPTION(isolate, AddPropertyForTemplate(isolate, obj, name,
164 value, attributes),
165 JSObject);
166 } else {
167 DCHECK(length == 4 || length == 5);
168 // TODO(verwaest): The 5th value used to be access_control. Remove once
169 // the bindings are updated.
170 auto name = handle(Name::cast(properties.get(i + 1)), isolate);
171 auto getter = handle(properties.get(i + 2), isolate);
172 auto setter = handle(properties.get(i + 3), isolate);
173 auto attributes = Smi::cast(properties.get(i + 4));
174 RETURN_ON_EXCEPTION(isolate,
175 DefineApiAccessorProperty(isolate, obj, name, getter,
176 setter, attributes),
177 JSObject);
178 }
179 i += length + 1;
180 }
181 return obj;
182 }
183
184
185 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
186 Handle<ObjectTemplateInfo> data) {
187 // Enter a new scope. Recursion could otherwise create a lot of handles.
188 HandleScope scope(isolate);
189 // Fast path.
190 Handle<JSObject> result;
191 auto info = Handle<ObjectTemplateInfo>::cast(data);
192 auto constructor = handle(info->constructor(), isolate);
193 Handle<JSFunction> cons;
194 if (constructor->IsUndefined()) {
195 cons = isolate->object_function();
196 } else {
197 auto cons_templ = Handle<FunctionTemplateInfo>::cast(constructor);
198 ASSIGN_RETURN_ON_EXCEPTION(
199 isolate, cons, InstantiateFunction(isolate, cons_templ), JSFunction);
200 }
201 auto object = isolate->factory()->NewJSObject(cons);
202 ASSIGN_RETURN_ON_EXCEPTION(
203 isolate, result, ConfigureInstance(isolate, object, info), JSFunction);
204 // TODO(dcarney): is this necessary?
205 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
206 return scope.CloseAndEscape(result);
207 }
208
209
210 void InstallInCache(Isolate* isolate, int serial_number,
211 Handle<JSFunction> function) {
212 auto cache = isolate->function_cache();
213 if (cache->length() <= serial_number) {
214 int new_size;
215 if (isolate->next_serial_number() < 50) {
216 new_size = 100;
217 } else {
218 new_size = 3 * isolate->next_serial_number() / 2;
219 }
220 cache = FixedArray::CopySize(cache, new_size);
221 isolate->native_context()->set_function_cache(*cache);
222 }
223 cache->set(serial_number, *function);
224 }
225
226
227 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
228 Handle<FunctionTemplateInfo> data,
229 Handle<Name> name) {
230 int serial_number = Smi::cast(data->serial_number())->value();
231 // Probe cache.
232 if (!data->do_not_cache()) {
233 auto cache = isolate->function_cache();
234 // Fast case: see if the function has already been instantiated
235 if (serial_number < cache->length()) {
236 Handle<Object> element = FixedArray::get(cache, serial_number);
237 if (element->IsJSFunction()) {
238 return Handle<JSFunction>::cast(element);
239 }
240 }
241 }
242 // Enter a new scope. Recursion could otherwise create a lot of handles.
243 HandleScope scope(isolate);
244 Handle<JSObject> prototype;
245 if (!data->remove_prototype()) {
246 auto prototype_templ = handle(data->prototype_template(), isolate);
247 if (prototype_templ->IsUndefined()) {
248 prototype = isolate->factory()->NewJSObject(isolate->object_function());
249 } else {
250 ASSIGN_RETURN_ON_EXCEPTION(
251 isolate, prototype,
252 InstantiateObject(isolate,
253 Handle<ObjectTemplateInfo>::cast(prototype_templ)),
254 JSFunction);
255 }
256 auto parent = handle(data->parent_template(), isolate);
257 if (!parent->IsUndefined()) {
258 Handle<JSFunction> parent_instance;
259 ASSIGN_RETURN_ON_EXCEPTION(
260 isolate, parent_instance,
261 InstantiateFunction(isolate,
262 Handle<FunctionTemplateInfo>::cast(parent)),
263 JSFunction);
264 // TODO(dcarney): decide what to do here.
265 Handle<Object> parent_prototype;
266 ASSIGN_RETURN_ON_EXCEPTION(
267 isolate, parent_prototype,
268 JSObject::GetProperty(parent_instance,
269 isolate->factory()->prototype_string()),
270 JSFunction);
271 RETURN_ON_EXCEPTION(
272 isolate, JSObject::SetPrototype(prototype, parent_prototype, false),
273 JSFunction);
274 }
275 }
276 auto function = ApiNatives::CreateApiFunction(
277 isolate, data, prototype, ApiNatives::JavaScriptObjectType);
278 if (!name.is_null() && name->IsString()) {
279 function->shared()->set_name(*name);
280 }
281 if (!data->do_not_cache()) {
282 // Cache the function to limit recursion.
283 InstallInCache(isolate, serial_number, function);
284 }
285 auto result = ConfigureInstance(isolate, function, data);
286 if (result.is_null()) {
287 // uncache on error.
288 if (!data->do_not_cache()) {
289 auto cache = isolate->function_cache();
290 cache->set(serial_number, isolate->heap()->undefined_value());
291 }
292 return MaybeHandle<JSFunction>();
293 }
294 return scope.CloseAndEscape(function);
295 }
296
297
298 class InvokeScope {
299 public:
300 explicit InvokeScope(Isolate* isolate)
301 : isolate_(isolate), save_context_(isolate) {}
302 ~InvokeScope() {
303 bool has_exception = isolate_->has_pending_exception();
304 if (has_exception) {
305 isolate_->ReportPendingMessages();
306 } else {
307 isolate_->clear_pending_message();
308 }
309 }
310
311 private:
312 Isolate* isolate_;
313 SaveContext save_context_;
314 };
315
316 } // namespace
317
318
319 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
320 Handle<FunctionTemplateInfo> data) {
321 Isolate* isolate = data->GetIsolate();
322 InvokeScope invoke_scope(isolate);
323 return ::v8::internal::InstantiateFunction(isolate, data);
324 }
325
326
327 MaybeHandle<JSObject> ApiNatives::InstantiateObject(
328 Handle<ObjectTemplateInfo> data) {
329 Isolate* isolate = data->GetIsolate();
330 InvokeScope invoke_scope(isolate);
331 return ::v8::internal::InstantiateObject(isolate, data);
332 }
333
334
335 MaybeHandle<FunctionTemplateInfo> ApiNatives::ConfigureInstance(
336 Isolate* isolate, Handle<FunctionTemplateInfo> desc,
337 Handle<JSObject> instance) {
338 // Configure the instance by adding the properties specified by the
339 // instance template.
340 if (desc->instance_template()->IsUndefined()) return desc;
341 InvokeScope invoke_scope(isolate);
342 Handle<ObjectTemplateInfo> instance_template(
343 ObjectTemplateInfo::cast(desc->instance_template()), isolate);
344 RETURN_ON_EXCEPTION(isolate, ::v8::internal::ConfigureInstance(
345 isolate, instance, instance_template),
346 FunctionTemplateInfo);
347 return desc;
348 }
349
350
351 Handle<JSFunction> ApiNatives::CreateApiFunction(
352 Isolate* isolate, Handle<FunctionTemplateInfo> obj,
353 Handle<Object> prototype, ApiInstanceType instance_type) {
354 Handle<Code> code = isolate->builtins()->HandleApiCall();
355 Handle<Code> construct_stub = isolate->builtins()->JSConstructStubApi();
356
357 obj->set_instantiated(true);
358 Handle<JSFunction> result;
359 if (obj->remove_prototype()) {
360 result = isolate->factory()->NewFunctionWithoutPrototype(
361 isolate->factory()->empty_string(), code);
362 } else {
363 int internal_field_count = 0;
364 if (!obj->instance_template()->IsUndefined()) {
365 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
366 ObjectTemplateInfo::cast(obj->instance_template()));
367 internal_field_count =
368 Smi::cast(instance_template->internal_field_count())->value();
369 }
370
371 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
372 // JSObject::GetHeaderSize.
373 int instance_size = kPointerSize * internal_field_count;
374 InstanceType type;
375 switch (instance_type) {
376 case JavaScriptObjectType:
377 type = JS_OBJECT_TYPE;
378 instance_size += JSObject::kHeaderSize;
379 break;
380 case GlobalObjectType:
381 type = JS_GLOBAL_OBJECT_TYPE;
382 instance_size += JSGlobalObject::kSize;
383 break;
384 case GlobalProxyType:
385 type = JS_GLOBAL_PROXY_TYPE;
386 instance_size += JSGlobalProxy::kSize;
387 break;
388 default:
389 UNREACHABLE();
390 type = JS_OBJECT_TYPE; // Keep the compiler happy.
391 break;
392 }
393
394 result = isolate->factory()->NewFunction(
395 isolate->factory()->empty_string(), code, prototype, type,
396 instance_size, obj->read_only_prototype(), true);
397 }
398
399 result->shared()->set_length(obj->length());
400 Handle<Object> class_name(obj->class_name(), isolate);
401 if (class_name->IsString()) {
402 result->shared()->set_instance_class_name(*class_name);
403 result->shared()->set_name(*class_name);
404 }
405 result->shared()->set_function_data(*obj);
406 result->shared()->set_construct_stub(*construct_stub);
407 result->shared()->DontAdaptArguments();
408
409 if (obj->remove_prototype()) {
410 DCHECK(result->shared()->IsApiFunction());
411 DCHECK(!result->has_initial_map());
412 DCHECK(!result->has_prototype());
413 return result;
414 }
415
416 #ifdef DEBUG
417 LookupIterator it(handle(JSObject::cast(result->prototype())),
418 isolate->factory()->constructor_string(),
419 LookupIterator::OWN_SKIP_INTERCEPTOR);
420 MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
421 DCHECK(it.IsFound());
422 DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
423 #endif
424
425 // Down from here is only valid for API functions that can be used as a
426 // constructor (don't set the "remove prototype" flag).
427
428 Handle<Map> map(result->initial_map());
429
430 // Mark as undetectable if needed.
431 if (obj->undetectable()) {
432 map->set_is_undetectable();
433 }
434
435 // Mark as hidden for the __proto__ accessor if needed.
436 if (obj->hidden_prototype()) {
437 map->set_is_hidden_prototype();
438 }
439
440 // Mark as needs_access_check if needed.
441 if (obj->needs_access_check()) {
442 map->set_is_access_check_needed(true);
443 }
444
445 // Set interceptor information in the map.
446 if (!obj->named_property_handler()->IsUndefined()) {
447 map->set_has_named_interceptor();
448 }
449 if (!obj->indexed_property_handler()->IsUndefined()) {
450 map->set_has_indexed_interceptor();
451 }
452
453 // Set instance call-as-function information in the map.
454 if (!obj->instance_call_handler()->IsUndefined()) {
455 map->set_has_instance_call_handler();
456 }
457
458 // Recursively copy parent instance templates' accessors,
459 // 'data' may be modified.
460 int max_number_of_additional_properties = 0;
461 int max_number_of_static_properties = 0;
462 FunctionTemplateInfo* info = *obj;
463 while (true) {
464 if (!info->instance_template()->IsUndefined()) {
465 Object* props = ObjectTemplateInfo::cast(info->instance_template())
466 ->property_accessors();
467 if (!props->IsUndefined()) {
468 Handle<Object> props_handle(props, isolate);
469 NeanderArray props_array(props_handle);
470 max_number_of_additional_properties += props_array.length();
471 }
472 }
473 if (!info->property_accessors()->IsUndefined()) {
474 Object* props = info->property_accessors();
475 if (!props->IsUndefined()) {
476 Handle<Object> props_handle(props, isolate);
477 NeanderArray props_array(props_handle);
478 max_number_of_static_properties += props_array.length();
479 }
480 }
481 Object* parent = info->parent_template();
482 if (parent->IsUndefined()) break;
483 info = FunctionTemplateInfo::cast(parent);
484 }
485
486 Map::EnsureDescriptorSlack(map, max_number_of_additional_properties);
487
488 // Use a temporary FixedArray to acculumate static accessors
489 int valid_descriptors = 0;
490 Handle<FixedArray> array;
491 if (max_number_of_static_properties > 0) {
492 array = isolate->factory()->NewFixedArray(max_number_of_static_properties);
493 }
494
495 while (true) {
496 // Install instance descriptors
497 if (!obj->instance_template()->IsUndefined()) {
498 Handle<ObjectTemplateInfo> instance = Handle<ObjectTemplateInfo>(
499 ObjectTemplateInfo::cast(obj->instance_template()), isolate);
500 Handle<Object> props =
501 Handle<Object>(instance->property_accessors(), isolate);
502 if (!props->IsUndefined()) {
503 Map::AppendCallbackDescriptors(map, props);
504 }
505 }
506 // Accumulate static accessors
507 if (!obj->property_accessors()->IsUndefined()) {
508 Handle<Object> props = Handle<Object>(obj->property_accessors(), isolate);
509 valid_descriptors =
510 AccessorInfo::AppendUnique(props, array, valid_descriptors);
511 }
512 // Climb parent chain
513 Handle<Object> parent = Handle<Object>(obj->parent_template(), isolate);
514 if (parent->IsUndefined()) break;
515 obj = Handle<FunctionTemplateInfo>::cast(parent);
516 }
517
518 // Install accumulated static accessors
519 for (int i = 0; i < valid_descriptors; i++) {
520 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
521 JSObject::SetAccessor(result, accessor).Assert();
522 }
523
524 DCHECK(result->shared()->IsApiFunction());
525 return result;
526 }
527
528 } // namespace internal
529 } // namespace v8
OLDNEW
« no previous file with comments | « src/api-natives.h ('k') | src/apinatives.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698