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 #include "src/objects/api-callbacks.h"
12 #include "src/objects/hash-table-inl.h"
13 #include "src/objects/templates.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 
19 namespace {
20 
21 class InvokeScope {
22  public:
InvokeScope(Isolate * isolate)23   explicit InvokeScope(Isolate* isolate)
24       : isolate_(isolate), save_context_(isolate) {}
~InvokeScope()25   ~InvokeScope() {
26     bool has_exception = isolate_->has_pending_exception();
27     if (has_exception) {
28       isolate_->ReportPendingMessages();
29     } else {
30       isolate_->clear_pending_message();
31     }
32   }
33 
34  private:
35   Isolate* isolate_;
36   SaveContext save_context_;
37 };
38 
39 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
40                                         Handle<ObjectTemplateInfo> data,
41                                         Handle<JSReceiver> new_target,
42                                         bool is_hidden_prototype,
43                                         bool is_prototype);
44 
45 MaybeHandle<JSFunction> InstantiateFunction(
46     Isolate* isolate, Handle<FunctionTemplateInfo> data,
47     MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
48 
Instantiate(Isolate * isolate,Handle<Object> data,MaybeHandle<Name> maybe_name=MaybeHandle<Name> ())49 MaybeHandle<Object> Instantiate(
50     Isolate* isolate, Handle<Object> data,
51     MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
52   if (data->IsFunctionTemplateInfo()) {
53     return InstantiateFunction(
54         isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
55   } else if (data->IsObjectTemplateInfo()) {
56     return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
57                              Handle<JSReceiver>(), false, false);
58   } else {
59     return data;
60   }
61 }
62 
DefineAccessorProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes,bool force_instantiate)63 MaybeHandle<Object> DefineAccessorProperty(
64     Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
65     Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
66     bool force_instantiate) {
67   DCHECK(!getter->IsFunctionTemplateInfo() ||
68          !FunctionTemplateInfo::cast(*getter)->do_not_cache());
69   DCHECK(!setter->IsFunctionTemplateInfo() ||
70          !FunctionTemplateInfo::cast(*setter)->do_not_cache());
71   if (force_instantiate) {
72     if (getter->IsFunctionTemplateInfo()) {
73       ASSIGN_RETURN_ON_EXCEPTION(
74           isolate, getter,
75           InstantiateFunction(isolate,
76                               Handle<FunctionTemplateInfo>::cast(getter)),
77           Object);
78     }
79     if (setter->IsFunctionTemplateInfo()) {
80       ASSIGN_RETURN_ON_EXCEPTION(
81           isolate, setter,
82           InstantiateFunction(isolate,
83                               Handle<FunctionTemplateInfo>::cast(setter)),
84           Object);
85     }
86   }
87   RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
88                                                         setter, attributes),
89                       Object);
90   return object;
91 }
92 
93 
DefineDataProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> prop_data,PropertyAttributes attributes)94 MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
95                                        Handle<JSObject> object,
96                                        Handle<Name> name,
97                                        Handle<Object> prop_data,
98                                        PropertyAttributes attributes) {
99   Handle<Object> value;
100   ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
101                              Instantiate(isolate, prop_data, name), Object);
102 
103   LookupIterator it = LookupIterator::PropertyOrElement(
104       isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
105 
106 #ifdef DEBUG
107   Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
108   DCHECK(maybe.IsJust());
109   if (it.IsFound()) {
110     THROW_NEW_ERROR(
111         isolate,
112         NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
113         Object);
114   }
115 #endif
116 
117   MAYBE_RETURN_NULL(
118       Object::AddDataProperty(&it, value, attributes, kThrowOnError,
119                               Object::CERTAINLY_NOT_STORE_FROM_KEYED));
120   return value;
121 }
122 
123 
DisableAccessChecks(Isolate * isolate,Handle<JSObject> object)124 void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
125   Handle<Map> old_map(object->map());
126   // Copy map so it won't interfere constructor's initial map.
127   Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
128   new_map->set_is_access_check_needed(false);
129   JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
130 }
131 
132 
EnableAccessChecks(Isolate * isolate,Handle<JSObject> object)133 void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
134   Handle<Map> old_map(object->map());
135   // Copy map so it won't interfere constructor's initial map.
136   Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
137   new_map->set_is_access_check_needed(true);
138   new_map->set_may_have_interesting_symbols(true);
139   JSObject::MigrateToMap(object, new_map);
140 }
141 
142 
143 class AccessCheckDisableScope {
144  public:
AccessCheckDisableScope(Isolate * isolate,Handle<JSObject> obj)145   AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
146       : isolate_(isolate),
147         disabled_(obj->map()->is_access_check_needed()),
148         obj_(obj) {
149     if (disabled_) {
150       DisableAccessChecks(isolate_, obj_);
151     }
152   }
~AccessCheckDisableScope()153   ~AccessCheckDisableScope() {
154     if (disabled_) {
155       EnableAccessChecks(isolate_, obj_);
156     }
157   }
158 
159  private:
160   Isolate* isolate_;
161   const bool disabled_;
162   Handle<JSObject> obj_;
163 };
164 
165 
GetIntrinsic(Isolate * isolate,v8::Intrinsic intrinsic)166 Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
167   Handle<Context> native_context = isolate->native_context();
168   DCHECK(!native_context.is_null());
169   switch (intrinsic) {
170 #define GET_INTRINSIC_VALUE(name, iname) \
171   case v8::k##name:                      \
172     return native_context->iname();
173     V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
174 #undef GET_INTRINSIC_VALUE
175   }
176   return nullptr;
177 }
178 
179 
180 template <typename TemplateInfoT>
ConfigureInstance(Isolate * isolate,Handle<JSObject> obj,Handle<TemplateInfoT> data,bool is_hidden_prototype)181 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
182                                         Handle<TemplateInfoT> data,
183                                         bool is_hidden_prototype) {
184   HandleScope scope(isolate);
185   // Disable access checks while instantiating the object.
186   AccessCheckDisableScope access_check_scope(isolate, obj);
187 
188   // Walk the inheritance chain and copy all accessors to current object.
189   int max_number_of_properties = 0;
190   TemplateInfoT* info = *data;
191   while (info != nullptr) {
192     Object* props = info->property_accessors();
193     if (!props->IsUndefined(isolate)) {
194       max_number_of_properties += TemplateList::cast(props)->length();
195     }
196     info = info->GetParent(isolate);
197   }
198 
199   if (max_number_of_properties > 0) {
200     int valid_descriptors = 0;
201     // Use a temporary FixedArray to accumulate unique accessors.
202     Handle<FixedArray> array =
203         isolate->factory()->NewFixedArray(max_number_of_properties);
204 
205     for (Handle<TemplateInfoT> temp(*data); *temp != nullptr;
206          temp = handle(temp->GetParent(isolate), isolate)) {
207       // Accumulate accessors.
208       Object* maybe_properties = temp->property_accessors();
209       if (!maybe_properties->IsUndefined(isolate)) {
210         valid_descriptors = AccessorInfo::AppendUnique(
211             handle(maybe_properties, isolate), array, valid_descriptors);
212       }
213     }
214 
215     // Install accumulated accessors.
216     for (int i = 0; i < valid_descriptors; i++) {
217       Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
218       Handle<Name> name(Name::cast(accessor->name()), isolate);
219       JSObject::SetAccessor(obj, name, accessor,
220                             accessor->initial_property_attributes())
221           .Assert();
222     }
223   }
224 
225   Object* maybe_property_list = data->property_list();
226   if (maybe_property_list->IsUndefined(isolate)) return obj;
227   Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
228                                   isolate);
229   if (properties->length() == 0) return obj;
230 
231   int i = 0;
232   for (int c = 0; c < data->number_of_properties(); c++) {
233     auto name = handle(Name::cast(properties->get(i++)), isolate);
234     Object* bit = properties->get(i++);
235     if (bit->IsSmi()) {
236       PropertyDetails details(Smi::cast(bit));
237       PropertyAttributes attributes = details.attributes();
238       PropertyKind kind = details.kind();
239 
240       if (kind == kData) {
241         auto prop_data = handle(properties->get(i++), isolate);
242         RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
243                                                         prop_data, attributes),
244                             JSObject);
245       } else {
246         auto getter = handle(properties->get(i++), isolate);
247         auto setter = handle(properties->get(i++), isolate);
248         RETURN_ON_EXCEPTION(
249             isolate, DefineAccessorProperty(isolate, obj, name, getter, setter,
250                                             attributes, is_hidden_prototype),
251             JSObject);
252       }
253     } else {
254       // Intrinsic data property --- Get appropriate value from the current
255       // context.
256       PropertyDetails details(Smi::cast(properties->get(i++)));
257       PropertyAttributes attributes = details.attributes();
258       DCHECK_EQ(kData, details.kind());
259 
260       v8::Intrinsic intrinsic =
261           static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
262       auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
263 
264       RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
265                                                       prop_data, attributes),
266                           JSObject);
267     }
268   }
269   return obj;
270 }
271 
272 // Whether or not to cache every instance: when we materialize a getter or
273 // setter from an lazy AccessorPair, we rely on this cache to be able to always
274 // return the same getter or setter. However, objects will be cloned anyways,
275 // so it's not observable if we didn't cache an instance. Furthermore, a badly
276 // behaved embedder might create an unlimited number of objects, so we limit
277 // the cache for those cases.
278 enum class CachingMode { kLimited, kUnlimited };
279 
ProbeInstantiationsCache(Isolate * isolate,int serial_number,CachingMode caching_mode)280 MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
281                                                int serial_number,
282                                                CachingMode caching_mode) {
283   DCHECK_LE(1, serial_number);
284   if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
285     Handle<FixedArray> fast_cache =
286         isolate->fast_template_instantiations_cache();
287     return fast_cache->GetValue<JSObject>(isolate, serial_number - 1);
288   } else if (caching_mode == CachingMode::kUnlimited ||
289              (serial_number <=
290               TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
291     Handle<SimpleNumberDictionary> slow_cache =
292         isolate->slow_template_instantiations_cache();
293     int entry = slow_cache->FindEntry(serial_number);
294     if (entry == SimpleNumberDictionary::kNotFound) {
295       return MaybeHandle<JSObject>();
296     }
297     return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
298   } else {
299     return MaybeHandle<JSObject>();
300   }
301 }
302 
CacheTemplateInstantiation(Isolate * isolate,int serial_number,CachingMode caching_mode,Handle<JSObject> object)303 void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
304                                 CachingMode caching_mode,
305                                 Handle<JSObject> object) {
306   DCHECK_LE(1, serial_number);
307   if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
308     Handle<FixedArray> fast_cache =
309         isolate->fast_template_instantiations_cache();
310     Handle<FixedArray> new_cache =
311         FixedArray::SetAndGrow(fast_cache, serial_number - 1, object);
312     if (*new_cache != *fast_cache) {
313       isolate->native_context()->set_fast_template_instantiations_cache(
314           *new_cache);
315     }
316   } else if (caching_mode == CachingMode::kUnlimited ||
317              (serial_number <=
318               TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
319     Handle<SimpleNumberDictionary> cache =
320         isolate->slow_template_instantiations_cache();
321     auto new_cache = SimpleNumberDictionary::Set(cache, serial_number, object);
322     if (*new_cache != *cache) {
323       isolate->native_context()->set_slow_template_instantiations_cache(
324           *new_cache);
325     }
326   }
327 }
328 
UncacheTemplateInstantiation(Isolate * isolate,int serial_number,CachingMode caching_mode)329 void UncacheTemplateInstantiation(Isolate* isolate, int serial_number,
330                                   CachingMode caching_mode) {
331   DCHECK_LE(1, serial_number);
332   if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
333     Handle<FixedArray> fast_cache =
334         isolate->fast_template_instantiations_cache();
335     DCHECK(!fast_cache->get(serial_number - 1)->IsUndefined(isolate));
336     fast_cache->set_undefined(serial_number - 1);
337   } else if (caching_mode == CachingMode::kUnlimited ||
338              (serial_number <=
339               TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
340     Handle<SimpleNumberDictionary> cache =
341         isolate->slow_template_instantiations_cache();
342     int entry = cache->FindEntry(serial_number);
343     DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
344     cache = SimpleNumberDictionary::DeleteEntry(cache, entry);
345     isolate->native_context()->set_slow_template_instantiations_cache(*cache);
346   }
347 }
348 
IsSimpleInstantiation(Isolate * isolate,ObjectTemplateInfo * info,JSReceiver * new_target)349 bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo* info,
350                            JSReceiver* new_target) {
351   DisallowHeapAllocation no_gc;
352 
353   if (!new_target->IsJSFunction()) return false;
354   JSFunction* fun = JSFunction::cast(new_target);
355   if (fun->shared()->function_data() != info->constructor()) return false;
356   if (info->immutable_proto()) return false;
357   return fun->context()->native_context() == isolate->raw_native_context();
358 }
359 
InstantiateObject(Isolate * isolate,Handle<ObjectTemplateInfo> info,Handle<JSReceiver> new_target,bool is_hidden_prototype,bool is_prototype)360 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
361                                         Handle<ObjectTemplateInfo> info,
362                                         Handle<JSReceiver> new_target,
363                                         bool is_hidden_prototype,
364                                         bool is_prototype) {
365   Handle<JSFunction> constructor;
366   int serial_number = Smi::ToInt(info->serial_number());
367   if (!new_target.is_null()) {
368     if (IsSimpleInstantiation(isolate, *info, *new_target)) {
369       constructor = Handle<JSFunction>::cast(new_target);
370     } else {
371       // Disable caching for subclass instantiation.
372       serial_number = 0;
373     }
374   }
375   // Fast path.
376   Handle<JSObject> result;
377   if (serial_number) {
378     if (ProbeInstantiationsCache(isolate, serial_number, CachingMode::kLimited)
379             .ToHandle(&result)) {
380       return isolate->factory()->CopyJSObject(result);
381     }
382   }
383 
384   if (constructor.is_null()) {
385     Object* maybe_constructor_info = info->constructor();
386     if (maybe_constructor_info->IsUndefined(isolate)) {
387       constructor = isolate->object_function();
388     } else {
389       // Enter a new scope.  Recursion could otherwise create a lot of handles.
390       HandleScope scope(isolate);
391       Handle<FunctionTemplateInfo> cons_templ(
392           FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
393       Handle<JSFunction> tmp_constructor;
394       ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
395                                  InstantiateFunction(isolate, cons_templ),
396                                  JSObject);
397       constructor = scope.CloseAndEscape(tmp_constructor);
398     }
399 
400     if (new_target.is_null()) new_target = constructor;
401   }
402 
403   Handle<JSObject> object;
404   ASSIGN_RETURN_ON_EXCEPTION(isolate, object,
405                              JSObject::New(constructor, new_target), JSObject);
406 
407   if (is_prototype) JSObject::OptimizeAsPrototype(object);
408 
409   ASSIGN_RETURN_ON_EXCEPTION(
410       isolate, result,
411       ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject);
412   if (info->immutable_proto()) {
413     JSObject::SetImmutableProto(object);
414   }
415   if (!is_prototype) {
416     // Keep prototypes in slow-mode. Let them be lazily turned fast later on.
417     // TODO(dcarney): is this necessary?
418     JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
419     // Don't cache prototypes.
420     if (serial_number) {
421       CacheTemplateInstantiation(isolate, serial_number, CachingMode::kLimited,
422                                  result);
423       result = isolate->factory()->CopyJSObject(result);
424     }
425   }
426 
427   return result;
428 }
429 
430 namespace {
GetInstancePrototype(Isolate * isolate,Object * function_template)431 MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
432                                          Object* function_template) {
433   // Enter a new scope.  Recursion could otherwise create a lot of handles.
434   HandleScope scope(isolate);
435   Handle<JSFunction> parent_instance;
436   ASSIGN_RETURN_ON_EXCEPTION(
437       isolate, parent_instance,
438       InstantiateFunction(
439           isolate,
440           handle(FunctionTemplateInfo::cast(function_template), isolate)),
441       JSFunction);
442   Handle<Object> instance_prototype;
443   // TODO(cbruni): decide what to do here.
444   ASSIGN_RETURN_ON_EXCEPTION(
445       isolate, instance_prototype,
446       JSObject::GetProperty(parent_instance,
447                             isolate->factory()->prototype_string()),
448       JSFunction);
449   return scope.CloseAndEscape(instance_prototype);
450 }
451 }  // namespace
452 
InstantiateFunction(Isolate * isolate,Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name)453 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
454                                             Handle<FunctionTemplateInfo> data,
455                                             MaybeHandle<Name> maybe_name) {
456   int serial_number = Smi::ToInt(data->serial_number());
457   if (serial_number) {
458     Handle<JSObject> result;
459     if (ProbeInstantiationsCache(isolate, serial_number,
460                                  CachingMode::kUnlimited)
461             .ToHandle(&result)) {
462       return Handle<JSFunction>::cast(result);
463     }
464   }
465   Handle<Object> prototype;
466   if (!data->remove_prototype()) {
467     Object* prototype_templ = data->prototype_template();
468     if (prototype_templ->IsUndefined(isolate)) {
469       Object* protoype_provider_templ = data->prototype_provider_template();
470       if (protoype_provider_templ->IsUndefined(isolate)) {
471         prototype = isolate->factory()->NewJSObject(isolate->object_function());
472       } else {
473         ASSIGN_RETURN_ON_EXCEPTION(
474             isolate, prototype,
475             GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
476       }
477     } else {
478       ASSIGN_RETURN_ON_EXCEPTION(
479           isolate, prototype,
480           InstantiateObject(
481               isolate,
482               handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
483               Handle<JSReceiver>(), data->hidden_prototype(), true),
484           JSFunction);
485     }
486     Object* parent = data->parent_template();
487     if (!parent->IsUndefined(isolate)) {
488       Handle<Object> parent_prototype;
489       ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
490                                  GetInstancePrototype(isolate, parent),
491                                  JSFunction);
492       JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
493                                   parent_prototype);
494     }
495   }
496   Handle<JSFunction> function = ApiNatives::CreateApiFunction(
497       isolate, data, prototype, ApiNatives::JavaScriptObjectType, maybe_name);
498   if (serial_number) {
499     // Cache the function.
500     CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
501                                function);
502   }
503   MaybeHandle<JSObject> result =
504       ConfigureInstance(isolate, function, data, data->hidden_prototype());
505   if (result.is_null()) {
506     // Uncache on error.
507     if (serial_number) {
508       UncacheTemplateInstantiation(isolate, serial_number,
509                                    CachingMode::kUnlimited);
510     }
511     return MaybeHandle<JSFunction>();
512   }
513   return function;
514 }
515 
516 
AddPropertyToPropertyList(Isolate * isolate,Handle<TemplateInfo> templ,int length,Handle<Object> * data)517 void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
518                                int length, Handle<Object>* data) {
519   Object* maybe_list = templ->property_list();
520   Handle<TemplateList> list;
521   if (maybe_list->IsUndefined(isolate)) {
522     list = TemplateList::New(isolate, length);
523   } else {
524     list = handle(TemplateList::cast(maybe_list), isolate);
525   }
526   templ->set_number_of_properties(templ->number_of_properties() + 1);
527   for (int i = 0; i < length; i++) {
528     Handle<Object> value =
529         data[i].is_null()
530             ? Handle<Object>::cast(isolate->factory()->undefined_value())
531             : data[i];
532     list = TemplateList::Add(isolate, list, value);
533   }
534   templ->set_property_list(*list);
535 }
536 
537 }  // namespace
538 
InstantiateFunction(Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name)539 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
540     Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
541   Isolate* isolate = data->GetIsolate();
542   InvokeScope invoke_scope(isolate);
543   return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
544 }
545 
InstantiateObject(Handle<ObjectTemplateInfo> data,Handle<JSReceiver> new_target)546 MaybeHandle<JSObject> ApiNatives::InstantiateObject(
547     Handle<ObjectTemplateInfo> data, Handle<JSReceiver> new_target) {
548   Isolate* isolate = data->GetIsolate();
549   InvokeScope invoke_scope(isolate);
550   return ::v8::internal::InstantiateObject(isolate, data, new_target, false,
551                                            false);
552 }
553 
InstantiateRemoteObject(Handle<ObjectTemplateInfo> data)554 MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
555     Handle<ObjectTemplateInfo> data) {
556   Isolate* isolate = data->GetIsolate();
557   InvokeScope invoke_scope(isolate);
558 
559   Handle<FunctionTemplateInfo> constructor(
560       FunctionTemplateInfo::cast(data->constructor()));
561   Handle<Map> object_map = isolate->factory()->NewMap(
562       JS_SPECIAL_API_OBJECT_TYPE,
563       JSObject::kHeaderSize + data->embedder_field_count() * kPointerSize,
564       TERMINAL_FAST_ELEMENTS_KIND);
565   object_map->SetConstructor(*constructor);
566   object_map->set_is_access_check_needed(true);
567   object_map->set_may_have_interesting_symbols(true);
568 
569   Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(object_map);
570   JSObject::ForceSetPrototype(object, isolate->factory()->null_value());
571 
572   return object;
573 }
574 
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)575 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
576                                  Handle<Name> name, Handle<Object> value,
577                                  PropertyAttributes attributes) {
578   PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
579   auto details_handle = handle(details.AsSmi(), isolate);
580   Handle<Object> data[] = {name, details_handle, value};
581   AddPropertyToPropertyList(isolate, info, arraysize(data), data);
582 }
583 
584 
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,v8::Intrinsic intrinsic,PropertyAttributes attributes)585 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
586                                  Handle<Name> name, v8::Intrinsic intrinsic,
587                                  PropertyAttributes attributes) {
588   auto value = handle(Smi::FromInt(intrinsic), isolate);
589   auto intrinsic_marker = isolate->factory()->true_value();
590   PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
591   auto details_handle = handle(details.AsSmi(), isolate);
592   Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
593   AddPropertyToPropertyList(isolate, info, arraysize(data), data);
594 }
595 
596 
AddAccessorProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<FunctionTemplateInfo> getter,Handle<FunctionTemplateInfo> setter,PropertyAttributes attributes)597 void ApiNatives::AddAccessorProperty(Isolate* isolate,
598                                      Handle<TemplateInfo> info,
599                                      Handle<Name> name,
600                                      Handle<FunctionTemplateInfo> getter,
601                                      Handle<FunctionTemplateInfo> setter,
602                                      PropertyAttributes attributes) {
603   PropertyDetails details(kAccessor, attributes, PropertyCellType::kNoCell);
604   auto details_handle = handle(details.AsSmi(), isolate);
605   Handle<Object> data[] = {name, details_handle, getter, setter};
606   AddPropertyToPropertyList(isolate, info, arraysize(data), data);
607 }
608 
609 
AddNativeDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<AccessorInfo> property)610 void ApiNatives::AddNativeDataProperty(Isolate* isolate,
611                                        Handle<TemplateInfo> info,
612                                        Handle<AccessorInfo> property) {
613   Object* maybe_list = info->property_accessors();
614   Handle<TemplateList> list;
615   if (maybe_list->IsUndefined(isolate)) {
616     list = TemplateList::New(isolate, 1);
617   } else {
618     list = handle(TemplateList::cast(maybe_list), isolate);
619   }
620   list = TemplateList::Add(isolate, list, property);
621   info->set_property_accessors(*list);
622 }
623 
CreateApiFunction(Isolate * isolate,Handle<FunctionTemplateInfo> obj,Handle<Object> prototype,ApiInstanceType instance_type,MaybeHandle<Name> maybe_name)624 Handle<JSFunction> ApiNatives::CreateApiFunction(
625     Isolate* isolate, Handle<FunctionTemplateInfo> obj,
626     Handle<Object> prototype, ApiInstanceType instance_type,
627     MaybeHandle<Name> maybe_name) {
628   Handle<SharedFunctionInfo> shared =
629       FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
630                                                           maybe_name);
631   // To simplify things, API functions always have shared name.
632   DCHECK(shared->HasSharedName());
633 
634   Handle<JSFunction> result =
635       isolate->factory()->NewFunctionFromSharedFunctionInfo(
636           shared, isolate->native_context());
637 
638   if (obj->remove_prototype()) {
639     DCHECK(prototype.is_null());
640     DCHECK(result->shared()->IsApiFunction());
641     DCHECK(!result->IsConstructor());
642     DCHECK(!result->has_prototype_slot());
643     return result;
644   }
645 
646   // Down from here is only valid for API functions that can be used as a
647   // constructor (don't set the "remove prototype" flag).
648   DCHECK(result->has_prototype_slot());
649 
650   if (obj->read_only_prototype()) {
651     result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
652   }
653 
654   if (prototype->IsTheHole(isolate)) {
655     prototype = isolate->factory()->NewFunctionPrototype(result);
656   } else if (obj->prototype_provider_template()->IsUndefined(isolate)) {
657     JSObject::AddProperty(Handle<JSObject>::cast(prototype),
658                           isolate->factory()->constructor_string(), result,
659                           DONT_ENUM);
660   }
661 
662   int embedder_field_count = 0;
663   bool immutable_proto = false;
664   if (!obj->instance_template()->IsUndefined(isolate)) {
665     Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
666         ObjectTemplateInfo::cast(obj->instance_template()));
667     embedder_field_count = instance_template->embedder_field_count();
668     immutable_proto = instance_template->immutable_proto();
669   }
670 
671   // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
672   // JSObject::GetHeaderSize.
673   int instance_size = kPointerSize * embedder_field_count;
674   InstanceType type;
675   switch (instance_type) {
676     case JavaScriptObjectType:
677       if (!obj->needs_access_check() &&
678           obj->named_property_handler()->IsUndefined(isolate) &&
679           obj->indexed_property_handler()->IsUndefined(isolate)) {
680         type = JS_API_OBJECT_TYPE;
681       } else {
682         type = JS_SPECIAL_API_OBJECT_TYPE;
683       }
684       instance_size += JSObject::kHeaderSize;
685       break;
686     case GlobalObjectType:
687       type = JS_GLOBAL_OBJECT_TYPE;
688       instance_size += JSGlobalObject::kSize;
689       break;
690     case GlobalProxyType:
691       type = JS_GLOBAL_PROXY_TYPE;
692       instance_size += JSGlobalProxy::kSize;
693       break;
694     default:
695       UNREACHABLE();
696       break;
697   }
698 
699   Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
700                                                TERMINAL_FAST_ELEMENTS_KIND);
701   JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
702 
703   // Mark as undetectable if needed.
704   if (obj->undetectable()) {
705     // We only allow callable undetectable receivers here, since this whole
706     // undetectable business is only to support document.all, which is both
707     // undetectable and callable. If we ever see the need to have an object
708     // that is undetectable but not callable, we need to update the types.h
709     // to allow encoding this.
710     CHECK(!obj->instance_call_handler()->IsUndefined(isolate));
711     map->set_is_undetectable(true);
712   }
713 
714   // Mark as needs_access_check if needed.
715   if (obj->needs_access_check()) {
716     map->set_is_access_check_needed(true);
717     map->set_may_have_interesting_symbols(true);
718   }
719 
720   // Set interceptor information in the map.
721   if (!obj->named_property_handler()->IsUndefined(isolate)) {
722     map->set_has_named_interceptor(true);
723     map->set_may_have_interesting_symbols(true);
724   }
725   if (!obj->indexed_property_handler()->IsUndefined(isolate)) {
726     map->set_has_indexed_interceptor(true);
727   }
728 
729   // Mark instance as callable in the map.
730   if (!obj->instance_call_handler()->IsUndefined(isolate)) {
731     map->set_is_callable(true);
732   }
733 
734   if (immutable_proto) map->set_is_immutable_proto(true);
735 
736   return result;
737 }
738 
739 }  // namespace internal
740 }  // namespace v8
741