Home | History | Annotate | Download | only in src
      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:
     20   explicit InvokeScope(Isolate* isolate)
     21       : isolate_(isolate), save_context_(isolate) {}
     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 
     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 
     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 
     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 
    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 
    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:
    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   }
    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 
    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>
    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 
    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 
    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 
    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 
    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 
    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 namespace {
    399 MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
    400                                          Object* function_template) {
    401   // Enter a new scope.  Recursion could otherwise create a lot of handles.
    402   HandleScope scope(isolate);
    403   Handle<JSFunction> parent_instance;
    404   ASSIGN_RETURN_ON_EXCEPTION(
    405       isolate, parent_instance,
    406       InstantiateFunction(
    407           isolate,
    408           handle(FunctionTemplateInfo::cast(function_template), isolate)),
    409       JSFunction);
    410   Handle<Object> instance_prototype;
    411   // TODO(cbruni): decide what to do here.
    412   ASSIGN_RETURN_ON_EXCEPTION(
    413       isolate, instance_prototype,
    414       JSObject::GetProperty(parent_instance,
    415                             isolate->factory()->prototype_string()),
    416       JSFunction);
    417   return scope.CloseAndEscape(instance_prototype);
    418 }
    419 }  // namespace
    420 
    421 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
    422                                             Handle<FunctionTemplateInfo> data,
    423                                             Handle<Name> name) {
    424   int serial_number = Smi::cast(data->serial_number())->value();
    425   if (serial_number) {
    426     Handle<JSObject> result;
    427     if (ProbeInstantiationsCache(isolate, serial_number).ToHandle(&result)) {
    428       return Handle<JSFunction>::cast(result);
    429     }
    430   }
    431   Handle<Object> prototype;
    432   if (!data->remove_prototype()) {
    433     Object* prototype_templ = data->prototype_template();
    434     if (prototype_templ->IsUndefined(isolate)) {
    435       Object* protoype_provider_templ = data->prototype_provider_template();
    436       if (protoype_provider_templ->IsUndefined(isolate)) {
    437         prototype = isolate->factory()->NewJSObject(isolate->object_function());
    438       } else {
    439         ASSIGN_RETURN_ON_EXCEPTION(
    440             isolate, prototype,
    441             GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
    442       }
    443     } else {
    444       ASSIGN_RETURN_ON_EXCEPTION(
    445           isolate, prototype,
    446           InstantiateObject(
    447               isolate,
    448               handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
    449               Handle<JSReceiver>(), data->hidden_prototype()),
    450           JSFunction);
    451     }
    452     Object* parent = data->parent_template();
    453     if (!parent->IsUndefined(isolate)) {
    454       Handle<Object> parent_prototype;
    455       ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
    456                                  GetInstancePrototype(isolate, parent),
    457                                  JSFunction);
    458       JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
    459                                   parent_prototype);
    460     }
    461   }
    462   Handle<JSFunction> function = ApiNatives::CreateApiFunction(
    463       isolate, data, prototype, ApiNatives::JavaScriptObjectType);
    464   if (!name.is_null() && name->IsString()) {
    465     function->shared()->set_name(*name);
    466   }
    467   if (serial_number) {
    468     // Cache the function.
    469     CacheTemplateInstantiation(isolate, serial_number, function);
    470   }
    471   MaybeHandle<JSObject> result =
    472       ConfigureInstance(isolate, function, data, data->hidden_prototype());
    473   if (result.is_null()) {
    474     // Uncache on error.
    475     if (serial_number) {
    476       UncacheTemplateInstantiation(isolate, serial_number);
    477     }
    478     return MaybeHandle<JSFunction>();
    479   }
    480   return function;
    481 }
    482 
    483 
    484 void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
    485                                int length, Handle<Object>* data) {
    486   Object* maybe_list = templ->property_list();
    487   Handle<TemplateList> list;
    488   if (maybe_list->IsUndefined(isolate)) {
    489     list = TemplateList::New(isolate, length);
    490   } else {
    491     list = handle(TemplateList::cast(maybe_list), isolate);
    492   }
    493   templ->set_number_of_properties(templ->number_of_properties() + 1);
    494   for (int i = 0; i < length; i++) {
    495     Handle<Object> value =
    496         data[i].is_null()
    497             ? Handle<Object>::cast(isolate->factory()->undefined_value())
    498             : data[i];
    499     list = TemplateList::Add(isolate, list, value);
    500   }
    501   templ->set_property_list(*list);
    502 }
    503 
    504 }  // namespace
    505 
    506 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
    507     Handle<FunctionTemplateInfo> data) {
    508   Isolate* isolate = data->GetIsolate();
    509   InvokeScope invoke_scope(isolate);
    510   return ::v8::internal::InstantiateFunction(isolate, data);
    511 }
    512 
    513 MaybeHandle<JSObject> ApiNatives::InstantiateObject(
    514     Handle<ObjectTemplateInfo> data, Handle<JSReceiver> new_target) {
    515   Isolate* isolate = data->GetIsolate();
    516   InvokeScope invoke_scope(isolate);
    517   return ::v8::internal::InstantiateObject(isolate, data, new_target, false);
    518 }
    519 
    520 MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
    521     Handle<ObjectTemplateInfo> data) {
    522   Isolate* isolate = data->GetIsolate();
    523   InvokeScope invoke_scope(isolate);
    524 
    525   Handle<FunctionTemplateInfo> constructor(
    526       FunctionTemplateInfo::cast(data->constructor()));
    527   Handle<SharedFunctionInfo> shared =
    528       FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, constructor);
    529   Handle<Map> initial_map = isolate->factory()->CreateSloppyFunctionMap(
    530       FUNCTION_WITH_WRITEABLE_PROTOTYPE);
    531   Handle<JSFunction> object_function =
    532       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    533           initial_map, shared, isolate->factory()->undefined_value());
    534   Handle<Map> object_map = isolate->factory()->NewMap(
    535       JS_SPECIAL_API_OBJECT_TYPE,
    536       JSObject::kHeaderSize + data->internal_field_count() * kPointerSize,
    537       FAST_HOLEY_SMI_ELEMENTS);
    538   JSFunction::SetInitialMap(object_function, object_map,
    539                             isolate->factory()->null_value());
    540   object_map->set_is_access_check_needed(true);
    541 
    542   Handle<JSObject> object = isolate->factory()->NewJSObject(object_function);
    543   JSObject::ForceSetPrototype(object, isolate->factory()->null_value());
    544 
    545   return object;
    546 }
    547 
    548 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
    549                                  Handle<Name> name, Handle<Object> value,
    550                                  PropertyAttributes attributes) {
    551   PropertyDetails details(kData, attributes, 0, PropertyCellType::kNoCell);
    552   auto details_handle = handle(details.AsSmi(), isolate);
    553   Handle<Object> data[] = {name, details_handle, value};
    554   AddPropertyToPropertyList(isolate, info, arraysize(data), data);
    555 }
    556 
    557 
    558 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
    559                                  Handle<Name> name, v8::Intrinsic intrinsic,
    560                                  PropertyAttributes attributes) {
    561   auto value = handle(Smi::FromInt(intrinsic), isolate);
    562   auto intrinsic_marker = isolate->factory()->true_value();
    563   PropertyDetails details(kData, attributes, 0, PropertyCellType::kNoCell);
    564   auto details_handle = handle(details.AsSmi(), isolate);
    565   Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
    566   AddPropertyToPropertyList(isolate, info, arraysize(data), data);
    567 }
    568 
    569 
    570 void ApiNatives::AddAccessorProperty(Isolate* isolate,
    571                                      Handle<TemplateInfo> info,
    572                                      Handle<Name> name,
    573                                      Handle<FunctionTemplateInfo> getter,
    574                                      Handle<FunctionTemplateInfo> setter,
    575                                      PropertyAttributes attributes) {
    576   PropertyDetails details(kAccessor, attributes, 0, PropertyCellType::kNoCell);
    577   auto details_handle = handle(details.AsSmi(), isolate);
    578   Handle<Object> data[] = {name, details_handle, getter, setter};
    579   AddPropertyToPropertyList(isolate, info, arraysize(data), data);
    580 }
    581 
    582 
    583 void ApiNatives::AddNativeDataProperty(Isolate* isolate,
    584                                        Handle<TemplateInfo> info,
    585                                        Handle<AccessorInfo> property) {
    586   Object* maybe_list = info->property_accessors();
    587   Handle<TemplateList> list;
    588   if (maybe_list->IsUndefined(isolate)) {
    589     list = TemplateList::New(isolate, 1);
    590   } else {
    591     list = handle(TemplateList::cast(maybe_list), isolate);
    592   }
    593   list = TemplateList::Add(isolate, list, property);
    594   info->set_property_accessors(*list);
    595 }
    596 
    597 
    598 Handle<JSFunction> ApiNatives::CreateApiFunction(
    599     Isolate* isolate, Handle<FunctionTemplateInfo> obj,
    600     Handle<Object> prototype, ApiInstanceType instance_type) {
    601   Handle<SharedFunctionInfo> shared =
    602       FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj);
    603   Handle<JSFunction> result =
    604       isolate->factory()->NewFunctionFromSharedFunctionInfo(
    605           shared, isolate->native_context());
    606 
    607   if (obj->remove_prototype()) {
    608     result->set_map(*isolate->sloppy_function_without_prototype_map());
    609     DCHECK(prototype.is_null());
    610     DCHECK(result->shared()->IsApiFunction());
    611     DCHECK(!result->has_initial_map());
    612     DCHECK(!result->has_prototype());
    613     DCHECK(!result->IsConstructor());
    614     return result;
    615   }
    616 
    617   // Down from here is only valid for API functions that can be used as a
    618   // constructor (don't set the "remove prototype" flag).
    619 
    620   if (obj->read_only_prototype()) {
    621     result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
    622   }
    623 
    624   if (prototype->IsTheHole(isolate)) {
    625     prototype = isolate->factory()->NewFunctionPrototype(result);
    626   } else if (obj->prototype_provider_template()->IsUndefined(isolate)) {
    627     JSObject::AddProperty(Handle<JSObject>::cast(prototype),
    628                           isolate->factory()->constructor_string(), result,
    629                           DONT_ENUM);
    630   }
    631 
    632   int internal_field_count = 0;
    633   bool immutable_proto = false;
    634   if (!obj->instance_template()->IsUndefined(isolate)) {
    635     Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
    636         ObjectTemplateInfo::cast(obj->instance_template()));
    637     internal_field_count = instance_template->internal_field_count();
    638     immutable_proto = instance_template->immutable_proto();
    639   }
    640 
    641   // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
    642   // JSObject::GetHeaderSize.
    643   int instance_size = kPointerSize * internal_field_count;
    644   InstanceType type;
    645   switch (instance_type) {
    646     case JavaScriptObjectType:
    647       if (!obj->needs_access_check() &&
    648           obj->named_property_handler()->IsUndefined(isolate) &&
    649           obj->indexed_property_handler()->IsUndefined(isolate)) {
    650         type = JS_API_OBJECT_TYPE;
    651       } else {
    652         type = JS_SPECIAL_API_OBJECT_TYPE;
    653       }
    654       instance_size += JSObject::kHeaderSize;
    655       break;
    656     case GlobalObjectType:
    657       type = JS_GLOBAL_OBJECT_TYPE;
    658       instance_size += JSGlobalObject::kSize;
    659       break;
    660     case GlobalProxyType:
    661       type = JS_GLOBAL_PROXY_TYPE;
    662       instance_size += JSGlobalProxy::kSize;
    663       break;
    664     default:
    665       UNREACHABLE();
    666       type = JS_OBJECT_TYPE;  // Keep the compiler happy.
    667       break;
    668   }
    669 
    670   Handle<Map> map =
    671       isolate->factory()->NewMap(type, instance_size, FAST_HOLEY_SMI_ELEMENTS);
    672   JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
    673 
    674   // Mark as undetectable if needed.
    675   if (obj->undetectable()) {
    676     // We only allow callable undetectable receivers here, since this whole
    677     // undetectable business is only to support document.all, which is both
    678     // undetectable and callable. If we ever see the need to have an object
    679     // that is undetectable but not callable, we need to update the types.h
    680     // to allow encoding this.
    681     CHECK(!obj->instance_call_handler()->IsUndefined(isolate));
    682     map->set_is_undetectable();
    683   }
    684 
    685   // Mark as needs_access_check if needed.
    686   if (obj->needs_access_check()) {
    687     map->set_is_access_check_needed(true);
    688   }
    689 
    690   // Set interceptor information in the map.
    691   if (!obj->named_property_handler()->IsUndefined(isolate)) {
    692     map->set_has_named_interceptor();
    693   }
    694   if (!obj->indexed_property_handler()->IsUndefined(isolate)) {
    695     map->set_has_indexed_interceptor();
    696   }
    697 
    698   // Mark instance as callable in the map.
    699   if (!obj->instance_call_handler()->IsUndefined(isolate)) {
    700     map->set_is_callable();
    701     map->set_is_constructor(true);
    702   }
    703 
    704   if (immutable_proto) map->set_immutable_proto(true);
    705 
    706   return result;
    707 }
    708 
    709 }  // namespace internal
    710 }  // namespace v8
    711