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