Line data Source code
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 :
7 : #include "src/api-inl.h"
8 : #include "src/isolate-inl.h"
9 : #include "src/lookup.h"
10 : #include "src/message-template.h"
11 : #include "src/objects/api-callbacks.h"
12 : #include "src/objects/hash-table-inl.h"
13 : #include "src/objects/property-cell.h"
14 : #include "src/objects/templates.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 :
20 : namespace {
21 :
22 : class InvokeScope {
23 : public:
24 : explicit InvokeScope(Isolate* isolate)
25 2377934 : : isolate_(isolate), save_context_(isolate) {}
26 4755860 : ~InvokeScope() {
27 2377918 : bool has_exception = isolate_->has_pending_exception();
28 2377940 : if (has_exception) {
29 0 : isolate_->ReportPendingMessages();
30 : } else {
31 2377940 : isolate_->clear_pending_message();
32 : }
33 2377943 : }
34 :
35 : private:
36 : Isolate* isolate_;
37 : SaveContext save_context_;
38 : };
39 :
40 : MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
41 : Handle<ObjectTemplateInfo> data,
42 : Handle<JSReceiver> new_target,
43 : bool is_hidden_prototype,
44 : bool is_prototype);
45 :
46 : MaybeHandle<JSFunction> InstantiateFunction(
47 : Isolate* isolate, Handle<FunctionTemplateInfo> data,
48 : MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
49 :
50 2781959 : MaybeHandle<Object> Instantiate(
51 : Isolate* isolate, Handle<Object> data,
52 : MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
53 5563918 : if (data->IsFunctionTemplateInfo()) {
54 : return InstantiateFunction(
55 2250464 : isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
56 1062990 : } else if (data->IsObjectTemplateInfo()) {
57 : return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
58 415212 : Handle<JSReceiver>(), false, false);
59 : } else {
60 116283 : return data;
61 : }
62 : }
63 :
64 144 : MaybeHandle<Object> DefineAccessorProperty(
65 : Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
66 : Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
67 : bool force_instantiate) {
68 : DCHECK(!getter->IsFunctionTemplateInfo() ||
69 : !FunctionTemplateInfo::cast(*getter)->do_not_cache());
70 : DCHECK(!setter->IsFunctionTemplateInfo() ||
71 : !FunctionTemplateInfo::cast(*setter)->do_not_cache());
72 144 : if (force_instantiate) {
73 0 : if (getter->IsFunctionTemplateInfo()) {
74 0 : ASSIGN_RETURN_ON_EXCEPTION(
75 : isolate, getter,
76 : InstantiateFunction(isolate,
77 : Handle<FunctionTemplateInfo>::cast(getter)),
78 : Object);
79 : }
80 0 : if (setter->IsFunctionTemplateInfo()) {
81 0 : ASSIGN_RETURN_ON_EXCEPTION(
82 : isolate, setter,
83 : InstantiateFunction(isolate,
84 : Handle<FunctionTemplateInfo>::cast(setter)),
85 : Object);
86 : }
87 : }
88 288 : RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
89 : setter, attributes),
90 : Object);
91 144 : return object;
92 : }
93 :
94 :
95 2781959 : MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
96 : Handle<JSObject> object,
97 : Handle<Name> name,
98 : Handle<Object> prop_data,
99 : PropertyAttributes attributes) {
100 : Handle<Object> value;
101 5563918 : ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
102 : Instantiate(isolate, prop_data, name), Object);
103 :
104 : LookupIterator it = LookupIterator::PropertyOrElement(
105 2781959 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
106 :
107 : #ifdef DEBUG
108 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
109 : DCHECK(maybe.IsJust());
110 : if (it.IsFound()) {
111 : THROW_NEW_ERROR(
112 : isolate,
113 : NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
114 : Object);
115 : }
116 : #endif
117 :
118 2781959 : MAYBE_RETURN_NULL(Object::AddDataProperty(
119 : &it, value, attributes, kThrowOnError, StoreOrigin::kNamed));
120 2781959 : return value;
121 : }
122 :
123 :
124 232 : void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
125 : Handle<Map> old_map(object->map(), isolate);
126 : // Copy map so it won't interfere constructor's initial map.
127 232 : Handle<Map> new_map = Map::Copy(isolate, old_map, "DisableAccessChecks");
128 : new_map->set_is_access_check_needed(false);
129 232 : JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
130 232 : }
131 :
132 :
133 232 : void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
134 : Handle<Map> old_map(object->map(), isolate);
135 : // Copy map so it won't interfere constructor's initial map.
136 232 : Handle<Map> new_map = Map::Copy(isolate, old_map, "EnableAccessChecks");
137 : new_map->set_is_access_check_needed(true);
138 232 : new_map->set_may_have_interesting_symbols(true);
139 232 : JSObject::MigrateToMap(object, new_map);
140 232 : }
141 :
142 :
143 : class AccessCheckDisableScope {
144 : public:
145 4482950 : AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
146 : : isolate_(isolate),
147 : disabled_(obj->map()->is_access_check_needed()),
148 8965905 : obj_(obj) {
149 4482955 : if (disabled_) {
150 232 : DisableAccessChecks(isolate_, obj_);
151 : }
152 4482955 : }
153 : ~AccessCheckDisableScope() {
154 4482958 : if (disabled_) {
155 232 : EnableAccessChecks(isolate_, obj_);
156 : }
157 : }
158 :
159 : private:
160 : Isolate* isolate_;
161 : const bool disabled_;
162 : Handle<JSObject> obj_;
163 : };
164 :
165 60 : Object GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
166 60 : Handle<Context> native_context = isolate->native_context();
167 : DCHECK(!native_context.is_null());
168 60 : switch (intrinsic) {
169 : #define GET_INTRINSIC_VALUE(name, iname) \
170 : case v8::k##name: \
171 : return native_context->iname();
172 60 : V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
173 : #undef GET_INTRINSIC_VALUE
174 : }
175 0 : return Object();
176 : }
177 :
178 : template <typename TemplateInfoT>
179 4482955 : MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
180 : Handle<TemplateInfoT> data,
181 : bool is_hidden_prototype) {
182 : HandleScope scope(isolate);
183 : // Disable access checks while instantiating the object.
184 4482955 : AccessCheckDisableScope access_check_scope(isolate, obj);
185 :
186 : // Walk the inheritance chain and copy all accessors to current object.
187 : int max_number_of_properties = 0;
188 4482949 : TemplateInfoT info = *data;
189 13449288 : while (!info.is_null()) {
190 4483374 : Object props = info->property_accessors();
191 4483386 : if (!props->IsUndefined(isolate)) {
192 52023 : max_number_of_properties += TemplateList::cast(props)->length();
193 : }
194 4483386 : info = info->GetParent(isolate);
195 : }
196 :
197 4482965 : if (max_number_of_properties > 0) {
198 : int valid_descriptors = 0;
199 : // Use a temporary FixedArray to accumulate unique accessors.
200 : Handle<FixedArray> array =
201 52005 : isolate->factory()->NewFixedArray(max_number_of_properties);
202 :
203 104082 : for (Handle<TemplateInfoT> temp(*data, isolate); !temp->is_null();
204 104154 : temp = handle(temp->GetParent(isolate), isolate)) {
205 : // Accumulate accessors.
206 52077 : Object maybe_properties = temp->property_accessors();
207 52077 : if (!maybe_properties->IsUndefined(isolate)) {
208 52023 : valid_descriptors = AccessorInfo::AppendUnique(
209 : isolate, handle(maybe_properties, isolate), array,
210 : valid_descriptors);
211 : }
212 : }
213 :
214 : // Install accumulated accessors.
215 52296 : for (int i = 0; i < valid_descriptors; i++) {
216 : Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)), isolate);
217 104592 : Handle<Name> name(Name::cast(accessor->name()), isolate);
218 : JSObject::SetAccessor(obj, name, accessor,
219 104592 : accessor->initial_property_attributes())
220 52296 : .Assert();
221 : }
222 : }
223 :
224 4482939 : Object maybe_property_list = data->property_list();
225 4482958 : if (maybe_property_list->IsUndefined(isolate)) return obj;
226 : Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
227 : isolate);
228 367784 : if (properties->length() == 0) return obj;
229 :
230 : int i = 0;
231 5931990 : for (int c = 0; c < data->number_of_properties(); c++) {
232 8346309 : auto name = handle(Name::cast(properties->get(i++)), isolate);
233 5564206 : Object bit = properties->get(i++);
234 2782103 : if (bit->IsSmi()) {
235 : PropertyDetails details(Smi::cast(bit));
236 : PropertyAttributes attributes = details.attributes();
237 : PropertyKind kind = details.kind();
238 :
239 2782043 : if (kind == kData) {
240 8345697 : auto prop_data = handle(properties->get(i++), isolate);
241 5563798 : RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
242 : prop_data, attributes),
243 : JSObject);
244 : } else {
245 432 : auto getter = handle(properties->get(i++), isolate);
246 432 : auto setter = handle(properties->get(i++), isolate);
247 288 : RETURN_ON_EXCEPTION(
248 : isolate, DefineAccessorProperty(isolate, obj, name, getter, setter,
249 : attributes, is_hidden_prototype),
250 : JSObject);
251 : }
252 : } else {
253 : // Intrinsic data property --- Get appropriate value from the current
254 : // context.
255 180 : PropertyDetails details(Smi::cast(properties->get(i++)));
256 : PropertyAttributes attributes = details.attributes();
257 : DCHECK_EQ(kData, details.kind());
258 :
259 : v8::Intrinsic intrinsic =
260 120 : static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
261 120 : auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
262 :
263 120 : RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
264 : prop_data, attributes),
265 : JSObject);
266 : }
267 : }
268 367784 : return obj;
269 : }
270 :
271 : // Whether or not to cache every instance: when we materialize a getter or
272 : // setter from an lazy AccessorPair, we rely on this cache to be able to always
273 : // return the same getter or setter. However, objects will be cloned anyways,
274 : // so it's not observable if we didn't cache an instance. Furthermore, a badly
275 : // behaved embedder might create an unlimited number of objects, so we limit
276 : // the cache for those cases.
277 : enum class CachingMode { kLimited, kUnlimited };
278 :
279 4822445 : MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
280 : int serial_number,
281 : CachingMode caching_mode) {
282 : DCHECK_LE(1, serial_number);
283 4822445 : if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
284 : Handle<FixedArray> fast_cache =
285 4744851 : isolate->fast_template_instantiations_cache();
286 9489704 : return fast_cache->GetValue<JSObject>(isolate, serial_number - 1);
287 155188 : } else if (caching_mode == CachingMode::kUnlimited ||
288 77594 : (serial_number <=
289 : TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
290 : Handle<SimpleNumberDictionary> slow_cache =
291 77594 : isolate->slow_template_instantiations_cache();
292 155188 : int entry = slow_cache->FindEntry(isolate, serial_number);
293 77594 : if (entry == SimpleNumberDictionary::kNotFound) {
294 74527 : return MaybeHandle<JSObject>();
295 : }
296 6134 : return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
297 : } else {
298 0 : return MaybeHandle<JSObject>();
299 : }
300 : }
301 :
302 3988203 : void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
303 : CachingMode caching_mode,
304 : Handle<JSObject> object) {
305 : DCHECK_LE(1, serial_number);
306 3988203 : if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
307 : Handle<FixedArray> fast_cache =
308 3913694 : isolate->fast_template_instantiations_cache();
309 : Handle<FixedArray> new_cache =
310 3913695 : FixedArray::SetAndGrow(isolate, fast_cache, serial_number - 1, object);
311 3913692 : if (*new_cache != *fast_cache) {
312 0 : isolate->native_context()->set_fast_template_instantiations_cache(
313 0 : *new_cache);
314 : }
315 149018 : } else if (caching_mode == CachingMode::kUnlimited ||
316 74509 : (serial_number <=
317 : TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
318 : Handle<SimpleNumberDictionary> cache =
319 74509 : isolate->slow_template_instantiations_cache();
320 : auto new_cache =
321 74509 : SimpleNumberDictionary::Set(isolate, cache, serial_number, object);
322 74509 : if (*new_cache != *cache) {
323 0 : isolate->native_context()->set_slow_template_instantiations_cache(
324 0 : *new_cache);
325 : }
326 : }
327 3988201 : }
328 :
329 0 : void UncacheTemplateInstantiation(Isolate* isolate, int serial_number,
330 : CachingMode caching_mode) {
331 : DCHECK_LE(1, serial_number);
332 0 : if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
333 : Handle<FixedArray> fast_cache =
334 0 : isolate->fast_template_instantiations_cache();
335 : DCHECK(!fast_cache->get(serial_number - 1)->IsUndefined(isolate));
336 0 : fast_cache->set_undefined(serial_number - 1);
337 0 : } else if (caching_mode == CachingMode::kUnlimited ||
338 0 : (serial_number <=
339 : TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
340 : Handle<SimpleNumberDictionary> cache =
341 0 : isolate->slow_template_instantiations_cache();
342 0 : int entry = cache->FindEntry(isolate, serial_number);
343 : DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
344 0 : cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry);
345 0 : isolate->native_context()->set_slow_template_instantiations_cache(*cache);
346 : }
347 0 : }
348 :
349 332840 : bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo info,
350 : JSReceiver new_target) {
351 : DisallowHeapAllocation no_gc;
352 :
353 332841 : if (!new_target->IsJSFunction()) return false;
354 332840 : JSFunction fun = JSFunction::cast(new_target);
355 665684 : if (fun->shared()->function_data() != info->constructor()) return false;
356 2889 : if (info->immutable_proto()) return false;
357 5766 : return fun->context()->native_context() == isolate->raw_native_context();
358 : }
359 :
360 965118 : MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
361 : Handle<ObjectTemplateInfo> info,
362 : Handle<JSReceiver> new_target,
363 : bool is_hidden_prototype,
364 : bool is_prototype) {
365 : Handle<JSFunction> constructor;
366 965127 : int serial_number = Smi::ToInt(info->serial_number());
367 965134 : if (!new_target.is_null()) {
368 332841 : if (IsSimpleInstantiation(isolate, *info, *new_target)) {
369 2883 : constructor = Handle<JSFunction>::cast(new_target);
370 : } else {
371 : // Disable caching for subclass instantiation.
372 : serial_number = 0;
373 : }
374 : }
375 : // Fast path.
376 : Handle<JSObject> result;
377 965138 : if (serial_number) {
378 476284 : if (ProbeInstantiationsCache(isolate, serial_number, CachingMode::kLimited)
379 952568 : .ToHandle(&result)) {
380 209714 : return isolate->factory()->CopyJSObject(result);
381 : }
382 : }
383 :
384 755424 : if (constructor.is_null()) {
385 753858 : Object maybe_constructor_info = info->constructor();
386 753859 : if (maybe_constructor_info->IsUndefined(isolate)) {
387 587166 : constructor = isolate->object_function();
388 : } else {
389 : // Enter a new scope. Recursion could otherwise create a lot of handles.
390 : HandleScope scope(isolate);
391 : Handle<FunctionTemplateInfo> cons_templ(
392 : FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
393 : Handle<JSFunction> tmp_constructor;
394 333386 : ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
395 : InstantiateFunction(isolate, cons_templ),
396 : JSObject);
397 166693 : constructor = scope.CloseAndEscape(tmp_constructor);
398 : }
399 :
400 753858 : if (new_target.is_null()) new_target = constructor;
401 : }
402 :
403 : Handle<JSObject> object;
404 1510846 : ASSIGN_RETURN_ON_EXCEPTION(
405 : isolate, object,
406 : JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
407 : JSObject);
408 :
409 755422 : if (is_prototype) JSObject::OptimizeAsPrototype(object);
410 :
411 1510820 : ASSIGN_RETURN_ON_EXCEPTION(
412 : isolate, result,
413 : ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject);
414 755401 : if (info->immutable_proto()) {
415 24 : JSObject::SetImmutableProto(object);
416 : }
417 755413 : if (!is_prototype) {
418 : // Keep prototypes in slow-mode. Let them be lazily turned fast later on.
419 : // TODO(dcarney): is this necessary?
420 649464 : JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
421 : // Don't cache prototypes.
422 649452 : if (serial_number) {
423 : CacheTemplateInstantiation(isolate, serial_number, CachingMode::kLimited,
424 265854 : result);
425 265854 : result = isolate->factory()->CopyJSObject(result);
426 : }
427 : }
428 :
429 755401 : return result;
430 : }
431 :
432 : namespace {
433 249 : MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
434 : Object function_template) {
435 : // Enter a new scope. Recursion could otherwise create a lot of handles.
436 : HandleScope scope(isolate);
437 : Handle<JSFunction> parent_instance;
438 747 : ASSIGN_RETURN_ON_EXCEPTION(
439 : isolate, parent_instance,
440 : InstantiateFunction(
441 : isolate,
442 : handle(FunctionTemplateInfo::cast(function_template), isolate)),
443 : JSFunction);
444 : Handle<Object> instance_prototype;
445 : // TODO(cbruni): decide what to do here.
446 498 : ASSIGN_RETURN_ON_EXCEPTION(
447 : isolate, instance_prototype,
448 : JSObject::GetProperty(isolate, parent_instance,
449 : isolate->factory()->prototype_string()),
450 : JSFunction);
451 249 : return scope.CloseAndEscape(instance_prototype);
452 : }
453 : } // namespace
454 :
455 4351349 : MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
456 : Handle<FunctionTemplateInfo> data,
457 : MaybeHandle<Name> maybe_name) {
458 4351349 : int serial_number = Smi::ToInt(data->serial_number());
459 4351351 : if (serial_number) {
460 : Handle<JSObject> result;
461 4346161 : if (ProbeInstantiationsCache(isolate, serial_number,
462 : CachingMode::kUnlimited)
463 8692323 : .ToHandle(&result)) {
464 623810 : return Handle<JSFunction>::cast(result);
465 : }
466 : }
467 : Handle<Object> prototype;
468 3727540 : if (!data->remove_prototype()) {
469 3722684 : Object prototype_templ = data->GetPrototypeTemplate();
470 3722682 : if (prototype_templ->IsUndefined(isolate)) {
471 3616733 : Object protoype_provider_templ = data->GetPrototypeProviderTemplate();
472 3616734 : if (protoype_provider_templ->IsUndefined(isolate)) {
473 3616729 : prototype = isolate->factory()->NewJSObject(isolate->object_function());
474 : } else {
475 10 : ASSIGN_RETURN_ON_EXCEPTION(
476 : isolate, prototype,
477 : GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
478 : }
479 : } else {
480 317847 : ASSIGN_RETURN_ON_EXCEPTION(
481 : isolate, prototype,
482 : InstantiateObject(
483 : isolate,
484 : handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
485 : Handle<JSReceiver>(), data->hidden_prototype(), true),
486 : JSFunction);
487 : }
488 3722679 : Object parent = data->GetParentTemplate();
489 3722682 : if (!parent->IsUndefined(isolate)) {
490 : Handle<Object> parent_prototype;
491 488 : ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
492 : GetInstancePrototype(isolate, parent),
493 : JSFunction);
494 : JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
495 244 : parent_prototype);
496 : }
497 : }
498 : InstanceType function_type =
499 11182382 : (!data->needs_access_check() &&
500 11181176 : data->GetNamedPropertyHandler()->IsUndefined(isolate) &&
501 7453870 : data->GetIndexedPropertyHandler()->IsUndefined(isolate))
502 : ? JS_API_OBJECT_TYPE
503 3727538 : : JS_SPECIAL_API_OBJECT_TYPE;
504 :
505 : Handle<JSFunction> function = ApiNatives::CreateApiFunction(
506 3727538 : isolate, data, prototype, function_type, maybe_name);
507 3727540 : if (serial_number) {
508 : // Cache the function.
509 : CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
510 3722350 : function);
511 : }
512 : MaybeHandle<JSObject> result =
513 7455073 : ConfigureInstance(isolate, function, data, data->hidden_prototype());
514 3727539 : if (result.is_null()) {
515 : // Uncache on error.
516 0 : if (serial_number) {
517 : UncacheTemplateInstantiation(isolate, serial_number,
518 0 : CachingMode::kUnlimited);
519 : }
520 0 : return MaybeHandle<JSFunction>();
521 : }
522 3727539 : return function;
523 : }
524 :
525 :
526 1956653 : void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
527 : int length, Handle<Object>* data) {
528 1956653 : Object maybe_list = templ->property_list();
529 : Handle<TemplateList> list;
530 1956653 : if (maybe_list->IsUndefined(isolate)) {
531 313721 : list = TemplateList::New(isolate, length);
532 : } else {
533 : list = handle(TemplateList::cast(maybe_list), isolate);
534 : }
535 1956653 : templ->set_number_of_properties(templ->number_of_properties() + 1);
536 7826776 : for (int i = 0; i < length; i++) {
537 : Handle<Object> value =
538 5870123 : data[i].is_null()
539 : ? Handle<Object>::cast(isolate->factory()->undefined_value())
540 5870182 : : data[i];
541 5870123 : list = TemplateList::Add(isolate, list, value);
542 : }
543 3913306 : templ->set_property_list(*list);
544 1956653 : }
545 :
546 : } // namespace
547 :
548 1933944 : MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
549 : Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
550 : Isolate* isolate = data->GetIsolate();
551 : InvokeScope invoke_scope(isolate);
552 1933945 : return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
553 : }
554 :
555 443965 : MaybeHandle<JSObject> ApiNatives::InstantiateObject(
556 : Isolate* isolate, Handle<ObjectTemplateInfo> data,
557 : Handle<JSReceiver> new_target) {
558 : InvokeScope invoke_scope(isolate);
559 : return ::v8::internal::InstantiateObject(isolate, data, new_target, false,
560 443972 : false);
561 : }
562 :
563 26 : MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
564 : Handle<ObjectTemplateInfo> data) {
565 : Isolate* isolate = data->GetIsolate();
566 : InvokeScope invoke_scope(isolate);
567 :
568 : Handle<FunctionTemplateInfo> constructor(
569 52 : FunctionTemplateInfo::cast(data->constructor()), isolate);
570 : Handle<Map> object_map = isolate->factory()->NewMap(
571 : JS_SPECIAL_API_OBJECT_TYPE,
572 : JSObject::kHeaderSize +
573 52 : data->embedder_field_count() * kEmbedderDataSlotSize,
574 26 : TERMINAL_FAST_ELEMENTS_KIND);
575 52 : object_map->SetConstructor(*constructor);
576 : object_map->set_is_access_check_needed(true);
577 26 : object_map->set_may_have_interesting_symbols(true);
578 :
579 26 : Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(object_map);
580 26 : JSObject::ForceSetPrototype(object, isolate->factory()->null_value());
581 :
582 26 : return object;
583 : }
584 :
585 1956489 : void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
586 : Handle<Name> name, Handle<Object> value,
587 : PropertyAttributes attributes) {
588 : PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
589 : auto details_handle = handle(details.AsSmi(), isolate);
590 1956489 : Handle<Object> data[] = {name, details_handle, value};
591 1956489 : AddPropertyToPropertyList(isolate, info, arraysize(data), data);
592 1956489 : }
593 :
594 :
595 55 : void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
596 : Handle<Name> name, v8::Intrinsic intrinsic,
597 : PropertyAttributes attributes) {
598 55 : auto value = handle(Smi::FromInt(intrinsic), isolate);
599 : auto intrinsic_marker = isolate->factory()->true_value();
600 : PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
601 : auto details_handle = handle(details.AsSmi(), isolate);
602 : Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
603 55 : AddPropertyToPropertyList(isolate, info, arraysize(data), data);
604 55 : }
605 :
606 :
607 109 : void ApiNatives::AddAccessorProperty(Isolate* isolate,
608 : Handle<TemplateInfo> info,
609 : Handle<Name> name,
610 : Handle<FunctionTemplateInfo> getter,
611 : Handle<FunctionTemplateInfo> setter,
612 : PropertyAttributes attributes) {
613 : PropertyDetails details(kAccessor, attributes, PropertyCellType::kNoCell);
614 : auto details_handle = handle(details.AsSmi(), isolate);
615 : Handle<Object> data[] = {name, details_handle, getter, setter};
616 109 : AddPropertyToPropertyList(isolate, info, arraysize(data), data);
617 109 : }
618 :
619 :
620 52207 : void ApiNatives::AddNativeDataProperty(Isolate* isolate,
621 : Handle<TemplateInfo> info,
622 : Handle<AccessorInfo> property) {
623 52207 : Object maybe_list = info->property_accessors();
624 : Handle<TemplateList> list;
625 52207 : if (maybe_list->IsUndefined(isolate)) {
626 51958 : list = TemplateList::New(isolate, 1);
627 : } else {
628 : list = handle(TemplateList::cast(maybe_list), isolate);
629 : }
630 52207 : list = TemplateList::Add(isolate, list, property);
631 104414 : info->set_property_accessors(*list);
632 52207 : }
633 :
634 3836165 : Handle<JSFunction> ApiNatives::CreateApiFunction(
635 : Isolate* isolate, Handle<FunctionTemplateInfo> obj,
636 : Handle<Object> prototype, InstanceType type, MaybeHandle<Name> maybe_name) {
637 : Handle<SharedFunctionInfo> shared =
638 : FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
639 3836165 : maybe_name);
640 : // To simplify things, API functions always have shared name.
641 : DCHECK(shared->HasSharedName());
642 :
643 : Handle<JSFunction> result =
644 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
645 7672335 : shared, isolate->native_context());
646 :
647 3836167 : if (obj->remove_prototype()) {
648 : DCHECK(prototype.is_null());
649 : DCHECK(result->shared()->IsApiFunction());
650 : DCHECK(!result->IsConstructor());
651 : DCHECK(!result->has_prototype_slot());
652 4856 : return result;
653 : }
654 :
655 : // Down from here is only valid for API functions that can be used as a
656 : // constructor (don't set the "remove prototype" flag).
657 : DCHECK(result->has_prototype_slot());
658 :
659 3831311 : if (obj->read_only_prototype()) {
660 3948162 : result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
661 : }
662 :
663 7662622 : if (prototype->IsTheHole(isolate)) {
664 108628 : prototype = isolate->factory()->NewFunctionPrototype(result);
665 7445365 : } else if (obj->GetPrototypeProviderTemplate()->IsUndefined(isolate)) {
666 : JSObject::AddProperty(isolate, Handle<JSObject>::cast(prototype),
667 : isolate->factory()->constructor_string(), result,
668 3722676 : DONT_ENUM);
669 : }
670 :
671 : int embedder_field_count = 0;
672 : bool immutable_proto = false;
673 7662621 : if (!obj->GetInstanceTemplate()->IsUndefined(isolate)) {
674 : Handle<ObjectTemplateInfo> GetInstanceTemplate = Handle<ObjectTemplateInfo>(
675 541134 : ObjectTemplateInfo::cast(obj->GetInstanceTemplate()), isolate);
676 270567 : embedder_field_count = GetInstanceTemplate->embedder_field_count();
677 270567 : immutable_proto = GetInstanceTemplate->immutable_proto();
678 : }
679 :
680 : // JS_FUNCTION_TYPE requires information about the prototype slot.
681 : DCHECK_NE(JS_FUNCTION_TYPE, type);
682 3831312 : int instance_size = JSObject::GetHeaderSize(type) +
683 3831310 : kEmbedderDataSlotSize * embedder_field_count;
684 :
685 : Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
686 3831310 : TERMINAL_FAST_ELEMENTS_KIND);
687 7662620 : JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
688 :
689 : // Mark as undetectable if needed.
690 3831309 : if (obj->undetectable()) {
691 : // We only allow callable undetectable receivers here, since this whole
692 : // undetectable business is only to support document.all, which is both
693 : // undetectable and callable. If we ever see the need to have an object
694 : // that is undetectable but not callable, we need to update the types.h
695 : // to allow encoding this.
696 304 : CHECK(!obj->GetInstanceCallHandler()->IsUndefined(isolate));
697 : map->set_is_undetectable(true);
698 : }
699 :
700 : // Mark as needs_access_check if needed.
701 3831309 : if (obj->needs_access_check()) {
702 : map->set_is_access_check_needed(true);
703 355 : map->set_may_have_interesting_symbols(true);
704 : }
705 :
706 : // Set interceptor information in the map.
707 7662621 : if (!obj->GetNamedPropertyHandler()->IsUndefined(isolate)) {
708 : map->set_has_named_interceptor(true);
709 1118 : map->set_may_have_interesting_symbols(true);
710 : }
711 7662622 : if (!obj->GetIndexedPropertyHandler()->IsUndefined(isolate)) {
712 : map->set_has_indexed_interceptor(true);
713 : }
714 :
715 : // Mark instance as callable in the map.
716 7662624 : if (!obj->GetInstanceCallHandler()->IsUndefined(isolate)) {
717 : map->set_is_callable(true);
718 402 : map->set_is_constructor(!obj->undetectable());
719 : }
720 :
721 3831330 : if (immutable_proto) map->set_is_immutable_proto(true);
722 :
723 3831312 : return result;
724 : }
725 :
726 : } // namespace internal
727 183867 : } // namespace v8
|