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