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 
Instantiate(Isolate * isolate,Handle<Object> data,Handle<Name> name=Handle<Name> ())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 
DefineAccessorProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes)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 
DefineDataProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> prop_data,PropertyAttributes attributes)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 
DisableAccessChecks(Isolate * isolate,Handle<JSObject> object)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 
EnableAccessChecks(Isolate * isolate,Handle<JSObject> object)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:
AccessCheckDisableScope(Isolate * isolate,Handle<JSObject> obj)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   }
~AccessCheckDisableScope()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 
GetIntrinsic(Isolate * isolate,v8::Intrinsic intrinsic)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 
ConfigureInstance(Isolate * isolate,Handle<JSObject> obj,Handle<TemplateInfo> data)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 
InstantiateObject(Isolate * isolate,Handle<ObjectTemplateInfo> data)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 
CacheFunction(Isolate * isolate,Handle<Smi> serial_number,Handle<JSFunction> function)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 
UncacheFunction(Isolate * isolate,Handle<Smi> serial_number)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 
InstantiateFunction(Isolate * isolate,Handle<FunctionTemplateInfo> data,Handle<Name> name)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:
InvokeScope(Isolate * isolate)317   explicit InvokeScope(Isolate* isolate)
318       : isolate_(isolate), save_context_(isolate) {}
~InvokeScope()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 
AddPropertyToPropertyList(Isolate * isolate,Handle<TemplateInfo> templ,int length,Handle<Object> * data)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 
InstantiateFunction(Handle<FunctionTemplateInfo> data)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 
InstantiateObject(Handle<ObjectTemplateInfo> data)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 
ConfigureInstance(Isolate * isolate,Handle<FunctionTemplateInfo> desc,Handle<JSObject> instance)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 
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)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 
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,v8::Intrinsic intrinsic,PropertyAttributes attributes)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 
AddAccessorProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<FunctionTemplateInfo> getter,Handle<FunctionTemplateInfo> setter,PropertyAttributes attributes)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 
AddNativeDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<AccessorInfo> property)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 
CreateApiFunction(Isolate * isolate,Handle<FunctionTemplateInfo> obj,Handle<Object> prototype,ApiInstanceType instance_type)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