| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/api-natives.h" | 5 #include "src/api-natives.h" |
| 6 | 6 |
| 7 #include "src/api.h" | 7 #include "src/api.h" |
| 8 #include "src/isolate-inl.h" | 8 #include "src/isolate-inl.h" |
| 9 #include "src/lookup.h" | 9 #include "src/lookup.h" |
| 10 #include "src/messages.h" | 10 #include "src/messages.h" |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 static_cast<uint32_t>(Smi::cast(data->serial_number())->value()); | 364 static_cast<uint32_t>(Smi::cast(data->serial_number())->value()); |
| 365 if (serial_number) { | 365 if (serial_number) { |
| 366 // Probe cache. | 366 // Probe cache. |
| 367 auto cache = isolate->template_instantiations_cache(); | 367 auto cache = isolate->template_instantiations_cache(); |
| 368 int entry = cache->FindEntry(serial_number); | 368 int entry = cache->FindEntry(serial_number); |
| 369 if (entry != UnseededNumberDictionary::kNotFound) { | 369 if (entry != UnseededNumberDictionary::kNotFound) { |
| 370 Object* element = cache->ValueAt(entry); | 370 Object* element = cache->ValueAt(entry); |
| 371 return handle(JSFunction::cast(element), isolate); | 371 return handle(JSFunction::cast(element), isolate); |
| 372 } | 372 } |
| 373 } | 373 } |
| 374 | |
| 375 // Enter a new scope. Recursion could otherwise create a lot of handles. | 374 // Enter a new scope. Recursion could otherwise create a lot of handles. |
| 376 HandleScope scope(isolate); | 375 HandleScope scope(isolate); |
| 377 | 376 Handle<JSObject> prototype; |
| 378 auto function = | 377 if (!data->remove_prototype()) { |
| 379 ApiNatives::CreateApiFunction(isolate, data, JS_API_OBJECT_TYPE); | 378 auto prototype_templ = handle(data->prototype_template(), isolate); |
| 379 if (prototype_templ->IsUndefined(isolate)) { |
| 380 prototype = isolate->factory()->NewJSObject(isolate->object_function()); |
| 381 } else { |
| 382 ASSIGN_RETURN_ON_EXCEPTION( |
| 383 isolate, prototype, |
| 384 InstantiateObject(isolate, |
| 385 Handle<ObjectTemplateInfo>::cast(prototype_templ), |
| 386 Handle<JSReceiver>(), data->hidden_prototype()), |
| 387 JSFunction); |
| 388 } |
| 389 auto parent = handle(data->parent_template(), isolate); |
| 390 if (!parent->IsUndefined(isolate)) { |
| 391 Handle<JSFunction> parent_instance; |
| 392 ASSIGN_RETURN_ON_EXCEPTION( |
| 393 isolate, parent_instance, |
| 394 InstantiateFunction(isolate, |
| 395 Handle<FunctionTemplateInfo>::cast(parent)), |
| 396 JSFunction); |
| 397 // TODO(dcarney): decide what to do here. |
| 398 Handle<Object> parent_prototype; |
| 399 ASSIGN_RETURN_ON_EXCEPTION( |
| 400 isolate, parent_prototype, |
| 401 JSObject::GetProperty(parent_instance, |
| 402 isolate->factory()->prototype_string()), |
| 403 JSFunction); |
| 404 MAYBE_RETURN(JSObject::SetPrototype(prototype, parent_prototype, false, |
| 405 Object::THROW_ON_ERROR), |
| 406 MaybeHandle<JSFunction>()); |
| 407 } |
| 408 } |
| 409 auto function = ApiNatives::CreateApiFunction( |
| 410 isolate, data, prototype, ApiNatives::JavaScriptObjectType); |
| 380 if (!name.is_null() && name->IsString()) { | 411 if (!name.is_null() && name->IsString()) { |
| 381 function->shared()->set_name(*name); | 412 function->shared()->set_name(*name); |
| 382 } | 413 } |
| 383 if (serial_number) { | 414 if (serial_number) { |
| 384 // Cache the function. | 415 // Cache the function. |
| 385 CacheTemplateInstantiation(isolate, serial_number, function); | 416 CacheTemplateInstantiation(isolate, serial_number, function); |
| 386 } | 417 } |
| 387 auto result = | 418 auto result = |
| 388 ConfigureInstance(isolate, function, data, data->hidden_prototype()); | 419 ConfigureInstance(isolate, function, data, data->hidden_prototype()); |
| 389 if (result.is_null()) { | 420 if (result.is_null()) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 Handle<AccessorInfo> property) { | 526 Handle<AccessorInfo> property) { |
| 496 auto list = handle(info->property_accessors(), isolate); | 527 auto list = handle(info->property_accessors(), isolate); |
| 497 if (list->IsUndefined(isolate)) { | 528 if (list->IsUndefined(isolate)) { |
| 498 list = NeanderArray(isolate).value(); | 529 list = NeanderArray(isolate).value(); |
| 499 info->set_property_accessors(*list); | 530 info->set_property_accessors(*list); |
| 500 } | 531 } |
| 501 NeanderArray array(list); | 532 NeanderArray array(list); |
| 502 array.add(isolate, property); | 533 array.add(isolate, property); |
| 503 } | 534 } |
| 504 | 535 |
| 536 |
| 505 Handle<JSFunction> ApiNatives::CreateApiFunction( | 537 Handle<JSFunction> ApiNatives::CreateApiFunction( |
| 506 Isolate* isolate, Handle<FunctionTemplateInfo> obj, InstanceType type) { | 538 Isolate* isolate, Handle<FunctionTemplateInfo> obj, |
| 539 Handle<Object> prototype, ApiInstanceType instance_type) { |
| 507 Handle<SharedFunctionInfo> shared = | 540 Handle<SharedFunctionInfo> shared = |
| 508 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj); | 541 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj); |
| 509 DCHECK(shared->IsApiFunction()); | |
| 510 Handle<JSFunction> result = | 542 Handle<JSFunction> result = |
| 511 isolate->factory()->NewFunctionFromSharedFunctionInfo( | 543 isolate->factory()->NewFunctionFromSharedFunctionInfo( |
| 512 shared, isolate->native_context()); | 544 shared, isolate->native_context()); |
| 513 | 545 |
| 514 if (obj->remove_prototype()) { | 546 if (obj->remove_prototype()) { |
| 515 result->set_map(*isolate->sloppy_function_without_prototype_map()); | 547 result->set_map(*isolate->sloppy_function_without_prototype_map()); |
| 548 DCHECK(prototype.is_null()); |
| 549 DCHECK(result->shared()->IsApiFunction()); |
| 516 DCHECK(!result->has_initial_map()); | 550 DCHECK(!result->has_initial_map()); |
| 517 DCHECK(!result->has_prototype()); | 551 DCHECK(!result->has_prototype()); |
| 518 DCHECK(!result->IsConstructor()); | 552 DCHECK(!result->IsConstructor()); |
| 519 return result; | 553 return result; |
| 520 } | 554 } |
| 521 | 555 |
| 522 // Down from here is only valid for API functions that can be used as a | 556 // Down from here is only valid for API functions that can be used as a |
| 523 // constructor (don't set the "remove prototype" flag). | 557 // constructor (don't set the "remove prototype" flag). |
| 524 | 558 |
| 525 // Set up function.prototype. | |
| 526 Handle<JSObject> prototype; | |
| 527 auto prototype_templ = handle(obj->prototype_template(), isolate); | |
| 528 if (type != JS_API_OBJECT_TYPE || prototype_templ->IsUndefined(isolate)) { | |
| 529 prototype = isolate->factory()->NewFunctionPrototype(result); | |
| 530 } else { | |
| 531 prototype = internal::InstantiateObject( | |
| 532 isolate, Handle<ObjectTemplateInfo>::cast(prototype_templ), | |
| 533 Handle<JSReceiver>(), obj->hidden_prototype()) | |
| 534 .ToHandleChecked(); | |
| 535 | |
| 536 JSObject::AddProperty(Handle<JSObject>::cast(prototype), | |
| 537 isolate->factory()->constructor_string(), result, | |
| 538 DONT_ENUM); | |
| 539 } | |
| 540 // Set up function.prototype.__proto__. | |
| 541 auto parent = handle(obj->parent_template(), isolate); | |
| 542 if (!parent->IsUndefined(isolate)) { | |
| 543 Handle<JSFunction> parent_instance = | |
| 544 internal::InstantiateFunction( | |
| 545 isolate, Handle<FunctionTemplateInfo>::cast(parent)) | |
| 546 .ToHandleChecked(); | |
| 547 Handle<Object> parent_prototype = | |
| 548 JSFunction::GetPrototype(isolate, parent_instance); | |
| 549 CHECK(JSObject::SetPrototype(prototype, parent_prototype, false, | |
| 550 Object::THROW_ON_ERROR) | |
| 551 .IsJust()); | |
| 552 } | |
| 553 | |
| 554 if (obj->read_only_prototype()) { | 559 if (obj->read_only_prototype()) { |
| 555 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map()); | 560 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map()); |
| 556 } | 561 } |
| 557 | 562 |
| 558 // Set up the function's initial map. | 563 if (prototype->IsTheHole(isolate)) { |
| 564 prototype = isolate->factory()->NewFunctionPrototype(result); |
| 565 } else { |
| 566 JSObject::AddProperty(Handle<JSObject>::cast(prototype), |
| 567 isolate->factory()->constructor_string(), result, |
| 568 DONT_ENUM); |
| 569 } |
| 570 |
| 559 int internal_field_count = 0; | 571 int internal_field_count = 0; |
| 560 if (!obj->instance_template()->IsUndefined(isolate)) { | 572 if (!obj->instance_template()->IsUndefined(isolate)) { |
| 561 Handle<ObjectTemplateInfo> instance_template( | 573 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>( |
| 562 ObjectTemplateInfo::cast(obj->instance_template())); | 574 ObjectTemplateInfo::cast(obj->instance_template())); |
| 563 internal_field_count = | 575 internal_field_count = |
| 564 Smi::cast(instance_template->internal_field_count())->value(); | 576 Smi::cast(instance_template->internal_field_count())->value(); |
| 565 } | 577 } |
| 566 | 578 |
| 579 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing |
| 580 // JSObject::GetHeaderSize. |
| 567 int instance_size = kPointerSize * internal_field_count; | 581 int instance_size = kPointerSize * internal_field_count; |
| 568 switch (type) { | 582 InstanceType type; |
| 569 case JS_API_OBJECT_TYPE: | 583 switch (instance_type) { |
| 570 if (obj->needs_access_check() || | 584 case JavaScriptObjectType: |
| 571 !obj->named_property_handler()->IsUndefined(isolate) || | 585 if (!obj->needs_access_check() && |
| 572 !obj->indexed_property_handler()->IsUndefined(isolate)) { | 586 obj->named_property_handler()->IsUndefined(isolate) && |
| 587 obj->indexed_property_handler()->IsUndefined(isolate)) { |
| 588 type = JS_API_OBJECT_TYPE; |
| 589 } else { |
| 573 type = JS_SPECIAL_API_OBJECT_TYPE; | 590 type = JS_SPECIAL_API_OBJECT_TYPE; |
| 574 } | 591 } |
| 575 instance_size += JSObject::kHeaderSize; | 592 instance_size += JSObject::kHeaderSize; |
| 576 break; | 593 break; |
| 577 case JS_GLOBAL_OBJECT_TYPE: | 594 case GlobalObjectType: |
| 595 type = JS_GLOBAL_OBJECT_TYPE; |
| 578 instance_size += JSGlobalObject::kSize; | 596 instance_size += JSGlobalObject::kSize; |
| 579 break; | 597 break; |
| 580 case JS_GLOBAL_PROXY_TYPE: | 598 case GlobalProxyType: |
| 599 type = JS_GLOBAL_PROXY_TYPE; |
| 581 instance_size += JSGlobalProxy::kSize; | 600 instance_size += JSGlobalProxy::kSize; |
| 582 break; | 601 break; |
| 583 default: | 602 default: |
| 584 UNREACHABLE(); | 603 UNREACHABLE(); |
| 604 type = JS_OBJECT_TYPE; // Keep the compiler happy. |
| 585 break; | 605 break; |
| 586 } | 606 } |
| 587 | 607 |
| 588 Handle<Map> map = | 608 Handle<Map> map = |
| 589 isolate->factory()->NewMap(type, instance_size, FAST_HOLEY_SMI_ELEMENTS); | 609 isolate->factory()->NewMap(type, instance_size, FAST_HOLEY_SMI_ELEMENTS); |
| 590 JSFunction::SetInitialMap(result, map, prototype); | 610 JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype)); |
| 591 | 611 |
| 592 if (obj->undetectable()) map->set_is_undetectable(); | 612 // Mark as undetectable if needed. |
| 593 if (obj->needs_access_check()) map->set_is_access_check_needed(true); | 613 if (obj->undetectable()) { |
| 614 map->set_is_undetectable(); |
| 615 } |
| 616 |
| 617 // Mark as needs_access_check if needed. |
| 618 if (obj->needs_access_check()) { |
| 619 map->set_is_access_check_needed(true); |
| 620 } |
| 621 |
| 622 // Set interceptor information in the map. |
| 594 if (!obj->named_property_handler()->IsUndefined(isolate)) { | 623 if (!obj->named_property_handler()->IsUndefined(isolate)) { |
| 595 map->set_has_named_interceptor(); | 624 map->set_has_named_interceptor(); |
| 596 } | 625 } |
| 597 if (!obj->indexed_property_handler()->IsUndefined(isolate)) { | 626 if (!obj->indexed_property_handler()->IsUndefined(isolate)) { |
| 598 map->set_has_indexed_interceptor(); | 627 map->set_has_indexed_interceptor(); |
| 599 } | 628 } |
| 629 |
| 630 // Mark instance as callable in the map. |
| 600 if (!obj->instance_call_handler()->IsUndefined(isolate)) { | 631 if (!obj->instance_call_handler()->IsUndefined(isolate)) { |
| 601 map->set_is_callable(); | 632 map->set_is_callable(); |
| 602 map->set_is_constructor(true); | 633 map->set_is_constructor(true); |
| 603 } | 634 } |
| 604 | 635 |
| 605 return result; | 636 return result; |
| 606 } | 637 } |
| 607 | 638 |
| 608 } // namespace internal | 639 } // namespace internal |
| 609 } // namespace v8 | 640 } // namespace v8 |
| OLD | NEW |