• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/api-natives.h"
6 
7 #include "src/api.h"
8 #include "src/isolate-inl.h"
9 #include "src/lookup.h"
10 #include "src/messages.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 
16 namespace {
17 
18 class InvokeScope {
19  public:
InvokeScope(Isolate * isolate)20   explicit InvokeScope(Isolate* isolate)
21       : isolate_(isolate), save_context_(isolate) {}
~InvokeScope()22   ~InvokeScope() {
23     bool has_exception = isolate_->has_pending_exception();
24     if (has_exception) {
25       isolate_->ReportPendingMessages();
26     } else {
27       isolate_->clear_pending_message();
28     }
29   }
30 
31  private:
32   Isolate* isolate_;
33   SaveContext save_context_;
34 };
35 
36 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
37                                         Handle<ObjectTemplateInfo> data,
38                                         Handle<JSReceiver> new_target,
39                                         bool is_hidden_prototype);
40 
41 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
42                                             Handle<FunctionTemplateInfo> data,
43                                             Handle<Name> name = Handle<Name>());
44 
Instantiate(Isolate * isolate,Handle<Object> data,Handle<Name> name=Handle<Name> ())45 MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data,
46                                 Handle<Name> name = Handle<Name>()) {
47   if (data->IsFunctionTemplateInfo()) {
48     return InstantiateFunction(isolate,
49                                Handle<FunctionTemplateInfo>::cast(data), name);
50   } else if (data->IsObjectTemplateInfo()) {
51     return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
52                              Handle<JSReceiver>(), false);
53   } else {
54     return data;
55   }
56 }
57 
DefineAccessorProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes,bool force_instantiate)58 MaybeHandle<Object> DefineAccessorProperty(
59     Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
60     Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
61     bool force_instantiate) {
62   DCHECK(!getter->IsFunctionTemplateInfo() ||
63          !FunctionTemplateInfo::cast(*getter)->do_not_cache());
64   DCHECK(!setter->IsFunctionTemplateInfo() ||
65          !FunctionTemplateInfo::cast(*setter)->do_not_cache());
66   if (force_instantiate) {
67     if (getter->IsFunctionTemplateInfo()) {
68       ASSIGN_RETURN_ON_EXCEPTION(
69           isolate, getter,
70           InstantiateFunction(isolate,
71                               Handle<FunctionTemplateInfo>::cast(getter)),
72           Object);
73     }
74     if (setter->IsFunctionTemplateInfo()) {
75       ASSIGN_RETURN_ON_EXCEPTION(
76           isolate, setter,
77           InstantiateFunction(isolate,
78                               Handle<FunctionTemplateInfo>::cast(setter)),
79           Object);
80     }
81   }
82   RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
83                                                         setter, attributes),
84                       Object);
85   return object;
86 }
87 
88 
DefineDataProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> prop_data,PropertyAttributes attributes)89 MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
90                                        Handle<JSObject> object,
91                                        Handle<Name> name,
92                                        Handle<Object> prop_data,
93                                        PropertyAttributes attributes) {
94   Handle<Object> value;
95   ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
96                              Instantiate(isolate, prop_data, name), Object);
97 
98   LookupIterator it = LookupIterator::PropertyOrElement(
99       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
100 
101 #ifdef DEBUG
102   Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
103   DCHECK(maybe.IsJust());
104   if (it.IsFound()) {
105     THROW_NEW_ERROR(
106         isolate,
107         NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
108         Object);
109   }
110 #endif
111 
112   MAYBE_RETURN_NULL(
113       Object::AddDataProperty(&it, value, attributes, Object::THROW_ON_ERROR,
114                               Object::CERTAINLY_NOT_STORE_FROM_KEYED));
115   return value;
116 }
117 
118 
DisableAccessChecks(Isolate * isolate,Handle<JSObject> object)119 void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
120   Handle<Map> old_map(object->map());
121   // Copy map so it won't interfere constructor's initial map.
122   Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
123   new_map->set_is_access_check_needed(false);
124   JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
125 }
126 
127 
EnableAccessChecks(Isolate * isolate,Handle<JSObject> object)128 void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
129   Handle<Map> old_map(object->map());
130   // Copy map so it won't interfere constructor's initial map.
131   Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
132   new_map->set_is_access_check_needed(true);
133   JSObject::MigrateToMap(object, new_map);
134 }
135 
136 
137 class AccessCheckDisableScope {
138  public:
AccessCheckDisableScope(Isolate * isolate,Handle<JSObject> obj)139   AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
140       : isolate_(isolate),
141         disabled_(obj->map()->is_access_check_needed()),
142         obj_(obj) {
143     if (disabled_) {
144       DisableAccessChecks(isolate_, obj_);
145     }
146   }
~AccessCheckDisableScope()147   ~AccessCheckDisableScope() {
148     if (disabled_) {
149       EnableAccessChecks(isolate_, obj_);
150     }
151   }
152 
153  private:
154   Isolate* isolate_;
155   const bool disabled_;
156   Handle<JSObject> obj_;
157 };
158 
159 
GetIntrinsic(Isolate * isolate,v8::Intrinsic intrinsic)160 Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
161   Handle<Context> native_context = isolate->native_context();
162   DCHECK(!native_context.is_null());
163   switch (intrinsic) {
164 #define GET_INTRINSIC_VALUE(name, iname) \
165   case v8::k##name:                      \
166     return native_context->iname();
167     V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
168 #undef GET_INTRINSIC_VALUE
169   }
170   return nullptr;
171 }
172 
173 
174 template <typename TemplateInfoT>
ConfigureInstance(Isolate * isolate,Handle<JSObject> obj,Handle<TemplateInfoT> data,bool is_hidden_prototype)175 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
176                                         Handle<TemplateInfoT> data,
177                                         bool is_hidden_prototype) {
178   HandleScope scope(isolate);
179   // Disable access checks while instantiating the object.
180   AccessCheckDisableScope access_check_scope(isolate, obj);
181 
182   // Walk the inheritance chain and copy all accessors to current object.
183   int max_number_of_properties = 0;
184   TemplateInfoT* info = *data;
185   while (info != nullptr) {
186     Object* props = info->property_accessors();
187     if (!props->IsUndefined(isolate)) {
188       max_number_of_properties += TemplateList::cast(props)->length();
189     }
190     info = info->GetParent(isolate);
191   }
192 
193   if (max_number_of_properties > 0) {
194     int valid_descriptors = 0;
195     // Use a temporary FixedArray to accumulate unique accessors.
196     Handle<FixedArray> array =
197         isolate->factory()->NewFixedArray(max_number_of_properties);
198 
199     for (Handle<TemplateInfoT> temp(*data); *temp != nullptr;
200          temp = handle(temp->GetParent(isolate), isolate)) {
201       // Accumulate accessors.
202       Object* maybe_properties = temp->property_accessors();
203       if (!maybe_properties->IsUndefined(isolate)) {
204         valid_descriptors = AccessorInfo::AppendUnique(
205             handle(maybe_properties, isolate), array, valid_descriptors);
206       }
207     }
208 
209     // Install accumulated accessors.
210     for (int i = 0; i < valid_descriptors; i++) {
211       Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
212       JSObject::SetAccessor(obj, accessor).Assert();
213     }
214   }
215 
216   Object* maybe_property_list = data->property_list();
217   if (maybe_property_list->IsUndefined(isolate)) return obj;
218   Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
219                                   isolate);
220   if (properties->length() == 0) return obj;
221 
222   int i = 0;
223   for (int c = 0; c < data->number_of_properties(); c++) {
224     auto name = handle(Name::cast(properties->get(i++)), isolate);
225     Object* bit = properties->get(i++);
226     if (bit->IsSmi()) {
227       PropertyDetails details(Smi::cast(bit));
228       PropertyAttributes attributes = details.attributes();
229       PropertyKind kind = details.kind();
230 
231       if (kind == kData) {
232         auto prop_data = handle(properties->get(i++), isolate);
233         RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
234                                                         prop_data, attributes),
235                             JSObject);
236       } else {
237         auto getter = handle(properties->get(i++), isolate);
238         auto setter = handle(properties->get(i++), isolate);
239         RETURN_ON_EXCEPTION(
240             isolate, DefineAccessorProperty(isolate, obj, name, getter, setter,
241                                             attributes, is_hidden_prototype),
242             JSObject);
243       }
244     } else {
245       // Intrinsic data property --- Get appropriate value from the current
246       // context.
247       PropertyDetails details(Smi::cast(properties->get(i++)));
248       PropertyAttributes attributes = details.attributes();
249       DCHECK_EQ(kData, details.kind());
250 
251       v8::Intrinsic intrinsic =
252           static_cast<v8::Intrinsic>(Smi::cast(properties->get(i++))->value());
253       auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
254 
255       RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
256                                                       prop_data, attributes),
257                           JSObject);
258     }
259   }
260   return obj;
261 }
262 
ProbeInstantiationsCache(Isolate * isolate,int serial_number)263 MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
264                                                int serial_number) {
265   DCHECK_LE(1, serial_number);
266   if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
267     Handle<FixedArray> fast_cache =
268         isolate->fast_template_instantiations_cache();
269     return fast_cache->GetValue<JSObject>(isolate, serial_number - 1);
270   } else {
271     Handle<UnseededNumberDictionary> slow_cache =
272         isolate->slow_template_instantiations_cache();
273     int entry = slow_cache->FindEntry(serial_number);
274     if (entry == UnseededNumberDictionary::kNotFound) {
275       return MaybeHandle<JSObject>();
276     }
277     return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
278   }
279 }
280 
CacheTemplateInstantiation(Isolate * isolate,int serial_number,Handle<JSObject> object)281 void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
282                                 Handle<JSObject> object) {
283   DCHECK_LE(1, serial_number);
284   if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
285     Handle<FixedArray> fast_cache =
286         isolate->fast_template_instantiations_cache();
287     Handle<FixedArray> new_cache =
288         FixedArray::SetAndGrow(fast_cache, serial_number - 1, object);
289     if (*new_cache != *fast_cache) {
290       isolate->native_context()->set_fast_template_instantiations_cache(
291           *new_cache);
292     }
293   } else {
294     Handle<UnseededNumberDictionary> cache =
295         isolate->slow_template_instantiations_cache();
296     auto new_cache =
297         UnseededNumberDictionary::AtNumberPut(cache, serial_number, object);
298     if (*new_cache != *cache) {
299       isolate->native_context()->set_slow_template_instantiations_cache(
300           *new_cache);
301     }
302   }
303 }
304 
UncacheTemplateInstantiation(Isolate * isolate,int serial_number)305 void UncacheTemplateInstantiation(Isolate* isolate, int serial_number) {
306   DCHECK_LE(1, serial_number);
307   if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
308     Handle<FixedArray> fast_cache =
309         isolate->fast_template_instantiations_cache();
310     DCHECK(!fast_cache->get(serial_number - 1)->IsUndefined(isolate));
311     fast_cache->set_undefined(serial_number - 1);
312   } else {
313     Handle<UnseededNumberDictionary> cache =
314         isolate->slow_template_instantiations_cache();
315     int entry = cache->FindEntry(serial_number);
316     DCHECK(entry != UnseededNumberDictionary::kNotFound);
317     Handle<Object> result =
318         UnseededNumberDictionary::DeleteProperty(cache, entry);
319     USE(result);
320     DCHECK(result->IsTrue(isolate));
321     auto new_cache = UnseededNumberDictionary::Shrink(cache, entry);
322     isolate->native_context()->set_slow_template_instantiations_cache(
323         *new_cache);
324   }
325 }
326 
IsSimpleInstantiation(Isolate * isolate,ObjectTemplateInfo * info,JSReceiver * new_target)327 bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo* info,
328                            JSReceiver* new_target) {
329   DisallowHeapAllocation no_gc;
330 
331   if (!new_target->IsJSFunction()) return false;
332   JSFunction* fun = JSFunction::cast(new_target);
333   if (fun->shared()->function_data() != info->constructor()) return false;
334   if (info->immutable_proto()) return false;
335   return fun->context()->native_context() == isolate->raw_native_context();
336 }
337 
InstantiateObject(Isolate * isolate,Handle<ObjectTemplateInfo> info,Handle<JSReceiver> new_target,bool is_hidden_prototype)338 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
339                                         Handle<ObjectTemplateInfo> info,
340                                         Handle<JSReceiver> new_target,
341                                         bool is_hidden_prototype) {
342   Handle<JSFunction> constructor;
343   int serial_number = Smi::cast(info->serial_number())->value();
344   if (!new_target.is_null()) {
345     if (IsSimpleInstantiation(isolate, *info, *new_target)) {
346       constructor = Handle<JSFunction>::cast(new_target);
347     } else {
348       // Disable caching for subclass instantiation.
349       serial_number = 0;
350     }
351   }
352   // Fast path.
353   Handle<JSObject> result;
354   if (serial_number) {
355     if (ProbeInstantiationsCache(isolate, serial_number).ToHandle(&result)) {
356       return isolate->factory()->CopyJSObject(result);
357     }
358   }
359 
360   if (constructor.is_null()) {
361     Object* maybe_constructor_info = info->constructor();
362     if (maybe_constructor_info->IsUndefined(isolate)) {
363       constructor = isolate->object_function();
364     } else {
365       // Enter a new scope.  Recursion could otherwise create a lot of handles.
366       HandleScope scope(isolate);
367       Handle<FunctionTemplateInfo> cons_templ(
368           FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
369       Handle<JSFunction> tmp_constructor;
370       ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
371                                  InstantiateFunction(isolate, cons_templ),
372                                  JSObject);
373       constructor = scope.CloseAndEscape(tmp_constructor);
374     }
375 
376     if (new_target.is_null()) new_target = constructor;
377   }
378 
379   Handle<JSObject> object;
380   ASSIGN_RETURN_ON_EXCEPTION(isolate, object,
381                              JSObject::New(constructor, new_target), JSObject);
382   ASSIGN_RETURN_ON_EXCEPTION(
383       isolate, result,
384       ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject);
385   if (info->immutable_proto()) {
386     JSObject::SetImmutableProto(object);
387   }
388   // TODO(dcarney): is this necessary?
389   JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
390 
391   if (serial_number) {
392     CacheTemplateInstantiation(isolate, serial_number, result);
393     result = isolate->factory()->CopyJSObject(result);
394   }
395   return result;
396 }
397 
398 namespace {
GetInstancePrototype(Isolate * isolate,Object * function_template)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 
InstantiateFunction(Isolate * isolate,Handle<FunctionTemplateInfo> data,Handle<Name> name)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 
AddPropertyToPropertyList(Isolate * isolate,Handle<TemplateInfo> templ,int length,Handle<Object> * data)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 
InstantiateFunction(Handle<FunctionTemplateInfo> data)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 
InstantiateObject(Handle<ObjectTemplateInfo> data,Handle<JSReceiver> new_target)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 
InstantiateRemoteObject(Handle<ObjectTemplateInfo> data)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 
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)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 
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,v8::Intrinsic intrinsic,PropertyAttributes attributes)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 
AddAccessorProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<FunctionTemplateInfo> getter,Handle<FunctionTemplateInfo> setter,PropertyAttributes attributes)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 
AddNativeDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<AccessorInfo> property)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 
CreateApiFunction(Isolate * isolate,Handle<FunctionTemplateInfo> obj,Handle<Object> prototype,ApiInstanceType instance_type)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