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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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