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