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 : isolate_(isolate), save_context_(isolate) {} 22 ~InvokeScope() { 23 bool has_exception = isolate_->has_pending_exception(); 24 if (has_exception) { 25 isolate_->ReportPendingMessages(); 26 } else { 27 isolate_->clear_pending_message(); 28 } 29 } 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 41 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate, 42 Handle<FunctionTemplateInfo> data, 43 Handle<Name> name = Handle<Name>()); 44 45 MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data, 46 Handle<Name> name = Handle<Name>()) { 47 if (data->IsFunctionTemplateInfo()) { 48 return InstantiateFunction(isolate, 49 Handle<FunctionTemplateInfo>::cast(data), name); 50 } else if (data->IsObjectTemplateInfo()) { 51 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data), 52 Handle<JSReceiver>(), false); 53 } else { 54 return data; 55 } 56 } 57 58 MaybeHandle<Object> DefineAccessorProperty( 59 Isolate* isolate, Handle<JSObject> object, Handle<Name> name, 60 Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes, 61 bool force_instantiate) { 62 DCHECK(!getter->IsFunctionTemplateInfo() || 63 !FunctionTemplateInfo::cast(*getter)->do_not_cache()); 64 DCHECK(!setter->IsFunctionTemplateInfo() || 65 !FunctionTemplateInfo::cast(*setter)->do_not_cache()); 66 if (force_instantiate) { 67 if (getter->IsFunctionTemplateInfo()) { 68 ASSIGN_RETURN_ON_EXCEPTION( 69 isolate, getter, 70 InstantiateFunction(isolate, 71 Handle<FunctionTemplateInfo>::cast(getter)), 72 Object); 73 } 74 if (setter->IsFunctionTemplateInfo()) { 75 ASSIGN_RETURN_ON_EXCEPTION( 76 isolate, setter, 77 InstantiateFunction(isolate, 78 Handle<FunctionTemplateInfo>::cast(setter)), 79 Object); 80 } 81 } 82 RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter, 83 setter, attributes), 84 Object); 85 return object; 86 } 87 88 89 MaybeHandle<Object> DefineDataProperty(Isolate* isolate, 90 Handle<JSObject> object, 91 Handle<Name> name, 92 Handle<Object> prop_data, 93 PropertyAttributes attributes) { 94 Handle<Object> value; 95 ASSIGN_RETURN_ON_EXCEPTION(isolate, value, 96 Instantiate(isolate, prop_data, name), Object); 97 98 LookupIterator it = LookupIterator::PropertyOrElement( 99 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 100 101 #ifdef DEBUG 102 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 103 DCHECK(maybe.IsJust()); 104 if (it.IsFound()) { 105 THROW_NEW_ERROR( 106 isolate, 107 NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name), 108 Object); 109 } 110 #endif 111 112 MAYBE_RETURN_NULL( 113 Object::AddDataProperty(&it, value, attributes, Object::THROW_ON_ERROR, 114 Object::CERTAINLY_NOT_STORE_FROM_KEYED)); 115 return value; 116 } 117 118 119 void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) { 120 Handle<Map> old_map(object->map()); 121 // Copy map so it won't interfere constructor's initial map. 122 Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks"); 123 new_map->set_is_access_check_needed(false); 124 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map); 125 } 126 127 128 void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) { 129 Handle<Map> old_map(object->map()); 130 // Copy map so it won't interfere constructor's initial map. 131 Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks"); 132 new_map->set_is_access_check_needed(true); 133 JSObject::MigrateToMap(object, new_map); 134 } 135 136 137 class AccessCheckDisableScope { 138 public: 139 AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj) 140 : isolate_(isolate), 141 disabled_(obj->map()->is_access_check_needed()), 142 obj_(obj) { 143 if (disabled_) { 144 DisableAccessChecks(isolate_, obj_); 145 } 146 } 147 ~AccessCheckDisableScope() { 148 if (disabled_) { 149 EnableAccessChecks(isolate_, obj_); 150 } 151 } 152 153 private: 154 Isolate* isolate_; 155 const bool disabled_; 156 Handle<JSObject> obj_; 157 }; 158 159 160 Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) { 161 Handle<Context> native_context = isolate->native_context(); 162 DCHECK(!native_context.is_null()); 163 switch (intrinsic) { 164 #define GET_INTRINSIC_VALUE(name, iname) \ 165 case v8::k##name: \ 166 return native_context->iname(); 167 V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE) 168 #undef GET_INTRINSIC_VALUE 169 } 170 return nullptr; 171 } 172 173 174 template <typename TemplateInfoT> 175 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj, 176 Handle<TemplateInfoT> data, 177 bool is_hidden_prototype) { 178 HandleScope scope(isolate); 179 // Disable access checks while instantiating the object. 180 AccessCheckDisableScope access_check_scope(isolate, obj); 181 182 // Walk the inheritance chain and copy all accessors to current object. 183 int max_number_of_properties = 0; 184 TemplateInfoT* info = *data; 185 while (info != nullptr) { 186 Object* props = info->property_accessors(); 187 if (!props->IsUndefined(isolate)) { 188 max_number_of_properties += TemplateList::cast(props)->length(); 189 } 190 info = info->GetParent(isolate); 191 } 192 193 if (max_number_of_properties > 0) { 194 int valid_descriptors = 0; 195 // Use a temporary FixedArray to accumulate unique accessors. 196 Handle<FixedArray> array = 197 isolate->factory()->NewFixedArray(max_number_of_properties); 198 199 for (Handle<TemplateInfoT> temp(*data); *temp != nullptr; 200 temp = handle(temp->GetParent(isolate), isolate)) { 201 // Accumulate accessors. 202 Object* maybe_properties = temp->property_accessors(); 203 if (!maybe_properties->IsUndefined(isolate)) { 204 valid_descriptors = AccessorInfo::AppendUnique( 205 handle(maybe_properties, isolate), array, valid_descriptors); 206 } 207 } 208 209 // Install accumulated accessors. 210 for (int i = 0; i < valid_descriptors; i++) { 211 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i))); 212 JSObject::SetAccessor(obj, accessor).Assert(); 213 } 214 } 215 216 Object* maybe_property_list = data->property_list(); 217 if (maybe_property_list->IsUndefined(isolate)) return obj; 218 Handle<TemplateList> properties(TemplateList::cast(maybe_property_list), 219 isolate); 220 if (properties->length() == 0) return obj; 221 222 int i = 0; 223 for (int c = 0; c < data->number_of_properties(); c++) { 224 auto name = handle(Name::cast(properties->get(i++)), isolate); 225 Object* bit = properties->get(i++); 226 if (bit->IsSmi()) { 227 PropertyDetails details(Smi::cast(bit)); 228 PropertyAttributes attributes = details.attributes(); 229 PropertyKind kind = details.kind(); 230 231 if (kind == kData) { 232 auto prop_data = handle(properties->get(i++), isolate); 233 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name, 234 prop_data, attributes), 235 JSObject); 236 } else { 237 auto getter = handle(properties->get(i++), isolate); 238 auto setter = handle(properties->get(i++), isolate); 239 RETURN_ON_EXCEPTION( 240 isolate, DefineAccessorProperty(isolate, obj, name, getter, setter, 241 attributes, is_hidden_prototype), 242 JSObject); 243 } 244 } else { 245 // Intrinsic data property --- Get appropriate value from the current 246 // context. 247 PropertyDetails details(Smi::cast(properties->get(i++))); 248 PropertyAttributes attributes = details.attributes(); 249 DCHECK_EQ(kData, details.kind()); 250 251 v8::Intrinsic intrinsic = 252 static_cast<v8::Intrinsic>(Smi::cast(properties->get(i++))->value()); 253 auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate); 254 255 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name, 256 prop_data, attributes), 257 JSObject); 258 } 259 } 260 return obj; 261 } 262 263 MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate, 264 int serial_number) { 265 DCHECK_LE(1, serial_number); 266 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) { 267 Handle<FixedArray> fast_cache = 268 isolate->fast_template_instantiations_cache(); 269 return fast_cache->GetValue<JSObject>(isolate, serial_number - 1); 270 } else { 271 Handle<UnseededNumberDictionary> slow_cache = 272 isolate->slow_template_instantiations_cache(); 273 int entry = slow_cache->FindEntry(serial_number); 274 if (entry == UnseededNumberDictionary::kNotFound) { 275 return MaybeHandle<JSObject>(); 276 } 277 return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate); 278 } 279 } 280 281 void CacheTemplateInstantiation(Isolate* isolate, int serial_number, 282 Handle<JSObject> object) { 283 DCHECK_LE(1, serial_number); 284 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) { 285 Handle<FixedArray> fast_cache = 286 isolate->fast_template_instantiations_cache(); 287 Handle<FixedArray> new_cache = 288 FixedArray::SetAndGrow(fast_cache, serial_number - 1, object); 289 if (*new_cache != *fast_cache) { 290 isolate->native_context()->set_fast_template_instantiations_cache( 291 *new_cache); 292 } 293 } else { 294 Handle<UnseededNumberDictionary> cache = 295 isolate->slow_template_instantiations_cache(); 296 auto new_cache = 297 UnseededNumberDictionary::AtNumberPut(cache, serial_number, object); 298 if (*new_cache != *cache) { 299 isolate->native_context()->set_slow_template_instantiations_cache( 300 *new_cache); 301 } 302 } 303 } 304 305 void UncacheTemplateInstantiation(Isolate* isolate, int serial_number) { 306 DCHECK_LE(1, serial_number); 307 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) { 308 Handle<FixedArray> fast_cache = 309 isolate->fast_template_instantiations_cache(); 310 DCHECK(!fast_cache->get(serial_number - 1)->IsUndefined(isolate)); 311 fast_cache->set_undefined(serial_number - 1); 312 } else { 313 Handle<UnseededNumberDictionary> cache = 314 isolate->slow_template_instantiations_cache(); 315 int entry = cache->FindEntry(serial_number); 316 DCHECK(entry != UnseededNumberDictionary::kNotFound); 317 Handle<Object> result = 318 UnseededNumberDictionary::DeleteProperty(cache, entry); 319 USE(result); 320 DCHECK(result->IsTrue(isolate)); 321 auto new_cache = UnseededNumberDictionary::Shrink(cache, entry); 322 isolate->native_context()->set_slow_template_instantiations_cache( 323 *new_cache); 324 } 325 } 326 327 bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo* info, 328 JSReceiver* new_target) { 329 DisallowHeapAllocation no_gc; 330 331 if (!new_target->IsJSFunction()) return false; 332 JSFunction* fun = JSFunction::cast(new_target); 333 if (fun->shared()->function_data() != info->constructor()) return false; 334 if (info->immutable_proto()) return false; 335 return fun->context()->native_context() == isolate->raw_native_context(); 336 } 337 338 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate, 339 Handle<ObjectTemplateInfo> info, 340 Handle<JSReceiver> new_target, 341 bool is_hidden_prototype) { 342 Handle<JSFunction> constructor; 343 int serial_number = Smi::cast(info->serial_number())->value(); 344 if (!new_target.is_null()) { 345 if (IsSimpleInstantiation(isolate, *info, *new_target)) { 346 constructor = Handle<JSFunction>::cast(new_target); 347 } else { 348 // Disable caching for subclass instantiation. 349 serial_number = 0; 350 } 351 } 352 // Fast path. 353 Handle<JSObject> result; 354 if (serial_number) { 355 if (ProbeInstantiationsCache(isolate, serial_number).ToHandle(&result)) { 356 return isolate->factory()->CopyJSObject(result); 357 } 358 } 359 360 if (constructor.is_null()) { 361 Object* maybe_constructor_info = info->constructor(); 362 if (maybe_constructor_info->IsUndefined(isolate)) { 363 constructor = isolate->object_function(); 364 } else { 365 // Enter a new scope. Recursion could otherwise create a lot of handles. 366 HandleScope scope(isolate); 367 Handle<FunctionTemplateInfo> cons_templ( 368 FunctionTemplateInfo::cast(maybe_constructor_info), isolate); 369 Handle<JSFunction> tmp_constructor; 370 ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor, 371 InstantiateFunction(isolate, cons_templ), 372 JSObject); 373 constructor = scope.CloseAndEscape(tmp_constructor); 374 } 375 376 if (new_target.is_null()) new_target = constructor; 377 } 378 379 Handle<JSObject> object; 380 ASSIGN_RETURN_ON_EXCEPTION(isolate, object, 381 JSObject::New(constructor, new_target), JSObject); 382 ASSIGN_RETURN_ON_EXCEPTION( 383 isolate, result, 384 ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject); 385 if (info->immutable_proto()) { 386 JSObject::SetImmutableProto(object); 387 } 388 // TODO(dcarney): is this necessary? 389 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject"); 390 391 if (serial_number) { 392 CacheTemplateInstantiation(isolate, serial_number, result); 393 result = isolate->factory()->CopyJSObject(result); 394 } 395 return result; 396 } 397 398 399 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate, 400 Handle<FunctionTemplateInfo> data, 401 Handle<Name> name) { 402 int serial_number = Smi::cast(data->serial_number())->value(); 403 if (serial_number) { 404 Handle<JSObject> result; 405 if (ProbeInstantiationsCache(isolate, serial_number).ToHandle(&result)) { 406 return Handle<JSFunction>::cast(result); 407 } 408 } 409 Handle<JSObject> prototype; 410 if (!data->remove_prototype()) { 411 Object* prototype_templ = data->prototype_template(); 412 if (prototype_templ->IsUndefined(isolate)) { 413 prototype = isolate->factory()->NewJSObject(isolate->object_function()); 414 } else { 415 ASSIGN_RETURN_ON_EXCEPTION( 416 isolate, prototype, 417 InstantiateObject( 418 isolate, 419 handle(ObjectTemplateInfo::cast(prototype_templ), isolate), 420 Handle<JSReceiver>(), data->hidden_prototype()), 421 JSFunction); 422 } 423 Object* parent = data->parent_template(); 424 if (!parent->IsUndefined(isolate)) { 425 // Enter a new scope. Recursion could otherwise create a lot of handles. 426 HandleScope scope(isolate); 427 Handle<JSFunction> parent_instance; 428 ASSIGN_RETURN_ON_EXCEPTION( 429 isolate, parent_instance, 430 InstantiateFunction( 431 isolate, handle(FunctionTemplateInfo::cast(parent), isolate)), 432 JSFunction); 433 // TODO(dcarney): decide what to do here. 434 Handle<Object> parent_prototype; 435 ASSIGN_RETURN_ON_EXCEPTION( 436 isolate, parent_prototype, 437 JSObject::GetProperty(parent_instance, 438 isolate->factory()->prototype_string()), 439 JSFunction); 440 JSObject::ForceSetPrototype(prototype, parent_prototype); 441 } 442 } 443 Handle<JSFunction> function = ApiNatives::CreateApiFunction( 444 isolate, data, prototype, ApiNatives::JavaScriptObjectType); 445 if (!name.is_null() && name->IsString()) { 446 function->shared()->set_name(*name); 447 } 448 if (serial_number) { 449 // Cache the function. 450 CacheTemplateInstantiation(isolate, serial_number, function); 451 } 452 MaybeHandle<JSObject> result = 453 ConfigureInstance(isolate, function, data, data->hidden_prototype()); 454 if (result.is_null()) { 455 // Uncache on error. 456 if (serial_number) { 457 UncacheTemplateInstantiation(isolate, serial_number); 458 } 459 return MaybeHandle<JSFunction>(); 460 } 461 return function; 462 } 463 464 465 void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ, 466 int length, Handle<Object>* data) { 467 Object* maybe_list = templ->property_list(); 468 Handle<TemplateList> list; 469 if (maybe_list->IsUndefined(isolate)) { 470 list = TemplateList::New(isolate, length); 471 } else { 472 list = handle(TemplateList::cast(maybe_list), isolate); 473 } 474 templ->set_number_of_properties(templ->number_of_properties() + 1); 475 for (int i = 0; i < length; i++) { 476 Handle<Object> value = 477 data[i].is_null() 478 ? Handle<Object>::cast(isolate->factory()->undefined_value()) 479 : data[i]; 480 list = TemplateList::Add(isolate, list, value); 481 } 482 templ->set_property_list(*list); 483 } 484 485 } // namespace 486 487 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction( 488 Handle<FunctionTemplateInfo> data) { 489 Isolate* isolate = data->GetIsolate(); 490 InvokeScope invoke_scope(isolate); 491 return ::v8::internal::InstantiateFunction(isolate, data); 492 } 493 494 MaybeHandle<JSObject> ApiNatives::InstantiateObject( 495 Handle<ObjectTemplateInfo> data, Handle<JSReceiver> new_target) { 496 Isolate* isolate = data->GetIsolate(); 497 InvokeScope invoke_scope(isolate); 498 return ::v8::internal::InstantiateObject(isolate, data, new_target, false); 499 } 500 501 MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject( 502 Handle<ObjectTemplateInfo> data) { 503 Isolate* isolate = data->GetIsolate(); 504 InvokeScope invoke_scope(isolate); 505 506 Handle<FunctionTemplateInfo> constructor( 507 FunctionTemplateInfo::cast(data->constructor())); 508 Handle<SharedFunctionInfo> shared = 509 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, constructor); 510 Handle<Map> initial_map = isolate->factory()->CreateSloppyFunctionMap( 511 FUNCTION_WITH_WRITEABLE_PROTOTYPE); 512 Handle<JSFunction> object_function = 513 isolate->factory()->NewFunctionFromSharedFunctionInfo( 514 initial_map, shared, isolate->factory()->undefined_value()); 515 Handle<Map> object_map = isolate->factory()->NewMap( 516 JS_SPECIAL_API_OBJECT_TYPE, 517 JSObject::kHeaderSize + data->internal_field_count() * kPointerSize, 518 FAST_HOLEY_SMI_ELEMENTS); 519 JSFunction::SetInitialMap(object_function, object_map, 520 isolate->factory()->null_value()); 521 object_map->set_is_access_check_needed(true); 522 object_map->set_is_callable(); 523 object_map->set_is_constructor(true); 524 525 Handle<JSObject> object = isolate->factory()->NewJSObject(object_function); 526 JSObject::ForceSetPrototype(object, isolate->factory()->null_value()); 527 528 return object; 529 } 530 531 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info, 532 Handle<Name> name, Handle<Object> value, 533 PropertyAttributes attributes) { 534 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); 535 auto details_handle = handle(details.AsSmi(), isolate); 536 Handle<Object> data[] = {name, details_handle, value}; 537 AddPropertyToPropertyList(isolate, info, arraysize(data), data); 538 } 539 540 541 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info, 542 Handle<Name> name, v8::Intrinsic intrinsic, 543 PropertyAttributes attributes) { 544 auto value = handle(Smi::FromInt(intrinsic), isolate); 545 auto intrinsic_marker = isolate->factory()->true_value(); 546 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); 547 auto details_handle = handle(details.AsSmi(), isolate); 548 Handle<Object> data[] = {name, intrinsic_marker, details_handle, value}; 549 AddPropertyToPropertyList(isolate, info, arraysize(data), data); 550 } 551 552 553 void ApiNatives::AddAccessorProperty(Isolate* isolate, 554 Handle<TemplateInfo> info, 555 Handle<Name> name, 556 Handle<FunctionTemplateInfo> getter, 557 Handle<FunctionTemplateInfo> setter, 558 PropertyAttributes attributes) { 559 PropertyDetails details(attributes, ACCESSOR, 0, PropertyCellType::kNoCell); 560 auto details_handle = handle(details.AsSmi(), isolate); 561 Handle<Object> data[] = {name, details_handle, getter, setter}; 562 AddPropertyToPropertyList(isolate, info, arraysize(data), data); 563 } 564 565 566 void ApiNatives::AddNativeDataProperty(Isolate* isolate, 567 Handle<TemplateInfo> info, 568 Handle<AccessorInfo> property) { 569 Object* maybe_list = info->property_accessors(); 570 Handle<TemplateList> list; 571 if (maybe_list->IsUndefined(isolate)) { 572 list = TemplateList::New(isolate, 1); 573 } else { 574 list = handle(TemplateList::cast(maybe_list), isolate); 575 } 576 list = TemplateList::Add(isolate, list, property); 577 info->set_property_accessors(*list); 578 } 579 580 581 Handle<JSFunction> ApiNatives::CreateApiFunction( 582 Isolate* isolate, Handle<FunctionTemplateInfo> obj, 583 Handle<Object> prototype, ApiInstanceType instance_type) { 584 Handle<SharedFunctionInfo> shared = 585 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj); 586 Handle<JSFunction> result = 587 isolate->factory()->NewFunctionFromSharedFunctionInfo( 588 shared, isolate->native_context()); 589 590 if (obj->remove_prototype()) { 591 result->set_map(*isolate->sloppy_function_without_prototype_map()); 592 DCHECK(prototype.is_null()); 593 DCHECK(result->shared()->IsApiFunction()); 594 DCHECK(!result->has_initial_map()); 595 DCHECK(!result->has_prototype()); 596 DCHECK(!result->IsConstructor()); 597 return result; 598 } 599 600 // Down from here is only valid for API functions that can be used as a 601 // constructor (don't set the "remove prototype" flag). 602 603 if (obj->read_only_prototype()) { 604 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map()); 605 } 606 607 if (prototype->IsTheHole(isolate)) { 608 prototype = isolate->factory()->NewFunctionPrototype(result); 609 } else { 610 JSObject::AddProperty(Handle<JSObject>::cast(prototype), 611 isolate->factory()->constructor_string(), result, 612 DONT_ENUM); 613 } 614 615 int internal_field_count = 0; 616 bool immutable_proto = false; 617 if (!obj->instance_template()->IsUndefined(isolate)) { 618 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>( 619 ObjectTemplateInfo::cast(obj->instance_template())); 620 internal_field_count = instance_template->internal_field_count(); 621 immutable_proto = instance_template->immutable_proto(); 622 } 623 624 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing 625 // JSObject::GetHeaderSize. 626 int instance_size = kPointerSize * internal_field_count; 627 InstanceType type; 628 switch (instance_type) { 629 case JavaScriptObjectType: 630 if (!obj->needs_access_check() && 631 obj->named_property_handler()->IsUndefined(isolate) && 632 obj->indexed_property_handler()->IsUndefined(isolate)) { 633 type = JS_API_OBJECT_TYPE; 634 } else { 635 type = JS_SPECIAL_API_OBJECT_TYPE; 636 } 637 instance_size += JSObject::kHeaderSize; 638 break; 639 case GlobalObjectType: 640 type = JS_GLOBAL_OBJECT_TYPE; 641 instance_size += JSGlobalObject::kSize; 642 break; 643 case GlobalProxyType: 644 type = JS_GLOBAL_PROXY_TYPE; 645 instance_size += JSGlobalProxy::kSize; 646 break; 647 default: 648 UNREACHABLE(); 649 type = JS_OBJECT_TYPE; // Keep the compiler happy. 650 break; 651 } 652 653 Handle<Map> map = 654 isolate->factory()->NewMap(type, instance_size, FAST_HOLEY_SMI_ELEMENTS); 655 JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype)); 656 657 // Mark as undetectable if needed. 658 if (obj->undetectable()) { 659 map->set_is_undetectable(); 660 } 661 662 // Mark as needs_access_check if needed. 663 if (obj->needs_access_check()) { 664 map->set_is_access_check_needed(true); 665 } 666 667 // Set interceptor information in the map. 668 if (!obj->named_property_handler()->IsUndefined(isolate)) { 669 map->set_has_named_interceptor(); 670 } 671 if (!obj->indexed_property_handler()->IsUndefined(isolate)) { 672 map->set_has_indexed_interceptor(); 673 } 674 675 // Mark instance as callable in the map. 676 if (!obj->instance_call_handler()->IsUndefined(isolate)) { 677 map->set_is_callable(); 678 map->set_is_constructor(true); 679 } 680 681 if (immutable_proto) map->set_immutable_proto(true); 682 683 return result; 684 } 685 686 } // namespace internal 687 } // namespace v8 688