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