LCOV - code coverage report
Current view: top level - src - api-natives.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 214 237 90.3 %
Date: 2017-10-20 Functions: 25 26 96.2 %

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

Generated by: LCOV version 1.10