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