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