api-natives.cc 22.3 KB
Newer Older
1 2 3 4 5
// 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.

#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 13 14

namespace v8 {
namespace internal {

15

16 17
namespace {

dcarney's avatar
dcarney committed
18
MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
19 20
                                        Handle<ObjectTemplateInfo> data,
                                        bool is_hidden_prototype);
dcarney's avatar
dcarney committed
21 22 23 24 25 26 27 28 29 30 31 32

MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
                                            Handle<FunctionTemplateInfo> data,
                                            Handle<Name> name = Handle<Name>());


MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data,
                                Handle<Name> name = Handle<Name>()) {
  if (data->IsFunctionTemplateInfo()) {
    return InstantiateFunction(isolate,
                               Handle<FunctionTemplateInfo>::cast(data), name);
  } else if (data->IsObjectTemplateInfo()) {
33 34
    return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
                             false);
dcarney's avatar
dcarney committed
35 36 37
  } else {
    return data;
  }
38 39
}

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
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());
  if (force_instantiate) {
    if (getter->IsFunctionTemplateInfo()) {
      ASSIGN_RETURN_ON_EXCEPTION(
          isolate, getter,
          InstantiateFunction(isolate,
                              Handle<FunctionTemplateInfo>::cast(getter)),
          Object);
    }
    if (setter->IsFunctionTemplateInfo()) {
      ASSIGN_RETURN_ON_EXCEPTION(
          isolate, setter,
          InstantiateFunction(isolate,
                              Handle<FunctionTemplateInfo>::cast(setter)),
          Object);
    }
dcarney's avatar
dcarney committed
63
  }
64 65
  RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
                                                        setter, attributes),
dcarney's avatar
dcarney committed
66
                      Object);
67 68 69 70
  return object;
}


dcarney's avatar
dcarney committed
71 72
MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
                                       Handle<JSObject> object,
73
                                       Handle<Name> name,
dcarney's avatar
dcarney committed
74
                                       Handle<Object> prop_data,
75
                                       PropertyAttributes attributes) {
dcarney's avatar
dcarney committed
76 77
  Handle<Object> value;
  ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
78
                             Instantiate(isolate, prop_data, name), Object);
dcarney's avatar
dcarney committed
79

80 81
  LookupIterator it = LookupIterator::PropertyOrElement(
      isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
82

83
#ifdef DEBUG
84 85 86
  Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
  DCHECK(maybe.IsJust());
  if (it.IsFound()) {
87
    THROW_NEW_ERROR(
88 89
        isolate,
        NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
90
        Object);
91 92 93
  }
#endif

94 95 96 97
  MAYBE_RETURN_NULL(
      Object::AddDataProperty(&it, value, attributes, Object::THROW_ON_ERROR,
                              Object::CERTAINLY_NOT_STORE_FROM_KEYED));
  return value;
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
}


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


void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
  Handle<Map> old_map(object->map());
  // Copy map so it won't interfere constructor's initial map.
  Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
  new_map->set_is_access_check_needed(true);
  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_;
};


142 143 144 145 146 147 148 149 150 151 152 153 154
Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
  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
  }
  return nullptr;
}

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
// Returns parent function template or null.
FunctionTemplateInfo* GetParent(FunctionTemplateInfo* data) {
  Object* parent = data->parent_template();
  return parent->IsUndefined() ? nullptr : FunctionTemplateInfo::cast(parent);
}

// Starting from given object template's constructor walk up the inheritance
// chain till a function template that has an instance template is found.
ObjectTemplateInfo* GetParent(ObjectTemplateInfo* data) {
  Object* maybe_ctor = data->constructor();
  if (maybe_ctor->IsUndefined()) return nullptr;
  FunctionTemplateInfo* ctor = FunctionTemplateInfo::cast(maybe_ctor);
  while (true) {
    ctor = GetParent(ctor);
    if (ctor == nullptr) return nullptr;
    Object* maybe_obj = ctor->instance_template();
    if (!maybe_obj->IsUndefined()) return ObjectTemplateInfo::cast(maybe_obj);
  }
}
174

175
template <typename TemplateInfoT>
176
MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
177 178
                                        Handle<TemplateInfoT> data,
                                        bool is_hidden_prototype) {
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
  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;
  TemplateInfoT* info = *data;
  while (info != nullptr) {
    if (!info->property_accessors()->IsUndefined()) {
      Object* props = info->property_accessors();
      if (!props->IsUndefined()) {
        Handle<Object> props_handle(props, isolate);
        NeanderArray props_array(props_handle);
        max_number_of_properties += props_array.length();
      }
    }
    info = GetParent(info);
  }

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

    info = *data;
    while (info != nullptr) {
      // Accumulate accessors.
      if (!info->property_accessors()->IsUndefined()) {
        Handle<Object> props(info->property_accessors(), isolate);
        valid_descriptors =
            AccessorInfo::AppendUnique(props, array, valid_descriptors);
      }
      info = GetParent(info);
    }

    // Install accumulated accessors.
    for (int i = 0; i < valid_descriptors; i++) {
      Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
      JSObject::SetAccessor(obj, accessor).Assert();
    }
  }

222 223 224 225 226
  auto property_list = handle(data->property_list(), isolate);
  if (property_list->IsUndefined()) return obj;
  // TODO(dcarney): just use a FixedArray here.
  NeanderArray properties(property_list);
  if (properties.length() == 0) return obj;
227 228 229 230

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

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

257 258 259
      v8::Intrinsic intrinsic =
          static_cast<v8::Intrinsic>(Smi::cast(properties.get(i++))->value());
      auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
260

dcarney's avatar
dcarney committed
261 262
      RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
                                                      prop_data, attributes),
263 264 265 266 267 268
                          JSObject);
    }
  }
  return obj;
}

269
void CacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number,
270 271
                                Handle<JSObject> object) {
  auto cache = isolate->template_instantiations_cache();
272 273
  auto new_cache =
      UnseededNumberDictionary::AtNumberPut(cache, serial_number, object);
274 275 276
  isolate->native_context()->set_template_instantiations_cache(*new_cache);
}

277
void UncacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number) {
278
  auto cache = isolate->template_instantiations_cache();
279
  int entry = cache->FindEntry(serial_number);
280 281 282 283 284 285
  DCHECK(entry != UnseededNumberDictionary::kNotFound);
  Handle<Object> result =
      UnseededNumberDictionary::DeleteProperty(cache, entry);
  USE(result);
  DCHECK(result->IsTrue());
  auto new_cache = UnseededNumberDictionary::Shrink(cache, entry);
286 287 288
  isolate->native_context()->set_template_instantiations_cache(*new_cache);
}

289
MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
290 291
                                        Handle<ObjectTemplateInfo> info,
                                        bool is_hidden_prototype) {
292 293
  // Fast path.
  Handle<JSObject> result;
294 295 296
  uint32_t serial_number =
      static_cast<uint32_t>(Smi::cast(info->serial_number())->value());
  if (serial_number) {
297 298
    // Probe cache.
    auto cache = isolate->template_instantiations_cache();
299
    int entry = cache->FindEntry(serial_number);
300 301
    if (entry != UnseededNumberDictionary::kNotFound) {
      Object* boilerplate = cache->ValueAt(entry);
302
      result = handle(JSObject::cast(boilerplate), isolate);
303
      return isolate->factory()->CopyJSObject(result);
304 305
    }
  }
306 307 308 309 310 311 312 313 314 315 316
  // Enter a new scope.  Recursion could otherwise create a lot of handles.
  HandleScope scope(isolate);
  auto constructor = handle(info->constructor(), isolate);
  Handle<JSFunction> cons;
  if (constructor->IsUndefined()) {
    cons = isolate->object_function();
  } else {
    auto cons_templ = Handle<FunctionTemplateInfo>::cast(constructor);
    ASSIGN_RETURN_ON_EXCEPTION(
        isolate, cons, InstantiateFunction(isolate, cons_templ), JSFunction);
  }
317 318
  auto object = isolate->factory()->NewJSObject(cons);
  ASSIGN_RETURN_ON_EXCEPTION(
319 320 321
      isolate, result,
      ConfigureInstance(isolate, object, info, is_hidden_prototype),
      JSFunction);
322 323
  // TODO(dcarney): is this necessary?
  JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
324

325
  if (serial_number) {
326
    CacheTemplateInstantiation(isolate, serial_number, result);
327
    result = isolate->factory()->CopyJSObject(result);
328 329
  }
  return scope.CloseAndEscape(result);
330 331 332
}


333 334 335
MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
                                            Handle<FunctionTemplateInfo> data,
                                            Handle<Name> name) {
336 337 338
  uint32_t serial_number =
      static_cast<uint32_t>(Smi::cast(data->serial_number())->value());
  if (serial_number) {
339 340
    // Probe cache.
    auto cache = isolate->template_instantiations_cache();
341
    int entry = cache->FindEntry(serial_number);
342 343
    if (entry != UnseededNumberDictionary::kNotFound) {
      Object* element = cache->ValueAt(entry);
344
      return handle(JSFunction::cast(element), isolate);
345 346 347 348 349 350 351 352 353 354 355 356 357
    }
  }
  // Enter a new scope.  Recursion could otherwise create a lot of handles.
  HandleScope scope(isolate);
  Handle<JSObject> prototype;
  if (!data->remove_prototype()) {
    auto prototype_templ = handle(data->prototype_template(), isolate);
    if (prototype_templ->IsUndefined()) {
      prototype = isolate->factory()->NewJSObject(isolate->object_function());
    } else {
      ASSIGN_RETURN_ON_EXCEPTION(
          isolate, prototype,
          InstantiateObject(isolate,
358 359
                            Handle<ObjectTemplateInfo>::cast(prototype_templ),
                            data->hidden_prototype()),
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
          JSFunction);
    }
    auto parent = handle(data->parent_template(), isolate);
    if (!parent->IsUndefined()) {
      Handle<JSFunction> parent_instance;
      ASSIGN_RETURN_ON_EXCEPTION(
          isolate, parent_instance,
          InstantiateFunction(isolate,
                              Handle<FunctionTemplateInfo>::cast(parent)),
          JSFunction);
      // TODO(dcarney): decide what to do here.
      Handle<Object> parent_prototype;
      ASSIGN_RETURN_ON_EXCEPTION(
          isolate, parent_prototype,
          JSObject::GetProperty(parent_instance,
                                isolate->factory()->prototype_string()),
          JSFunction);
377
      MAYBE_RETURN(JSObject::SetPrototype(prototype, parent_prototype, false,
378
                                          Object::THROW_ON_ERROR),
379
                   MaybeHandle<JSFunction>());
380 381 382 383 384 385 386
    }
  }
  auto function = ApiNatives::CreateApiFunction(
      isolate, data, prototype, ApiNatives::JavaScriptObjectType);
  if (!name.is_null() && name->IsString()) {
    function->shared()->set_name(*name);
  }
387
  if (serial_number) {
388
    // Cache the function.
389
    CacheTemplateInstantiation(isolate, serial_number, function);
390
  }
391 392
  auto result =
      ConfigureInstance(isolate, function, data, data->hidden_prototype());
393
  if (result.is_null()) {
394
    // Uncache on error.
395
    if (serial_number) {
396
      UncacheTemplateInstantiation(isolate, serial_number);
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
    }
    return MaybeHandle<JSFunction>();
  }
  return scope.CloseAndEscape(function);
}


class InvokeScope {
 public:
  explicit InvokeScope(Isolate* isolate)
      : isolate_(isolate), save_context_(isolate) {}
  ~InvokeScope() {
    bool has_exception = isolate_->has_pending_exception();
    if (has_exception) {
      isolate_->ReportPendingMessages();
    } else {
      isolate_->clear_pending_message();
    }
  }

 private:
  Isolate* isolate_;
  SaveContext save_context_;
};

dcarney's avatar
dcarney committed
422 423 424 425 426 427 428 429

void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
                               int length, Handle<Object>* data) {
  auto list = handle(templ->property_list(), isolate);
  if (list->IsUndefined()) {
    list = NeanderArray(isolate).value();
    templ->set_property_list(*list);
  }
430
  templ->set_number_of_properties(templ->number_of_properties() + 1);
dcarney's avatar
dcarney committed
431 432 433 434 435 436 437 438 439 440
  NeanderArray array(list);
  for (int i = 0; i < length; i++) {
    Handle<Object> value =
        data[i].is_null()
            ? Handle<Object>::cast(isolate->factory()->undefined_value())
            : data[i];
    array.add(isolate, value);
  }
}

441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
}  // namespace


MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
    Handle<FunctionTemplateInfo> data) {
  Isolate* isolate = data->GetIsolate();
  InvokeScope invoke_scope(isolate);
  return ::v8::internal::InstantiateFunction(isolate, data);
}


MaybeHandle<JSObject> ApiNatives::InstantiateObject(
    Handle<ObjectTemplateInfo> data) {
  Isolate* isolate = data->GetIsolate();
  InvokeScope invoke_scope(isolate);
456
  return ::v8::internal::InstantiateObject(isolate, data, false);
457 458 459
}


dcarney's avatar
dcarney committed
460 461 462 463
void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
                                 Handle<Name> name, Handle<Object> value,
                                 PropertyAttributes attributes) {
  const int kSize = 3;
464 465 466
  PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
  auto details_handle = handle(details.AsSmi(), isolate);
  Handle<Object> data[kSize] = {name, details_handle, value};
dcarney's avatar
dcarney committed
467 468 469 470
  AddPropertyToPropertyList(isolate, info, kSize, data);
}


471 472 473 474 475 476 477 478 479 480 481 482 483
void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
                                 Handle<Name> name, v8::Intrinsic intrinsic,
                                 PropertyAttributes attributes) {
  const int kSize = 4;
  auto value = handle(Smi::FromInt(intrinsic), isolate);
  auto intrinsic_marker = isolate->factory()->true_value();
  PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
  auto details_handle = handle(details.AsSmi(), isolate);
  Handle<Object> data[kSize] = {name, intrinsic_marker, details_handle, value};
  AddPropertyToPropertyList(isolate, info, kSize, data);
}


dcarney's avatar
dcarney committed
484 485
void ApiNatives::AddAccessorProperty(Isolate* isolate,
                                     Handle<TemplateInfo> info,
486 487 488
                                     Handle<Name> name,
                                     Handle<FunctionTemplateInfo> getter,
                                     Handle<FunctionTemplateInfo> setter,
dcarney's avatar
dcarney committed
489 490
                                     PropertyAttributes attributes) {
  const int kSize = 4;
491 492 493
  PropertyDetails details(attributes, ACCESSOR, 0, PropertyCellType::kNoCell);
  auto details_handle = handle(details.AsSmi(), isolate);
  Handle<Object> data[kSize] = {name, details_handle, getter, setter};
dcarney's avatar
dcarney committed
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
  AddPropertyToPropertyList(isolate, info, kSize, data);
}


void ApiNatives::AddNativeDataProperty(Isolate* isolate,
                                       Handle<TemplateInfo> info,
                                       Handle<AccessorInfo> property) {
  auto list = handle(info->property_accessors(), isolate);
  if (list->IsUndefined()) {
    list = NeanderArray(isolate).value();
    info->set_property_accessors(*list);
  }
  NeanderArray array(list);
  array.add(isolate, property);
}


511 512 513
Handle<JSFunction> ApiNatives::CreateApiFunction(
    Isolate* isolate, Handle<FunctionTemplateInfo> obj,
    Handle<Object> prototype, ApiInstanceType instance_type) {
514 515 516 517 518 519 520
  Handle<Code> code;
  if (obj->call_code()->IsCallHandlerInfo() &&
      CallHandlerInfo::cast(obj->call_code())->fast_handler()->IsCode()) {
    code = isolate->builtins()->HandleFastApiCall();
  } else {
    code = isolate->builtins()->HandleApiCall();
  }
521 522 523
  Handle<Code> construct_stub =
      prototype.is_null() ? isolate->builtins()->ConstructedNonConstructable()
                          : isolate->builtins()->JSConstructStubApi();
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544

  obj->set_instantiated(true);
  Handle<JSFunction> result;
  if (obj->remove_prototype()) {
    result = isolate->factory()->NewFunctionWithoutPrototype(
        isolate->factory()->empty_string(), code);
  } else {
    int internal_field_count = 0;
    if (!obj->instance_template()->IsUndefined()) {
      Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
          ObjectTemplateInfo::cast(obj->instance_template()));
      internal_field_count =
          Smi::cast(instance_template->internal_field_count())->value();
    }

    // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
    // JSObject::GetHeaderSize.
    int instance_size = kPointerSize * internal_field_count;
    InstanceType type;
    switch (instance_type) {
      case JavaScriptObjectType:
545 546 547
        if (!obj->needs_access_check() &&
            obj->named_property_handler()->IsUndefined() &&
            obj->indexed_property_handler()->IsUndefined()) {
548
          type = JS_API_OBJECT_TYPE;
549 550 551
        } else {
          type = JS_SPECIAL_API_OBJECT_TYPE;
        }
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
        instance_size += JSObject::kHeaderSize;
        break;
      case GlobalObjectType:
        type = JS_GLOBAL_OBJECT_TYPE;
        instance_size += JSGlobalObject::kSize;
        break;
      case GlobalProxyType:
        type = JS_GLOBAL_PROXY_TYPE;
        instance_size += JSGlobalProxy::kSize;
        break;
      default:
        UNREACHABLE();
        type = JS_OBJECT_TYPE;  // Keep the compiler happy.
        break;
    }

    result = isolate->factory()->NewFunction(
        isolate->factory()->empty_string(), code, prototype, type,
        instance_size, obj->read_only_prototype(), true);
  }

  result->shared()->set_length(obj->length());
  Handle<Object> class_name(obj->class_name(), isolate);
  if (class_name->IsString()) {
    result->shared()->set_instance_class_name(*class_name);
    result->shared()->set_name(*class_name);
  }
579
  result->shared()->set_api_func_data(*obj);
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
  result->shared()->set_construct_stub(*construct_stub);
  result->shared()->DontAdaptArguments();

  if (obj->remove_prototype()) {
    DCHECK(result->shared()->IsApiFunction());
    DCHECK(!result->has_initial_map());
    DCHECK(!result->has_prototype());
    return result;
  }

#ifdef DEBUG
  LookupIterator it(handle(JSObject::cast(result->prototype())),
                    isolate->factory()->constructor_string(),
                    LookupIterator::OWN_SKIP_INTERCEPTOR);
  MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
  DCHECK(it.IsFound());
  DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
#endif

  // Down from here is only valid for API functions that can be used as a
  // constructor (don't set the "remove prototype" flag).

  Handle<Map> map(result->initial_map());

  // Mark as undetectable if needed.
  if (obj->undetectable()) {
    map->set_is_undetectable();
  }

  // Mark as needs_access_check if needed.
  if (obj->needs_access_check()) {
    map->set_is_access_check_needed(true);
  }

  // Set interceptor information in the map.
  if (!obj->named_property_handler()->IsUndefined()) {
    map->set_has_named_interceptor();
  }
  if (!obj->indexed_property_handler()->IsUndefined()) {
    map->set_has_indexed_interceptor();
  }

622
  // Mark instance as callable in the map.
623
  if (!obj->instance_call_handler()->IsUndefined()) {
624
    map->set_is_callable();
625
    map->set_is_constructor(true);
626 627 628 629 630 631 632 633
  }

  DCHECK(result->shared()->IsApiFunction());
  return result;
}

}  // namespace internal
}  // namespace v8