api-natives.cc 27.4 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/isolate-inl.h"
9
#include "src/message-template.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 17 18 19 20

namespace v8 {
namespace internal {

namespace {

21 22
class InvokeScope {
 public:
23 24
  explicit InvokeScope(Isolate* isolate)
      : isolate_(isolate), save_context_(isolate) {}
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 37 38
  SaveContext save_context_;
};

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

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

49 50 51
MaybeHandle<Object> Instantiate(
    Isolate* isolate, Handle<Object> data,
    MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
dcarney's avatar
dcarney committed
52
  if (data->IsFunctionTemplateInfo()) {
53 54
    return InstantiateFunction(
        isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
dcarney's avatar
dcarney committed
55
  } else if (data->IsObjectTemplateInfo()) {
56
    return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
57
                             Handle<JSReceiver>(), false, false);
dcarney's avatar
dcarney committed
58 59 60
  } else {
    return data;
  }
61 62
}

63 64 65 66 67 68 69 70
MaybeHandle<Object> DefineAccessorProperty(
    Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
    Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
    bool force_instantiate) {
  DCHECK(!getter->IsFunctionTemplateInfo() ||
         !FunctionTemplateInfo::cast(*getter)->do_not_cache());
  DCHECK(!setter->IsFunctionTemplateInfo() ||
         !FunctionTemplateInfo::cast(*setter)->do_not_cache());
71 72 73
  if (getter->IsFunctionTemplateInfo()) {
    if (force_instantiate ||
        FunctionTemplateInfo::cast(*getter)->BreakAtEntry()) {
74 75 76 77 78 79
      ASSIGN_RETURN_ON_EXCEPTION(
          isolate, getter,
          InstantiateFunction(isolate,
                              Handle<FunctionTemplateInfo>::cast(getter)),
          Object);
    }
80 81 82 83
  }
  if (setter->IsFunctionTemplateInfo()) {
    if (force_instantiate ||
        FunctionTemplateInfo::cast(*setter)->BreakAtEntry()) {
84 85 86 87 88 89
      ASSIGN_RETURN_ON_EXCEPTION(
          isolate, setter,
          InstantiateFunction(isolate,
                              Handle<FunctionTemplateInfo>::cast(setter)),
          Object);
    }
dcarney's avatar
dcarney committed
90
  }
91 92 93 94
  RETURN_ON_EXCEPTION(
      isolate,
      JSObject::DefineAccessor(object, name, getter, setter, attributes),
      Object);
95 96 97
  return object;
}

dcarney's avatar
dcarney committed
98 99
MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
                                       Handle<JSObject> object,
100
                                       Handle<Name> name,
dcarney's avatar
dcarney committed
101
                                       Handle<Object> prop_data,
102
                                       PropertyAttributes attributes) {
dcarney's avatar
dcarney committed
103 104
  Handle<Object> value;
  ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
105
                             Instantiate(isolate, prop_data, name), Object);
dcarney's avatar
dcarney committed
106

107 108
  LookupIterator it = LookupIterator::PropertyOrElement(
      isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
109

110
#ifdef DEBUG
111 112 113
  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
  DCHECK(maybe.IsJust());
  if (it.IsFound()) {
114
    THROW_NEW_ERROR(
115 116
        isolate,
        NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
117
        Object);
118 119 120
  }
#endif

121 122 123
  MAYBE_RETURN_NULL(Object::AddDataProperty(&it, value, attributes,
                                            Just(ShouldThrow::kThrowOnError),
                                            StoreOrigin::kNamed));
124
  return value;
125 126 127
}

void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
128
  Handle<Map> old_map(object->map(), isolate);
129
  // Copy map so it won't interfere constructor's initial map.
130
  Handle<Map> new_map = Map::Copy(isolate, old_map, "DisableAccessChecks");
131 132 133 134 135
  new_map->set_is_access_check_needed(false);
  JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
}

void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
136
  Handle<Map> old_map(object->map(), isolate);
137
  // Copy map so it won't interfere constructor's initial map.
138
  Handle<Map> new_map = Map::Copy(isolate, old_map, "EnableAccessChecks");
139
  new_map->set_is_access_check_needed(true);
140
  new_map->set_may_have_interesting_symbols(true);
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
  JSObject::MigrateToMap(object, new_map);
}

class AccessCheckDisableScope {
 public:
  AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
      : isolate_(isolate),
        disabled_(obj->map()->is_access_check_needed()),
        obj_(obj) {
    if (disabled_) {
      DisableAccessChecks(isolate_, obj_);
    }
  }
  ~AccessCheckDisableScope() {
    if (disabled_) {
      EnableAccessChecks(isolate_, obj_);
    }
  }

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

166
Object GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
167 168 169 170 171 172 173 174 175
  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
  }
176
  return Object();
177 178
}

179
template <typename TemplateInfoT>
180
MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
181 182
                                        Handle<TemplateInfoT> data,
                                        bool is_hidden_prototype) {
183 184 185 186 187 188
  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;
189 190
  TemplateInfoT info = *data;
  while (!info.is_null()) {
191
    Object props = info->property_accessors();
192 193
    if (!props->IsUndefined(isolate)) {
      max_number_of_properties += TemplateList::cast(props)->length();
194
    }
195
    info = info->GetParent(isolate);
196 197 198 199 200 201 202 203
  }

  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);

204
    for (Handle<TemplateInfoT> temp(*data, isolate); !temp->is_null();
205
         temp = handle(temp->GetParent(isolate), isolate)) {
206
      // Accumulate accessors.
207
      Object maybe_properties = temp->property_accessors();
208 209
      if (!maybe_properties->IsUndefined(isolate)) {
        valid_descriptors = AccessorInfo::AppendUnique(
210 211
            isolate, handle(maybe_properties, isolate), array,
            valid_descriptors);
212 213 214 215 216
      }
    }

    // Install accumulated accessors.
    for (int i = 0; i < valid_descriptors; i++) {
217
      Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)), isolate);
218 219 220 221
      Handle<Name> name(Name::cast(accessor->name()), isolate);
      JSObject::SetAccessor(obj, name, accessor,
                            accessor->initial_property_attributes())
          .Assert();
222 223 224
    }
  }

225
  Object maybe_property_list = data->property_list();
226 227 228 229
  if (maybe_property_list->IsUndefined(isolate)) return obj;
  Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
                                  isolate);
  if (properties->length() == 0) return obj;
230 231 232

  int i = 0;
  for (int c = 0; c < data->number_of_properties(); c++) {
233
    auto name = handle(Name::cast(properties->get(i++)), isolate);
234
    Object bit = properties->get(i++);
235
    if (bit->IsSmi()) {
236
      PropertyDetails details(Smi::cast(bit));
237 238 239 240
      PropertyAttributes attributes = details.attributes();
      PropertyKind kind = details.kind();

      if (kind == kData) {
241
        auto prop_data = handle(properties->get(i++), isolate);
242 243 244 245
        RETURN_ON_EXCEPTION(
            isolate,
            DefineDataProperty(isolate, obj, name, prop_data, attributes),
            JSObject);
246
      } else {
247 248
        auto getter = handle(properties->get(i++), isolate);
        auto setter = handle(properties->get(i++), isolate);
249
        RETURN_ON_EXCEPTION(
250 251 252
            isolate,
            DefineAccessorProperty(isolate, obj, name, getter, setter,
                                   attributes, is_hidden_prototype),
253
            JSObject);
254 255 256 257
      }
    } else {
      // Intrinsic data property --- Get appropriate value from the current
      // context.
258
      PropertyDetails details(Smi::cast(properties->get(i++)));
259 260
      PropertyAttributes attributes = details.attributes();
      DCHECK_EQ(kData, details.kind());
261

262
      v8::Intrinsic intrinsic =
jgruber's avatar
jgruber committed
263
          static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
264
      auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
265

266 267 268 269
      RETURN_ON_EXCEPTION(
          isolate,
          DefineDataProperty(isolate, obj, name, prop_data, attributes),
          JSObject);
270 271 272 273 274
    }
  }
  return obj;
}

275 276 277 278 279 280 281 282
// 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 };

283
MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
284 285
                                               int serial_number,
                                               CachingMode caching_mode) {
286 287 288 289 290
  DCHECK_LE(1, serial_number);
  if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
    Handle<FixedArray> fast_cache =
        isolate->fast_template_instantiations_cache();
    return fast_cache->GetValue<JSObject>(isolate, serial_number - 1);
291 292 293
  } else if (caching_mode == CachingMode::kUnlimited ||
             (serial_number <=
              TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
294
    Handle<SimpleNumberDictionary> slow_cache =
295
        isolate->slow_template_instantiations_cache();
296
    int entry = slow_cache->FindEntry(isolate, serial_number);
297
    if (entry == SimpleNumberDictionary::kNotFound) {
298 299 300
      return MaybeHandle<JSObject>();
    }
    return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
301 302
  } else {
    return MaybeHandle<JSObject>();
303 304 305 306
  }
}

void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
307
                                CachingMode caching_mode,
308
                                Handle<JSObject> object) {
309 310 311 312 313
  DCHECK_LE(1, serial_number);
  if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
    Handle<FixedArray> fast_cache =
        isolate->fast_template_instantiations_cache();
    Handle<FixedArray> new_cache =
314
        FixedArray::SetAndGrow(isolate, fast_cache, serial_number - 1, object);
315 316 317 318
    if (*new_cache != *fast_cache) {
      isolate->native_context()->set_fast_template_instantiations_cache(
          *new_cache);
    }
319 320 321
  } else if (caching_mode == CachingMode::kUnlimited ||
             (serial_number <=
              TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
322
    Handle<SimpleNumberDictionary> cache =
323
        isolate->slow_template_instantiations_cache();
324 325
    auto new_cache =
        SimpleNumberDictionary::Set(isolate, cache, serial_number, object);
326 327 328 329 330 331 332
    if (*new_cache != *cache) {
      isolate->native_context()->set_slow_template_instantiations_cache(
          *new_cache);
    }
  }
}

333 334
void UncacheTemplateInstantiation(Isolate* isolate, int serial_number,
                                  CachingMode caching_mode) {
335 336 337 338 339 340
  DCHECK_LE(1, serial_number);
  if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
    Handle<FixedArray> fast_cache =
        isolate->fast_template_instantiations_cache();
    DCHECK(!fast_cache->get(serial_number - 1)->IsUndefined(isolate));
    fast_cache->set_undefined(serial_number - 1);
341 342 343
  } else if (caching_mode == CachingMode::kUnlimited ||
             (serial_number <=
              TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
344
    Handle<SimpleNumberDictionary> cache =
345
        isolate->slow_template_instantiations_cache();
346
    int entry = cache->FindEntry(isolate, serial_number);
347
    DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
348
    cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry);
349
    isolate->native_context()->set_slow_template_instantiations_cache(*cache);
350
  }
351 352
}

353
bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo info,
354
                           JSReceiver new_target) {
355 356 357
  DisallowHeapAllocation no_gc;

  if (!new_target->IsJSFunction()) return false;
358
  JSFunction fun = JSFunction::cast(new_target);
359 360
  if (fun->shared()->function_data() != info->constructor()) return false;
  if (info->immutable_proto()) return false;
361
  return fun->context()->native_context() == isolate->raw_native_context();
362 363
}

364
MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
365
                                        Handle<ObjectTemplateInfo> info,
366
                                        Handle<JSReceiver> new_target,
367 368
                                        bool is_hidden_prototype,
                                        bool is_prototype) {
369
  Handle<JSFunction> constructor;
jgruber's avatar
jgruber committed
370
  int serial_number = Smi::ToInt(info->serial_number());
371
  if (!new_target.is_null()) {
372
    if (IsSimpleInstantiation(isolate, *info, *new_target)) {
373 374 375 376 377 378 379 380
      constructor = Handle<JSFunction>::cast(new_target);
    } else {
      // Disable caching for subclass instantiation.
      serial_number = 0;
    }
  }
  // Fast path.
  Handle<JSObject> result;
381
  if (serial_number) {
382 383
    if (ProbeInstantiationsCache(isolate, serial_number, CachingMode::kLimited)
            .ToHandle(&result)) {
384
      return isolate->factory()->CopyJSObject(result);
385 386
    }
  }
387 388

  if (constructor.is_null()) {
389
    Object maybe_constructor_info = info->constructor();
390
    if (maybe_constructor_info->IsUndefined(isolate)) {
391 392
      constructor = isolate->object_function();
    } else {
393 394 395 396 397 398
      // 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,
399 400
                                 InstantiateFunction(isolate, cons_templ),
                                 JSObject);
401
      constructor = scope.CloseAndEscape(tmp_constructor);
402 403 404
    }

    if (new_target.is_null()) new_target = constructor;
405
  }
406 407

  Handle<JSObject> object;
408 409 410 411
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, object,
      JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
      JSObject);
412

413
  if (is_prototype) JSObject::OptimizeAsPrototype(object);
414

415
  ASSIGN_RETURN_ON_EXCEPTION(
416
      isolate, result,
417
      ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject);
418 419 420
  if (info->immutable_proto()) {
    JSObject::SetImmutableProto(object);
  }
421 422 423 424 425 426
  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.
    if (serial_number) {
427 428
      CacheTemplateInstantiation(isolate, serial_number, CachingMode::kLimited,
                                 result);
429 430
      result = isolate->factory()->CopyJSObject(result);
    }
431
  }
432

433
  return result;
434 435
}

436 437
namespace {
MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
438
                                         Object function_template) {
439 440 441 442 443 444 445 446 447 448 449 450 451
  // 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(
          isolate,
          handle(FunctionTemplateInfo::cast(function_template), isolate)),
      JSFunction);
  Handle<Object> instance_prototype;
  // TODO(cbruni): decide what to do here.
  ASSIGN_RETURN_ON_EXCEPTION(
      isolate, instance_prototype,
452
      JSObject::GetProperty(isolate, parent_instance,
453 454 455 456 457
                            isolate->factory()->prototype_string()),
      JSFunction);
  return scope.CloseAndEscape(instance_prototype);
}
}  // namespace
458

459 460
MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
                                            Handle<FunctionTemplateInfo> data,
461
                                            MaybeHandle<Name> maybe_name) {
jgruber's avatar
jgruber committed
462
  int serial_number = Smi::ToInt(data->serial_number());
463
  if (serial_number) {
464
    Handle<JSObject> result;
465 466 467
    if (ProbeInstantiationsCache(isolate, serial_number,
                                 CachingMode::kUnlimited)
            .ToHandle(&result)) {
468
      return Handle<JSFunction>::cast(result);
469 470
    }
  }
471
  Handle<Object> prototype;
472
  if (!data->remove_prototype()) {
473
    Object prototype_templ = data->GetPrototypeTemplate();
474
    if (prototype_templ->IsUndefined(isolate)) {
475
      Object protoype_provider_templ = data->GetPrototypeProviderTemplate();
476 477 478 479 480 481 482
      if (protoype_provider_templ->IsUndefined(isolate)) {
        prototype = isolate->factory()->NewJSObject(isolate->object_function());
      } else {
        ASSIGN_RETURN_ON_EXCEPTION(
            isolate, prototype,
            GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
      }
483 484 485
    } else {
      ASSIGN_RETURN_ON_EXCEPTION(
          isolate, prototype,
486 487 488
          InstantiateObject(
              isolate,
              handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
489
              Handle<JSReceiver>(), data->hidden_prototype(), true),
490 491
          JSFunction);
    }
492
    Object parent = data->GetParentTemplate();
493 494
    if (!parent->IsUndefined(isolate)) {
      Handle<Object> parent_prototype;
495 496 497
      ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
                                 GetInstancePrototype(isolate, parent),
                                 JSFunction);
498
      CHECK(parent_prototype->IsHeapObject());
499
      JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
500
                                  Handle<HeapObject>::cast(parent_prototype));
501 502
    }
  }
503 504
  InstanceType function_type =
      (!data->needs_access_check() &&
505 506
       data->GetNamedPropertyHandler()->IsUndefined(isolate) &&
       data->GetIndexedPropertyHandler()->IsUndefined(isolate))
507 508 509
          ? JS_API_OBJECT_TYPE
          : JS_SPECIAL_API_OBJECT_TYPE;

510
  Handle<JSFunction> function = ApiNatives::CreateApiFunction(
511
      isolate, data, prototype, function_type, maybe_name);
512
  if (serial_number) {
513
    // Cache the function.
514 515
    CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
                               function);
516
  }
517
  MaybeHandle<JSObject> result =
518
      ConfigureInstance(isolate, function, data, data->hidden_prototype());
519
  if (result.is_null()) {
520
    // Uncache on error.
521
    if (serial_number) {
522 523
      UncacheTemplateInstantiation(isolate, serial_number,
                                   CachingMode::kUnlimited);
524 525 526
    }
    return MaybeHandle<JSFunction>();
  }
527
  return function;
528 529
}

dcarney's avatar
dcarney committed
530 531
void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
                               int length, Handle<Object>* data) {
532
  Object maybe_list = templ->property_list();
533 534 535 536 537
  Handle<TemplateList> list;
  if (maybe_list->IsUndefined(isolate)) {
    list = TemplateList::New(isolate, length);
  } else {
    list = handle(TemplateList::cast(maybe_list), isolate);
dcarney's avatar
dcarney committed
538
  }
539
  templ->set_number_of_properties(templ->number_of_properties() + 1);
dcarney's avatar
dcarney committed
540 541 542 543 544
  for (int i = 0; i < length; i++) {
    Handle<Object> value =
        data[i].is_null()
            ? Handle<Object>::cast(isolate->factory()->undefined_value())
            : data[i];
545
    list = TemplateList::Add(isolate, list, value);
dcarney's avatar
dcarney committed
546
  }
547
  templ->set_property_list(*list);
dcarney's avatar
dcarney committed
548 549
}

550 551 552
}  // namespace

MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
553
    Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
554 555
  Isolate* isolate = data->GetIsolate();
  InvokeScope invoke_scope(isolate);
556
  return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
557 558 559
}

MaybeHandle<JSObject> ApiNatives::InstantiateObject(
560 561
    Isolate* isolate, Handle<ObjectTemplateInfo> data,
    Handle<JSReceiver> new_target) {
562
  InvokeScope invoke_scope(isolate);
563 564
  return ::v8::internal::InstantiateObject(isolate, data, new_target, false,
                                           false);
565 566
}

567 568 569 570 571 572
MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
    Handle<ObjectTemplateInfo> data) {
  Isolate* isolate = data->GetIsolate();
  InvokeScope invoke_scope(isolate);

  Handle<FunctionTemplateInfo> constructor(
573
      FunctionTemplateInfo::cast(data->constructor()), isolate);
574 575
  Handle<Map> object_map = isolate->factory()->NewMap(
      JS_SPECIAL_API_OBJECT_TYPE,
576 577
      JSObject::kHeaderSize +
          data->embedder_field_count() * kEmbedderDataSlotSize,
578
      TERMINAL_FAST_ELEMENTS_KIND);
579
  object_map->SetConstructor(*constructor);
580
  object_map->set_is_access_check_needed(true);
581
  object_map->set_may_have_interesting_symbols(true);
582

583
  Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(object_map);
584 585 586 587
  JSObject::ForceSetPrototype(object, isolate->factory()->null_value());

  return object;
}
588

dcarney's avatar
dcarney committed
589 590 591
void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
                                 Handle<Name> name, Handle<Object> value,
                                 PropertyAttributes attributes) {
592
  PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
593
  auto details_handle = handle(details.AsSmi(), isolate);
594 595
  Handle<Object> data[] = {name, details_handle, value};
  AddPropertyToPropertyList(isolate, info, arraysize(data), data);
dcarney's avatar
dcarney committed
596 597
}

598 599 600 601 602
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();
603
  PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
604
  auto details_handle = handle(details.AsSmi(), isolate);
605 606
  Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
  AddPropertyToPropertyList(isolate, info, arraysize(data), data);
607 608
}

dcarney's avatar
dcarney committed
609 610
void ApiNatives::AddAccessorProperty(Isolate* isolate,
                                     Handle<TemplateInfo> info,
611 612 613
                                     Handle<Name> name,
                                     Handle<FunctionTemplateInfo> getter,
                                     Handle<FunctionTemplateInfo> setter,
dcarney's avatar
dcarney committed
614
                                     PropertyAttributes attributes) {
615
  PropertyDetails details(kAccessor, attributes, PropertyCellType::kNoCell);
616
  auto details_handle = handle(details.AsSmi(), isolate);
617 618
  Handle<Object> data[] = {name, details_handle, getter, setter};
  AddPropertyToPropertyList(isolate, info, arraysize(data), data);
dcarney's avatar
dcarney committed
619 620 621 622 623
}

void ApiNatives::AddNativeDataProperty(Isolate* isolate,
                                       Handle<TemplateInfo> info,
                                       Handle<AccessorInfo> property) {
624
  Object maybe_list = info->property_accessors();
625 626 627 628 629
  Handle<TemplateList> list;
  if (maybe_list->IsUndefined(isolate)) {
    list = TemplateList::New(isolate, 1);
  } else {
    list = handle(TemplateList::cast(maybe_list), isolate);
dcarney's avatar
dcarney committed
630
  }
631 632
  list = TemplateList::Add(isolate, list, property);
  info->set_property_accessors(*list);
dcarney's avatar
dcarney committed
633 634
}

635
Handle<JSFunction> ApiNatives::CreateApiFunction(
636
    Isolate* isolate, Handle<FunctionTemplateInfo> obj,
637
    Handle<Object> prototype, InstanceType type, MaybeHandle<Name> maybe_name) {
638
  Handle<SharedFunctionInfo> shared =
639 640 641
      FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
                                                          maybe_name);
  // To simplify things, API functions always have shared name.
642
  DCHECK(shared->HasSharedName());
643

644 645 646
  Handle<JSFunction> result =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(
          shared, isolate->native_context());
647 648

  if (obj->remove_prototype()) {
649 650
    DCHECK(prototype.is_null());
    DCHECK(result->shared()->IsApiFunction());
651
    DCHECK(!result->IsConstructor());
652
    DCHECK(!result->has_prototype_slot());
653 654 655 656 657
    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).
658
  DCHECK(result->has_prototype_slot());
659

660 661 662 663 664
  if (obj->read_only_prototype()) {
    result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
  }

  if (prototype->IsTheHole(isolate)) {
665
    prototype = isolate->factory()->NewFunctionPrototype(result);
666
  } else if (obj->GetPrototypeProviderTemplate()->IsUndefined(isolate)) {
667
    JSObject::AddProperty(isolate, Handle<JSObject>::cast(prototype),
668 669 670 671
                          isolate->factory()->constructor_string(), result,
                          DONT_ENUM);
  }

672
  int embedder_field_count = 0;
673
  bool immutable_proto = false;
674 675 676 677 678
  if (!obj->GetInstanceTemplate()->IsUndefined(isolate)) {
    Handle<ObjectTemplateInfo> GetInstanceTemplate = Handle<ObjectTemplateInfo>(
        ObjectTemplateInfo::cast(obj->GetInstanceTemplate()), isolate);
    embedder_field_count = GetInstanceTemplate->embedder_field_count();
    immutable_proto = GetInstanceTemplate->immutable_proto();
679 680
  }

681 682
  // JS_FUNCTION_TYPE requires information about the prototype slot.
  DCHECK_NE(JS_FUNCTION_TYPE, type);
683 684
  int instance_size = JSObject::GetHeaderSize(type) +
                      kEmbedderDataSlotSize * embedder_field_count;
685

686 687
  Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
                                               TERMINAL_FAST_ELEMENTS_KIND);
688 689 690 691
  JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));

  // Mark as undetectable if needed.
  if (obj->undetectable()) {
692 693 694 695 696
    // 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.
697
    CHECK(!obj->GetInstanceCallHandler()->IsUndefined(isolate));
698
    map->set_is_undetectable(true);
699
  }
700

701 702 703
  // Mark as needs_access_check if needed.
  if (obj->needs_access_check()) {
    map->set_is_access_check_needed(true);
704
    map->set_may_have_interesting_symbols(true);
705 706 707
  }

  // Set interceptor information in the map.
708
  if (!obj->GetNamedPropertyHandler()->IsUndefined(isolate)) {
709
    map->set_has_named_interceptor(true);
710
    map->set_may_have_interesting_symbols(true);
711
  }
712
  if (!obj->GetIndexedPropertyHandler()->IsUndefined(isolate)) {
713
    map->set_has_indexed_interceptor(true);
714
  }
715 716

  // Mark instance as callable in the map.
717
  if (!obj->GetInstanceCallHandler()->IsUndefined(isolate)) {
718
    map->set_is_callable(true);
719
    map->set_is_constructor(!obj->undetectable());
720 721
  }

722
  if (immutable_proto) map->set_is_immutable_proto(true);
723

724 725 726 727 728
  return result;
}

}  // namespace internal
}  // namespace v8