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 |
374 // Enter a new scope. Recursion could otherwise create a lot of handles. | 375 // Enter a new scope. Recursion could otherwise create a lot of handles. |
375 HandleScope scope(isolate); | 376 HandleScope scope(isolate); |
376 Handle<JSObject> prototype; | 377 |
377 if (!data->remove_prototype()) { | 378 auto function = |
378 auto prototype_templ = handle(data->prototype_template(), isolate); | 379 ApiNatives::CreateApiFunction(isolate, data, JS_API_OBJECT_TYPE); |
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); | |
411 if (!name.is_null() && name->IsString()) { | 380 if (!name.is_null() && name->IsString()) { |
412 function->shared()->set_name(*name); | 381 function->shared()->set_name(*name); |
413 } | 382 } |
414 if (serial_number) { | 383 if (serial_number) { |
415 // Cache the function. | 384 // Cache the function. |
416 CacheTemplateInstantiation(isolate, serial_number, function); | 385 CacheTemplateInstantiation(isolate, serial_number, function); |
417 } | 386 } |
418 auto result = | 387 auto result = |
419 ConfigureInstance(isolate, function, data, data->hidden_prototype()); | 388 ConfigureInstance(isolate, function, data, data->hidden_prototype()); |
420 if (result.is_null()) { | 389 if (result.is_null()) { |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 Handle<AccessorInfo> property) { | 495 Handle<AccessorInfo> property) { |
527 auto list = handle(info->property_accessors(), isolate); | 496 auto list = handle(info->property_accessors(), isolate); |
528 if (list->IsUndefined(isolate)) { | 497 if (list->IsUndefined(isolate)) { |
529 list = NeanderArray(isolate).value(); | 498 list = NeanderArray(isolate).value(); |
530 info->set_property_accessors(*list); | 499 info->set_property_accessors(*list); |
531 } | 500 } |
532 NeanderArray array(list); | 501 NeanderArray array(list); |
533 array.add(isolate, property); | 502 array.add(isolate, property); |
534 } | 503 } |
535 | 504 |
536 | |
537 Handle<JSFunction> ApiNatives::CreateApiFunction( | 505 Handle<JSFunction> ApiNatives::CreateApiFunction( |
538 Isolate* isolate, Handle<FunctionTemplateInfo> obj, | 506 Isolate* isolate, Handle<FunctionTemplateInfo> obj, InstanceType type) { |
539 Handle<Object> prototype, ApiInstanceType instance_type) { | |
540 Handle<SharedFunctionInfo> shared = | 507 Handle<SharedFunctionInfo> shared = |
541 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj); | 508 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj); |
| 509 DCHECK(shared->IsApiFunction()); |
542 Handle<JSFunction> result = | 510 Handle<JSFunction> result = |
543 isolate->factory()->NewFunctionFromSharedFunctionInfo( | 511 isolate->factory()->NewFunctionFromSharedFunctionInfo( |
544 shared, isolate->native_context()); | 512 shared, isolate->native_context()); |
545 | 513 |
546 if (obj->remove_prototype()) { | 514 if (obj->remove_prototype()) { |
547 result->set_map(*isolate->sloppy_function_without_prototype_map()); | 515 result->set_map(*isolate->sloppy_function_without_prototype_map()); |
548 DCHECK(prototype.is_null()); | |
549 DCHECK(result->shared()->IsApiFunction()); | |
550 DCHECK(!result->has_initial_map()); | 516 DCHECK(!result->has_initial_map()); |
551 DCHECK(!result->has_prototype()); | 517 DCHECK(!result->has_prototype()); |
552 DCHECK(!result->IsConstructor()); | 518 DCHECK(!result->IsConstructor()); |
553 return result; | 519 return result; |
554 } | 520 } |
555 | 521 |
556 // Down from here is only valid for API functions that can be used as a | 522 // Down from here is only valid for API functions that can be used as a |
557 // constructor (don't set the "remove prototype" flag). | 523 // constructor (don't set the "remove prototype" flag). |
558 | 524 |
| 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 |
559 if (obj->read_only_prototype()) { | 554 if (obj->read_only_prototype()) { |
560 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map()); | 555 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map()); |
561 } | 556 } |
562 | 557 |
563 if (prototype->IsTheHole(isolate)) { | 558 // Set up the function's initial map. |
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 | |
571 int internal_field_count = 0; | 559 int internal_field_count = 0; |
572 if (!obj->instance_template()->IsUndefined(isolate)) { | 560 if (!obj->instance_template()->IsUndefined(isolate)) { |
573 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>( | 561 Handle<ObjectTemplateInfo> instance_template( |
574 ObjectTemplateInfo::cast(obj->instance_template())); | 562 ObjectTemplateInfo::cast(obj->instance_template())); |
575 internal_field_count = | 563 internal_field_count = |
576 Smi::cast(instance_template->internal_field_count())->value(); | 564 Smi::cast(instance_template->internal_field_count())->value(); |
577 } | 565 } |
578 | 566 |
579 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing | |
580 // JSObject::GetHeaderSize. | |
581 int instance_size = kPointerSize * internal_field_count; | 567 int instance_size = kPointerSize * internal_field_count; |
582 InstanceType type; | 568 switch (type) { |
583 switch (instance_type) { | 569 case JS_API_OBJECT_TYPE: |
584 case JavaScriptObjectType: | 570 if (obj->needs_access_check() || |
585 if (!obj->needs_access_check() && | 571 !obj->named_property_handler()->IsUndefined(isolate) || |
586 obj->named_property_handler()->IsUndefined(isolate) && | 572 !obj->indexed_property_handler()->IsUndefined(isolate)) { |
587 obj->indexed_property_handler()->IsUndefined(isolate)) { | |
588 type = JS_API_OBJECT_TYPE; | |
589 } else { | |
590 type = JS_SPECIAL_API_OBJECT_TYPE; | 573 type = JS_SPECIAL_API_OBJECT_TYPE; |
591 } | 574 } |
592 instance_size += JSObject::kHeaderSize; | 575 instance_size += JSObject::kHeaderSize; |
593 break; | 576 break; |
594 case GlobalObjectType: | 577 case JS_GLOBAL_OBJECT_TYPE: |
595 type = JS_GLOBAL_OBJECT_TYPE; | |
596 instance_size += JSGlobalObject::kSize; | 578 instance_size += JSGlobalObject::kSize; |
597 break; | 579 break; |
598 case GlobalProxyType: | 580 case JS_GLOBAL_PROXY_TYPE: |
599 type = JS_GLOBAL_PROXY_TYPE; | |
600 instance_size += JSGlobalProxy::kSize; | 581 instance_size += JSGlobalProxy::kSize; |
601 break; | 582 break; |
602 default: | 583 default: |
603 UNREACHABLE(); | 584 UNREACHABLE(); |
604 type = JS_OBJECT_TYPE; // Keep the compiler happy. | |
605 break; | 585 break; |
606 } | 586 } |
607 | 587 |
608 Handle<Map> map = | 588 Handle<Map> map = |
609 isolate->factory()->NewMap(type, instance_size, FAST_HOLEY_SMI_ELEMENTS); | 589 isolate->factory()->NewMap(type, instance_size, FAST_HOLEY_SMI_ELEMENTS); |
610 JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype)); | 590 JSFunction::SetInitialMap(result, map, prototype); |
611 | 591 |
612 // Mark as undetectable if needed. | 592 if (obj->undetectable()) map->set_is_undetectable(); |
613 if (obj->undetectable()) { | 593 if (obj->needs_access_check()) map->set_is_access_check_needed(true); |
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. | |
623 if (!obj->named_property_handler()->IsUndefined(isolate)) { | 594 if (!obj->named_property_handler()->IsUndefined(isolate)) { |
624 map->set_has_named_interceptor(); | 595 map->set_has_named_interceptor(); |
625 } | 596 } |
626 if (!obj->indexed_property_handler()->IsUndefined(isolate)) { | 597 if (!obj->indexed_property_handler()->IsUndefined(isolate)) { |
627 map->set_has_indexed_interceptor(); | 598 map->set_has_indexed_interceptor(); |
628 } | 599 } |
629 | |
630 // Mark instance as callable in the map. | |
631 if (!obj->instance_call_handler()->IsUndefined(isolate)) { | 600 if (!obj->instance_call_handler()->IsUndefined(isolate)) { |
632 map->set_is_callable(); | 601 map->set_is_callable(); |
633 map->set_is_constructor(true); | 602 map->set_is_constructor(true); |
634 } | 603 } |
635 | 604 |
636 return result; | 605 return result; |
637 } | 606 } |
638 | 607 |
639 } // namespace internal | 608 } // namespace internal |
640 } // namespace v8 | 609 } // namespace v8 |
OLD | NEW |