api-natives.cc 29.7 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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 19 20 21 22

namespace v8 {
namespace internal {

namespace {

23
class V8_NODISCARD InvokeScope {
24
 public:
25 26
  explicit InvokeScope(Isolate* isolate)
      : isolate_(isolate), save_context_(isolate) {}
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 39 40
  SaveContext save_context_;
};

41 42 43
MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
                                        Handle<ObjectTemplateInfo> data,
                                        Handle<JSReceiver> new_target,
44
                                        bool is_prototype);
dcarney's avatar
dcarney committed
45

46
MaybeHandle<JSFunction> InstantiateFunction(
47 48
    Isolate* isolate, Handle<NativeContext> native_context,
    Handle<FunctionTemplateInfo> data,
49
    MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
dcarney's avatar
dcarney committed
50

51 52 53 54 55 56 57
MaybeHandle<JSFunction> InstantiateFunction(
    Isolate* isolate, Handle<FunctionTemplateInfo> data,
    MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
  return InstantiateFunction(isolate, isolate->native_context(), data,
                             maybe_name);
}

58 59 60
MaybeHandle<Object> Instantiate(
    Isolate* isolate, Handle<Object> data,
    MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
dcarney's avatar
dcarney committed
61
  if (data->IsFunctionTemplateInfo()) {
62 63
    return InstantiateFunction(
        isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
dcarney's avatar
dcarney committed
64
  } else if (data->IsObjectTemplateInfo()) {
65
    return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
66
                             Handle<JSReceiver>(), false);
dcarney's avatar
dcarney committed
67 68 69
  } else {
    return data;
  }
70 71
}

72 73 74 75 76 77
MaybeHandle<Object> DefineAccessorProperty(Isolate* isolate,
                                           Handle<JSObject> object,
                                           Handle<Name> name,
                                           Handle<Object> getter,
                                           Handle<Object> setter,
                                           PropertyAttributes attributes) {
78
  DCHECK(!getter->IsFunctionTemplateInfo() ||
79
         FunctionTemplateInfo::cast(*getter).should_cache());
80
  DCHECK(!setter->IsFunctionTemplateInfo() ||
81
         FunctionTemplateInfo::cast(*setter).should_cache());
82 83 84 85 86 87 88
  if (getter->IsFunctionTemplateInfo() &&
      FunctionTemplateInfo::cast(*getter).BreakAtEntry()) {
    ASSIGN_RETURN_ON_EXCEPTION(
        isolate, getter,
        InstantiateFunction(isolate,
                            Handle<FunctionTemplateInfo>::cast(getter)),
        Object);
89
  }
90 91 92 93 94 95 96
  if (setter->IsFunctionTemplateInfo() &&
      FunctionTemplateInfo::cast(*setter).BreakAtEntry()) {
    ASSIGN_RETURN_ON_EXCEPTION(
        isolate, setter,
        InstantiateFunction(isolate,
                            Handle<FunctionTemplateInfo>::cast(setter)),
        Object);
dcarney's avatar
dcarney committed
97
  }
98 99 100 101
  RETURN_ON_EXCEPTION(
      isolate,
      JSObject::DefineAccessor(object, name, getter, setter, attributes),
      Object);
102 103 104
  return object;
}

dcarney's avatar
dcarney committed
105 106
MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
                                       Handle<JSObject> object,
107
                                       Handle<Name> name,
dcarney's avatar
dcarney committed
108
                                       Handle<Object> prop_data,
109
                                       PropertyAttributes attributes) {
dcarney's avatar
dcarney committed
110 111
  Handle<Object> value;
  ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
112
                             Instantiate(isolate, prop_data, name), Object);
dcarney's avatar
dcarney committed
113

114
  PropertyKey key(isolate, name);
115
  LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
116

117
#ifdef DEBUG
118 119 120
  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
  DCHECK(maybe.IsJust());
  if (it.IsFound()) {
121
    THROW_NEW_ERROR(
122 123
        isolate,
        NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
124
        Object);
125 126 127
  }
#endif

128 129 130
  MAYBE_RETURN_NULL(Object::AddDataProperty(&it, value, attributes,
                                            Just(ShouldThrow::kThrowOnError),
                                            StoreOrigin::kNamed));
131
  return value;
132 133 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 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 153 154
 public:
  AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
      : isolate_(isolate),
155
        disabled_(obj->map().is_access_check_needed()),
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
        obj_(obj) {
    if (disabled_) {
      DisableAccessChecks(isolate_, obj_);
    }
  }
  ~AccessCheckDisableScope() {
    if (disabled_) {
      EnableAccessChecks(isolate_, obj_);
    }
  }

 private:
  Isolate* isolate_;
  const bool disabled_;
  Handle<JSObject> obj_;
};

173
Object GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
174 175 176 177 178 179 180 181 182
  Handle<Context> native_context = isolate->native_context();
  DCHECK(!native_context.is_null());
  switch (intrinsic) {
#define GET_INTRINSIC_VALUE(name, iname) \
  case v8::k##name:                      \
    return native_context->iname();
    V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
#undef GET_INTRINSIC_VALUE
  }
183
  return Object();
184 185
}

186
template <typename TemplateInfoT>
187
MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
188
                                        Handle<TemplateInfoT> data) {
189
  RCS_SCOPE(isolate, RuntimeCallCounterId::kConfigureInstance);
190 191 192 193 194 195
  HandleScope scope(isolate);
  // Disable access checks while instantiating the object.
  AccessCheckDisableScope access_check_scope(isolate, obj);

  // Walk the inheritance chain and copy all accessors to current object.
  int max_number_of_properties = 0;
196 197
  TemplateInfoT info = *data;
  while (!info.is_null()) {
198 199 200
    Object props = info.property_accessors();
    if (!props.IsUndefined(isolate)) {
      max_number_of_properties += TemplateList::cast(props).length();
201
    }
202
    info = info.GetParent(isolate);
203 204 205 206 207 208 209 210
  }

  if (max_number_of_properties > 0) {
    int valid_descriptors = 0;
    // Use a temporary FixedArray to accumulate unique accessors.
    Handle<FixedArray> array =
        isolate->factory()->NewFixedArray(max_number_of_properties);

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 218
            isolate, handle(maybe_properties, isolate), array,
            valid_descriptors);
219 220 221 222 223
      }
    }

    // Install accumulated accessors.
    for (int i = 0; i < valid_descriptors; i++) {
224
      Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)), isolate);
225 226 227 228
      Handle<Name> name(Name::cast(accessor->name()), isolate);
      JSObject::SetAccessor(obj, name, accessor,
                            accessor->initial_property_attributes())
          .Assert();
229 230 231
    }
  }

232
  Object maybe_property_list = data->property_list();
233
  if (maybe_property_list.IsUndefined(isolate)) return obj;
234 235 236
  Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
                                  isolate);
  if (properties->length() == 0) return obj;
237 238 239

  int i = 0;
  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 245 246
      PropertyAttributes attributes = details.attributes();
      PropertyKind kind = details.kind();

247
      if (kind == PropertyKind::kData) {
248
        auto prop_data = handle(properties->get(i++), isolate);
249 250 251 252
        RETURN_ON_EXCEPTION(
            isolate,
            DefineDataProperty(isolate, obj, name, prop_data, attributes),
            JSObject);
253
      } else {
254 255
        auto getter = handle(properties->get(i++), isolate);
        auto setter = handle(properties->get(i++), isolate);
256 257
        RETURN_ON_EXCEPTION(isolate,
                            DefineAccessorProperty(isolate, obj, name, getter,
258
                                                   setter, attributes),
259
                            JSObject);
260 261 262 263
      }
    } else {
      // Intrinsic data property --- Get appropriate value from the current
      // 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 =
jgruber's avatar
jgruber committed
269
          static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
270
      auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
271

272 273 274 275
      RETURN_ON_EXCEPTION(
          isolate,
          DefineDataProperty(isolate, obj, name, prop_data, attributes),
          JSObject);
276 277 278 279 280
    }
  }
  return obj;
}

281 282 283 284 285 286 287 288
// Whether or not to cache every instance: when we materialize a getter or
// setter from an lazy AccessorPair, we rely on this cache to be able to always
// return the same getter or setter. However, objects will be cloned anyways,
// so it's not observable if we didn't cache an instance. Furthermore, a badly
// behaved embedder might create an unlimited number of objects, so we limit
// the cache for those cases.
enum class CachingMode { kLimited, kUnlimited };

289 290 291
MaybeHandle<JSObject> ProbeInstantiationsCache(
    Isolate* isolate, Handle<NativeContext> native_context, int serial_number,
    CachingMode caching_mode) {
292 293 294 295 296 297
  DCHECK_NE(serial_number, TemplateInfo::kDoNotCache);
  if (serial_number == TemplateInfo::kUncached) {
    return {};
  }

  if (serial_number < TemplateInfo::kFastTemplateInstantiationsCacheSize) {
298 299
    FixedArray fast_cache =
        native_context->fast_template_instantiations_cache();
300
    Handle<Object> object{fast_cache.get(serial_number), isolate};
301
    if (object->IsTheHole(isolate)) return {};
302 303 304
    return Handle<JSObject>::cast(object);
  }
  if (caching_mode == CachingMode::kUnlimited ||
305
      (serial_number < TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
306 307
    SimpleNumberDictionary slow_cache =
        native_context->slow_template_instantiations_cache();
308 309
    InternalIndex entry = slow_cache.FindEntry(isolate, serial_number);
    if (entry.is_found()) {
310
      return handle(JSObject::cast(slow_cache.ValueAt(entry)), isolate);
311 312
    }
  }
313
  return {};
314 315
}

316 317
void CacheTemplateInstantiation(Isolate* isolate,
                                Handle<NativeContext> native_context,
318 319
                                Handle<TemplateInfo> data,
                                CachingMode caching_mode,
320
                                Handle<JSObject> object) {
321 322 323 324 325 326 327 328
  DCHECK_NE(TemplateInfo::kDoNotCache, data->serial_number());

  int serial_number = data->serial_number();
  if (serial_number == TemplateInfo::kUncached) {
    serial_number = isolate->heap()->GetNextTemplateSerialNumber();
  }

  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 343
    auto new_cache =
        SimpleNumberDictionary::Set(isolate, cache, serial_number, object);
344
    if (*new_cache != *cache) {
345
      native_context->set_slow_template_instantiations_cache(*new_cache);
346
    }
347 348 349 350
    data->set_serial_number(serial_number);
  } else {
    // we've overflowed the cache limit, no more caching
    data->set_serial_number(TemplateInfo::kDoNotCache);
351 352 353
  }
}

354 355
void UncacheTemplateInstantiation(Isolate* isolate,
                                  Handle<NativeContext> native_context,
356 357 358 359 360 361
                                  Handle<TemplateInfo> data,
                                  CachingMode caching_mode) {
  int serial_number = data->serial_number();
  if (serial_number < 0) return;

  if (serial_number < TemplateInfo::kFastTemplateInstantiationsCacheSize) {
362 363
    FixedArray fast_cache =
        native_context->fast_template_instantiations_cache();
364 365 366
    DCHECK(!fast_cache.get(serial_number).IsUndefined(isolate));
    fast_cache.set_undefined(serial_number);
    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 373
    InternalIndex entry = cache->FindEntry(isolate, serial_number);
    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
}

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 387
  if (fun.shared().function_data(kAcquireLoad) != info.constructor())
    return false;
388
  if (info.immutable_proto()) return false;
389
  return fun.native_context() == isolate->raw_native_context();
390 391
}

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 402 403
      constructor = Handle<JSFunction>::cast(new_target);
    } else {
      // Disable caching for subclass instantiation.
404
      should_cache = false;
405 406 407 408
    }
  }
  // Fast path.
  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 421
      constructor = isolate->object_function();
    } else {
422 423 424 425 426 427
      // Enter a new scope.  Recursion could otherwise create a lot of handles.
      HandleScope scope(isolate);
      Handle<FunctionTemplateInfo> cons_templ(
          FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
      Handle<JSFunction> tmp_constructor;
      ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
428 429
                                 InstantiateFunction(isolate, cons_templ),
                                 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 438 439 440
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, object,
      JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
      JSObject);
441

442
  if (is_prototype) JSObject::OptimizeAsPrototype(object);
443

444
  ASSIGN_RETURN_ON_EXCEPTION(
445
      isolate, result, ConfigureInstance(isolate, object, info), JSObject);
446 447 448
  if (info->immutable_proto()) {
    JSObject::SetImmutableProto(object);
  }
449 450 451 452 453
  if (!is_prototype) {
    // Keep prototypes in slow-mode. Let them be lazily turned fast later on.
    // TODO(dcarney): is this necessary?
    JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
    // Don't cache prototypes.
454 455 456
    if (should_cache) {
      CacheTemplateInstantiation(isolate, isolate->native_context(), info,
                                 CachingMode::kLimited, result);
457 458
      result = isolate->factory()->CopyJSObject(result);
    }
459
  }
460

461
  return result;
462 463
}

464 465
namespace {
MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
466
                                         Handle<Object> function_template) {
467 468 469 470 471 472
  // Enter a new scope.  Recursion could otherwise create a lot of handles.
  HandleScope scope(isolate);
  Handle<JSFunction> parent_instance;
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, parent_instance,
      InstantiateFunction(
473
          isolate, Handle<FunctionTemplateInfo>::cast(function_template)),
474 475 476 477 478
      JSFunction);
  Handle<Object> instance_prototype;
  // TODO(cbruni): decide what to do here.
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, instance_prototype,
479
      JSObject::GetProperty(isolate, parent_instance,
480 481 482 483 484
                            isolate->factory()->prototype_string()),
      JSFunction);
  return scope.CloseAndEscape(instance_prototype);
}
}  // namespace
485

486 487 488
MaybeHandle<JSFunction> InstantiateFunction(
    Isolate* isolate, Handle<NativeContext> native_context,
    Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
489
  RCS_SCOPE(isolate, RuntimeCallCounterId::kInstantiateFunction);
490 491
  bool should_cache = data->should_cache();
  if (should_cache && data->is_cached()) {
492
    Handle<JSObject> result;
493
    if (ProbeInstantiationsCache(isolate, native_context, data->serial_number(),
494 495
                                 CachingMode::kUnlimited)
            .ToHandle(&result)) {
496
      return Handle<JSFunction>::cast(result);
497 498
    }
  }
499
  Handle<Object> prototype;
500
  if (!data->remove_prototype()) {
501 502 503 504 505
    Handle<Object> prototype_templ(data->GetPrototypeTemplate(), isolate);
    if (prototype_templ->IsUndefined(isolate)) {
      Handle<Object> protoype_provider_templ(
          data->GetPrototypeProviderTemplate(), isolate);
      if (protoype_provider_templ->IsUndefined(isolate)) {
506 507 508 509 510 511
        prototype = isolate->factory()->NewJSObject(isolate->object_function());
      } else {
        ASSIGN_RETURN_ON_EXCEPTION(
            isolate, prototype,
            GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
      }
512 513 514
    } else {
      ASSIGN_RETURN_ON_EXCEPTION(
          isolate, prototype,
515 516 517
          InstantiateObject(isolate,
                            Handle<ObjectTemplateInfo>::cast(prototype_templ),
                            Handle<JSReceiver>(), true),
518 519
          JSFunction);
    }
520 521
    Handle<Object> parent(data->GetParentTemplate(), isolate);
    if (!parent->IsUndefined(isolate)) {
522
      Handle<Object> parent_prototype;
523 524 525
      ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
                                 GetInstancePrototype(isolate, parent),
                                 JSFunction);
526
      CHECK(parent_prototype->IsHeapObject());
527
      JSObject::ForceSetPrototype(isolate, Handle<JSObject>::cast(prototype),
528
                                  Handle<HeapObject>::cast(parent_prototype));
529 530
    }
  }
531 532 533 534 535 536 537 538
  InstanceType function_type = JS_SPECIAL_API_OBJECT_TYPE;
  if (!data->needs_access_check() &&
      data->GetNamedPropertyHandler().IsUndefined(isolate) &&
      data->GetIndexedPropertyHandler().IsUndefined(isolate)) {
    function_type = FLAG_embedder_instance_types && data->HasInstanceType()
                        ? static_cast<InstanceType>(data->InstanceType())
                        : JS_API_OBJECT_TYPE;
  }
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 551
    UncacheTemplateInstantiation(isolate, native_context, data,
                                 CachingMode::kUnlimited);
552 553
    return MaybeHandle<JSFunction>();
  }
554
  data->set_published(true);
555
  return function;
556 557
}

dcarney's avatar
dcarney committed
558 559
void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
                               int length, Handle<Object>* data) {
560
  Object maybe_list = templ->property_list();
561
  Handle<TemplateList> list;
562
  if (maybe_list.IsUndefined(isolate)) {
563 564 565
    list = TemplateList::New(isolate, length);
  } else {
    list = handle(TemplateList::cast(maybe_list), isolate);
dcarney's avatar
dcarney committed
566
  }
567
  templ->set_number_of_properties(templ->number_of_properties() + 1);
dcarney's avatar
dcarney committed
568 569 570 571 572
  for (int i = 0; i < length; i++) {
    Handle<Object> value =
        data[i].is_null()
            ? Handle<Object>::cast(isolate->factory()->undefined_value())
            : data[i];
573
    list = TemplateList::Add(isolate, list, value);
dcarney's avatar
dcarney committed
574
  }
575
  templ->set_property_list(*list);
dcarney's avatar
dcarney committed
576 577
}

578 579
}  // namespace

580 581 582 583 584 585 586 587
MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
    Isolate* isolate, Handle<NativeContext> native_context,
    Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
  InvokeScope invoke_scope(isolate);
  return ::v8::internal::InstantiateFunction(isolate, native_context, data,
                                             maybe_name);
}

588
MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
589
    Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
590 591
  Isolate* isolate = data->GetIsolate();
  InvokeScope invoke_scope(isolate);
592
  return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
593 594 595
}

MaybeHandle<JSObject> ApiNatives::InstantiateObject(
596 597
    Isolate* isolate, Handle<ObjectTemplateInfo> data,
    Handle<JSReceiver> new_target) {
598
  InvokeScope invoke_scope(isolate);
599
  return ::v8::internal::InstantiateObject(isolate, data, new_target, false);
600 601
}

602 603 604 605 606 607
MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
    Handle<ObjectTemplateInfo> data) {
  Isolate* isolate = data->GetIsolate();
  InvokeScope invoke_scope(isolate);

  Handle<FunctionTemplateInfo> constructor(
608
      FunctionTemplateInfo::cast(data->constructor()), isolate);
609 610
  Handle<Map> object_map = isolate->factory()->NewMap(
      JS_SPECIAL_API_OBJECT_TYPE,
611 612
      JSObject::kHeaderSize +
          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 620
  JSObject::ForceSetPrototype(isolate, object,
                              isolate->factory()->null_value());
621 622 623

  return object;
}
624

dcarney's avatar
dcarney committed
625 626 627
void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
                                 Handle<Name> name, Handle<Object> value,
                                 PropertyAttributes attributes) {
628 629
  PropertyDetails details(PropertyKind::kData, attributes,
                          PropertyConstness::kMutable);
630
  auto details_handle = handle(details.AsSmi(), isolate);
631 632
  Handle<Object> data[] = {name, details_handle, value};
  AddPropertyToPropertyList(isolate, info, arraysize(data), data);
dcarney's avatar
dcarney committed
633 634
}

635 636 637 638 639
void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
                                 Handle<Name> name, v8::Intrinsic intrinsic,
                                 PropertyAttributes attributes) {
  auto value = handle(Smi::FromInt(intrinsic), isolate);
  auto intrinsic_marker = isolate->factory()->true_value();
640 641
  PropertyDetails details(PropertyKind::kData, attributes,
                          PropertyConstness::kMutable);
642
  auto details_handle = handle(details.AsSmi(), isolate);
643 644
  Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
  AddPropertyToPropertyList(isolate, info, arraysize(data), data);
645 646
}

dcarney's avatar
dcarney committed
647 648
void ApiNatives::AddAccessorProperty(Isolate* isolate,
                                     Handle<TemplateInfo> info,
649 650 651
                                     Handle<Name> name,
                                     Handle<FunctionTemplateInfo> getter,
                                     Handle<FunctionTemplateInfo> setter,
dcarney's avatar
dcarney committed
652
                                     PropertyAttributes attributes) {
653 654
  if (!getter.is_null()) getter->set_published(true);
  if (!setter.is_null()) setter->set_published(true);
655 656
  PropertyDetails details(PropertyKind::kAccessor, attributes,
                          PropertyConstness::kMutable);
657
  auto details_handle = handle(details.AsSmi(), isolate);
658 659
  Handle<Object> data[] = {name, details_handle, getter, setter};
  AddPropertyToPropertyList(isolate, info, arraysize(data), data);
dcarney's avatar
dcarney committed
660 661 662 663 664
}

void ApiNatives::AddNativeDataProperty(Isolate* isolate,
                                       Handle<TemplateInfo> info,
                                       Handle<AccessorInfo> property) {
665
  Object maybe_list = info->property_accessors();
666
  Handle<TemplateList> list;
667
  if (maybe_list.IsUndefined(isolate)) {
668 669 670
    list = TemplateList::New(isolate, 1);
  } else {
    list = handle(TemplateList::cast(maybe_list), isolate);
dcarney's avatar
dcarney committed
671
  }
672 673
  list = TemplateList::Add(isolate, list, property);
  info->set_property_accessors(*list);
dcarney's avatar
dcarney committed
674 675
}

676
Handle<JSFunction> ApiNatives::CreateApiFunction(
677 678 679
    Isolate* isolate, Handle<NativeContext> native_context,
    Handle<FunctionTemplateInfo> obj, Handle<Object> prototype,
    InstanceType type, MaybeHandle<Name> maybe_name) {
680
  RCS_SCOPE(isolate, RuntimeCallCounterId::kCreateApiFunction);
681
  Handle<SharedFunctionInfo> shared =
682 683 684
      FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
                                                          maybe_name);
  // 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 696 697 698 699
    return result;
  }

  // Down from here is only valid for API functions that can be used as a
  // constructor (don't set the "remove prototype" flag).
700
  DCHECK(result->has_prototype_slot());
701

702 703 704 705 706
  if (obj->read_only_prototype()) {
    result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
  }

  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 711 712 713
                          isolate->factory()->constructor_string(), result,
                          DONT_ENUM);
  }

714
  int embedder_field_count = 0;
715
  bool immutable_proto = false;
716
  if (!obj->GetInstanceTemplate().IsUndefined(isolate)) {
717 718 719 720
    Handle<ObjectTemplateInfo> GetInstanceTemplate = Handle<ObjectTemplateInfo>(
        ObjectTemplateInfo::cast(obj->GetInstanceTemplate()), isolate);
    embedder_field_count = GetInstanceTemplate->embedder_field_count();
    immutable_proto = GetInstanceTemplate->immutable_proto();
721 722
  }

723 724
  // JSFunction requires information about the prototype slot.
  DCHECK(!InstanceTypeChecker::IsJSFunction(type));
725 726
  int instance_size = JSObject::GetHeaderSize(type) +
                      kEmbedderDataSlotSize * embedder_field_count;
727

728 729
  Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
                                               TERMINAL_FAST_ELEMENTS_KIND);
730 731 732

  // Mark as undetectable if needed.
  if (obj->undetectable()) {
733 734 735 736 737
    // We only allow callable undetectable receivers here, since this whole
    // undetectable business is only to support document.all, which is both
    // undetectable and callable. If we ever see the need to have an object
    // that is undetectable but not callable, we need to update the types.h
    // to allow encoding this.
738
    CHECK(!obj->GetInstanceCallHandler().IsUndefined(isolate));
739
    map->set_is_undetectable(true);
740
  }
741

742 743 744
  // Mark as needs_access_check if needed.
  if (obj->needs_access_check()) {
    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 766
  JSFunction::SetInitialMap(isolate, result, map,
                            Handle<JSObject>::cast(prototype));
767 768 769 770 771
  return result;
}

}  // namespace internal
}  // namespace v8