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 namespace { 399 MaybeHandle<Object> GetInstancePrototype(Isolate* isolate, 400 Object* function_template) { 401 // Enter a new scope. Recursion could otherwise create a lot of handles. 402 HandleScope scope(isolate); 403 Handle<JSFunction> parent_instance; 404 ASSIGN_RETURN_ON_EXCEPTION( 405 isolate, parent_instance, 406 InstantiateFunction( 407 isolate, 408 handle(FunctionTemplateInfo::cast(function_template), isolate)), 409 JSFunction); 410 Handle<Object> instance_prototype; 411 // TODO(cbruni): decide what to do here. 412 ASSIGN_RETURN_ON_EXCEPTION( 413 isolate, instance_prototype, 414 JSObject::GetProperty(parent_instance, 415 isolate->factory()->prototype_string()), 416 JSFunction); 417 return scope.CloseAndEscape(instance_prototype); 418 } 419 } // namespace 420 421 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate, 422 Handle<FunctionTemplateInfo> data, 423 Handle<Name> name) { 424 int serial_number = Smi::cast(data->serial_number())->value(); 425 if (serial_number) { 426 Handle<JSObject> result; 427 if (ProbeInstantiationsCache(isolate, serial_number).ToHandle(&result)) { 428 return Handle<JSFunction>::cast(result); 429 } 430 } 431 Handle<Object> prototype; 432 if (!data->remove_prototype()) { 433 Object* prototype_templ = data->prototype_template(); 434 if (prototype_templ->IsUndefined(isolate)) { 435 Object* protoype_provider_templ = data->prototype_provider_template(); 436 if (protoype_provider_templ->IsUndefined(isolate)) { 437 prototype = isolate->factory()->NewJSObject(isolate->object_function()); 438 } else { 439 ASSIGN_RETURN_ON_EXCEPTION( 440 isolate, prototype, 441 GetInstancePrototype(isolate, protoype_provider_templ), JSFunction); 442 } 443 } else { 444 ASSIGN_RETURN_ON_EXCEPTION( 445 isolate, prototype, 446 InstantiateObject( 447 isolate, 448 handle(ObjectTemplateInfo::cast(prototype_templ), isolate), 449 Handle<JSReceiver>(), data->hidden_prototype()), 450 JSFunction); 451 } 452 Object* parent = data->parent_template(); 453 if (!parent->IsUndefined(isolate)) { 454 Handle<Object> parent_prototype; 455 ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype, 456 GetInstancePrototype(isolate, parent), 457 JSFunction); 458 JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype), 459 parent_prototype); 460 } 461 } 462 Handle<JSFunction> function = ApiNatives::CreateApiFunction( 463 isolate, data, prototype, ApiNatives::JavaScriptObjectType); 464 if (!name.is_null() && name->IsString()) { 465 function->shared()->set_name(*name); 466 } 467 if (serial_number) { 468 // Cache the function. 469 CacheTemplateInstantiation(isolate, serial_number, function); 470 } 471 MaybeHandle<JSObject> result = 472 ConfigureInstance(isolate, function, data, data->hidden_prototype()); 473 if (result.is_null()) { 474 // Uncache on error. 475 if (serial_number) { 476 UncacheTemplateInstantiation(isolate, serial_number); 477 } 478 return MaybeHandle<JSFunction>(); 479 } 480 return function; 481 } 482 483 484 void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ, 485 int length, Handle<Object>* data) { 486 Object* maybe_list = templ->property_list(); 487 Handle<TemplateList> list; 488 if (maybe_list->IsUndefined(isolate)) { 489 list = TemplateList::New(isolate, length); 490 } else { 491 list = handle(TemplateList::cast(maybe_list), isolate); 492 } 493 templ->set_number_of_properties(templ->number_of_properties() + 1); 494 for (int i = 0; i < length; i++) { 495 Handle<Object> value = 496 data[i].is_null() 497 ? Handle<Object>::cast(isolate->factory()->undefined_value()) 498 : data[i]; 499 list = TemplateList::Add(isolate, list, value); 500 } 501 templ->set_property_list(*list); 502 } 503 504 } // namespace 505 506 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction( 507 Handle<FunctionTemplateInfo> data) { 508 Isolate* isolate = data->GetIsolate(); 509 InvokeScope invoke_scope(isolate); 510 return ::v8::internal::InstantiateFunction(isolate, data); 511 } 512 513 MaybeHandle<JSObject> ApiNatives::InstantiateObject( 514 Handle<ObjectTemplateInfo> data, Handle<JSReceiver> new_target) { 515 Isolate* isolate = data->GetIsolate(); 516 InvokeScope invoke_scope(isolate); 517 return ::v8::internal::InstantiateObject(isolate, data, new_target, false); 518 } 519 520 MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject( 521 Handle<ObjectTemplateInfo> data) { 522 Isolate* isolate = data->GetIsolate(); 523 InvokeScope invoke_scope(isolate); 524 525 Handle<FunctionTemplateInfo> constructor( 526 FunctionTemplateInfo::cast(data->constructor())); 527 Handle<SharedFunctionInfo> shared = 528 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, constructor); 529 Handle<Map> initial_map = isolate->factory()->CreateSloppyFunctionMap( 530 FUNCTION_WITH_WRITEABLE_PROTOTYPE); 531 Handle<JSFunction> object_function = 532 isolate->factory()->NewFunctionFromSharedFunctionInfo( 533 initial_map, shared, isolate->factory()->undefined_value()); 534 Handle<Map> object_map = isolate->factory()->NewMap( 535 JS_SPECIAL_API_OBJECT_TYPE, 536 JSObject::kHeaderSize + data->internal_field_count() * kPointerSize, 537 FAST_HOLEY_SMI_ELEMENTS); 538 JSFunction::SetInitialMap(object_function, object_map, 539 isolate->factory()->null_value()); 540 object_map->set_is_access_check_needed(true); 541 542 Handle<JSObject> object = isolate->factory()->NewJSObject(object_function); 543 JSObject::ForceSetPrototype(object, isolate->factory()->null_value()); 544 545 return object; 546 } 547 548 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info, 549 Handle<Name> name, Handle<Object> value, 550 PropertyAttributes attributes) { 551 PropertyDetails details(kData, attributes, 0, PropertyCellType::kNoCell); 552 auto details_handle = handle(details.AsSmi(), isolate); 553 Handle<Object> data[] = {name, details_handle, value}; 554 AddPropertyToPropertyList(isolate, info, arraysize(data), data); 555 } 556 557 558 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info, 559 Handle<Name> name, v8::Intrinsic intrinsic, 560 PropertyAttributes attributes) { 561 auto value = handle(Smi::FromInt(intrinsic), isolate); 562 auto intrinsic_marker = isolate->factory()->true_value(); 563 PropertyDetails details(kData, attributes, 0, PropertyCellType::kNoCell); 564 auto details_handle = handle(details.AsSmi(), isolate); 565 Handle<Object> data[] = {name, intrinsic_marker, details_handle, value}; 566 AddPropertyToPropertyList(isolate, info, arraysize(data), data); 567 } 568 569 570 void ApiNatives::AddAccessorProperty(Isolate* isolate, 571 Handle<TemplateInfo> info, 572 Handle<Name> name, 573 Handle<FunctionTemplateInfo> getter, 574 Handle<FunctionTemplateInfo> setter, 575 PropertyAttributes attributes) { 576 PropertyDetails details(kAccessor, attributes, 0, PropertyCellType::kNoCell); 577 auto details_handle = handle(details.AsSmi(), isolate); 578 Handle<Object> data[] = {name, details_handle, getter, setter}; 579 AddPropertyToPropertyList(isolate, info, arraysize(data), data); 580 } 581 582 583 void ApiNatives::AddNativeDataProperty(Isolate* isolate, 584 Handle<TemplateInfo> info, 585 Handle<AccessorInfo> property) { 586 Object* maybe_list = info->property_accessors(); 587 Handle<TemplateList> list; 588 if (maybe_list->IsUndefined(isolate)) { 589 list = TemplateList::New(isolate, 1); 590 } else { 591 list = handle(TemplateList::cast(maybe_list), isolate); 592 } 593 list = TemplateList::Add(isolate, list, property); 594 info->set_property_accessors(*list); 595 } 596 597 598 Handle<JSFunction> ApiNatives::CreateApiFunction( 599 Isolate* isolate, Handle<FunctionTemplateInfo> obj, 600 Handle<Object> prototype, ApiInstanceType instance_type) { 601 Handle<SharedFunctionInfo> shared = 602 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj); 603 Handle<JSFunction> result = 604 isolate->factory()->NewFunctionFromSharedFunctionInfo( 605 shared, isolate->native_context()); 606 607 if (obj->remove_prototype()) { 608 result->set_map(*isolate->sloppy_function_without_prototype_map()); 609 DCHECK(prototype.is_null()); 610 DCHECK(result->shared()->IsApiFunction()); 611 DCHECK(!result->has_initial_map()); 612 DCHECK(!result->has_prototype()); 613 DCHECK(!result->IsConstructor()); 614 return result; 615 } 616 617 // Down from here is only valid for API functions that can be used as a 618 // constructor (don't set the "remove prototype" flag). 619 620 if (obj->read_only_prototype()) { 621 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map()); 622 } 623 624 if (prototype->IsTheHole(isolate)) { 625 prototype = isolate->factory()->NewFunctionPrototype(result); 626 } else if (obj->prototype_provider_template()->IsUndefined(isolate)) { 627 JSObject::AddProperty(Handle<JSObject>::cast(prototype), 628 isolate->factory()->constructor_string(), result, 629 DONT_ENUM); 630 } 631 632 int internal_field_count = 0; 633 bool immutable_proto = false; 634 if (!obj->instance_template()->IsUndefined(isolate)) { 635 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>( 636 ObjectTemplateInfo::cast(obj->instance_template())); 637 internal_field_count = instance_template->internal_field_count(); 638 immutable_proto = instance_template->immutable_proto(); 639 } 640 641 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing 642 // JSObject::GetHeaderSize. 643 int instance_size = kPointerSize * internal_field_count; 644 InstanceType type; 645 switch (instance_type) { 646 case JavaScriptObjectType: 647 if (!obj->needs_access_check() && 648 obj->named_property_handler()->IsUndefined(isolate) && 649 obj->indexed_property_handler()->IsUndefined(isolate)) { 650 type = JS_API_OBJECT_TYPE; 651 } else { 652 type = JS_SPECIAL_API_OBJECT_TYPE; 653 } 654 instance_size += JSObject::kHeaderSize; 655 break; 656 case GlobalObjectType: 657 type = JS_GLOBAL_OBJECT_TYPE; 658 instance_size += JSGlobalObject::kSize; 659 break; 660 case GlobalProxyType: 661 type = JS_GLOBAL_PROXY_TYPE; 662 instance_size += JSGlobalProxy::kSize; 663 break; 664 default: 665 UNREACHABLE(); 666 type = JS_OBJECT_TYPE; // Keep the compiler happy. 667 break; 668 } 669 670 Handle<Map> map = 671 isolate->factory()->NewMap(type, instance_size, FAST_HOLEY_SMI_ELEMENTS); 672 JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype)); 673 674 // Mark as undetectable if needed. 675 if (obj->undetectable()) { 676 // We only allow callable undetectable receivers here, since this whole 677 // undetectable business is only to support document.all, which is both 678 // undetectable and callable. If we ever see the need to have an object 679 // that is undetectable but not callable, we need to update the types.h 680 // to allow encoding this. 681 CHECK(!obj->instance_call_handler()->IsUndefined(isolate)); 682 map->set_is_undetectable(); 683 } 684 685 // Mark as needs_access_check if needed. 686 if (obj->needs_access_check()) { 687 map->set_is_access_check_needed(true); 688 } 689 690 // Set interceptor information in the map. 691 if (!obj->named_property_handler()->IsUndefined(isolate)) { 692 map->set_has_named_interceptor(); 693 } 694 if (!obj->indexed_property_handler()->IsUndefined(isolate)) { 695 map->set_has_indexed_interceptor(); 696 } 697 698 // Mark instance as callable in the map. 699 if (!obj->instance_call_handler()->IsUndefined(isolate)) { 700 map->set_is_callable(); 701 map->set_is_constructor(true); 702 } 703 704 if (immutable_proto) map->set_immutable_proto(true); 705 706 return result; 707 } 708 709 } // namespace internal 710 } // namespace v8 711