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