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