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/api-natives.h" 6 7#include "src/api/api-inl.h" 8#include "src/common/message-template.h" 9#include "src/execution/isolate-inl.h" 10#include "src/heap/heap-inl.h" 11#include "src/logging/runtime-call-stats-scope.h" 12#include "src/objects/api-callbacks.h" 13#include "src/objects/hash-table-inl.h" 14#include "src/objects/lookup.h" 15#include "src/objects/property-cell.h" 16#include "src/objects/templates.h" 17 18namespace v8 { 19namespace internal { 20 21namespace { 22 23class V8_NODISCARD InvokeScope { 24 public: 25 explicit InvokeScope(Isolate* isolate) 26 : isolate_(isolate), save_context_(isolate) {} 27 ~InvokeScope() { 28 bool has_exception = isolate_->has_pending_exception(); 29 if (has_exception) { 30 isolate_->ReportPendingMessages(); 31 } else { 32 isolate_->clear_pending_message(); 33 } 34 } 35 36 private: 37 Isolate* isolate_; 38 SaveContext save_context_; 39}; 40 41MaybeHandle<JSObject> InstantiateObject(Isolate* isolate, 42 Handle<ObjectTemplateInfo> data, 43 Handle<JSReceiver> new_target, 44 bool is_prototype); 45 46MaybeHandle<JSFunction> InstantiateFunction( 47 Isolate* isolate, Handle<NativeContext> native_context, 48 Handle<FunctionTemplateInfo> data, 49 MaybeHandle<Name> maybe_name = MaybeHandle<Name>()); 50 51MaybeHandle<JSFunction> InstantiateFunction( 52 Isolate* isolate, Handle<FunctionTemplateInfo> data, 53 MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) { 54 return InstantiateFunction(isolate, isolate->native_context(), data, 55 maybe_name); 56} 57 58MaybeHandle<Object> Instantiate( 59 Isolate* isolate, Handle<Object> data, 60 MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) { 61 if (data->IsFunctionTemplateInfo()) { 62 return InstantiateFunction( 63 isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name); 64 } else if (data->IsObjectTemplateInfo()) { 65 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data), 66 Handle<JSReceiver>(), false); 67 } else { 68 return data; 69 } 70} 71 72MaybeHandle<Object> DefineAccessorProperty(Isolate* isolate, 73 Handle<JSObject> object, 74 Handle<Name> name, 75 Handle<Object> getter, 76 Handle<Object> setter, 77 PropertyAttributes attributes) { 78 DCHECK(!getter->IsFunctionTemplateInfo() || 79 FunctionTemplateInfo::cast(*getter).should_cache()); 80 DCHECK(!setter->IsFunctionTemplateInfo() || 81 FunctionTemplateInfo::cast(*setter).should_cache()); 82 if (getter->IsFunctionTemplateInfo() && 83 FunctionTemplateInfo::cast(*getter).BreakAtEntry()) { 84 ASSIGN_RETURN_ON_EXCEPTION( 85 isolate, getter, 86 InstantiateFunction(isolate, 87 Handle<FunctionTemplateInfo>::cast(getter)), 88 Object); 89 } 90 if (setter->IsFunctionTemplateInfo() && 91 FunctionTemplateInfo::cast(*setter).BreakAtEntry()) { 92 ASSIGN_RETURN_ON_EXCEPTION( 93 isolate, setter, 94 InstantiateFunction(isolate, 95 Handle<FunctionTemplateInfo>::cast(setter)), 96 Object); 97 } 98 RETURN_ON_EXCEPTION( 99 isolate, 100 JSObject::DefineAccessor(object, name, getter, setter, attributes), 101 Object); 102 return object; 103} 104 105MaybeHandle<Object> DefineDataProperty(Isolate* isolate, 106 Handle<JSObject> object, 107 Handle<Name> name, 108 Handle<Object> prop_data, 109 PropertyAttributes attributes) { 110 Handle<Object> value; 111 ASSIGN_RETURN_ON_EXCEPTION(isolate, value, 112 Instantiate(isolate, prop_data, name), Object); 113 114 PropertyKey key(isolate, name); 115 LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR); 116 117#ifdef DEBUG 118 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); 119 DCHECK(maybe.IsJust()); 120 if (it.IsFound()) { 121 THROW_NEW_ERROR( 122 isolate, 123 NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name), 124 Object); 125 } 126#endif 127 128 MAYBE_RETURN_NULL(Object::AddDataProperty(&it, value, attributes, 129 Just(ShouldThrow::kThrowOnError), 130 StoreOrigin::kNamed)); 131 return value; 132} 133 134void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) { 135 Handle<Map> old_map(object->map(), isolate); 136 // Copy map so it won't interfere constructor's initial map. 137 Handle<Map> new_map = Map::Copy(isolate, old_map, "DisableAccessChecks"); 138 new_map->set_is_access_check_needed(false); 139 JSObject::MigrateToMap(isolate, Handle<JSObject>::cast(object), new_map); 140} 141 142void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) { 143 Handle<Map> old_map(object->map(), isolate); 144 // Copy map so it won't interfere constructor's initial map. 145 Handle<Map> new_map = Map::Copy(isolate, old_map, "EnableAccessChecks"); 146 new_map->set_is_access_check_needed(true); 147 new_map->set_may_have_interesting_symbols(true); 148 JSObject::MigrateToMap(isolate, object, new_map); 149} 150 151class V8_NODISCARD AccessCheckDisableScope { 152 public: 153 AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj) 154 : isolate_(isolate), 155 disabled_(obj->map().is_access_check_needed()), 156 obj_(obj) { 157 if (disabled_) { 158 DisableAccessChecks(isolate_, obj_); 159 } 160 } 161 ~AccessCheckDisableScope() { 162 if (disabled_) { 163 EnableAccessChecks(isolate_, obj_); 164 } 165 } 166 167 private: 168 Isolate* isolate_; 169 const bool disabled_; 170 Handle<JSObject> obj_; 171}; 172 173Object GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) { 174 Handle<Context> native_context = isolate->native_context(); 175 DCHECK(!native_context.is_null()); 176 switch (intrinsic) { 177#define GET_INTRINSIC_VALUE(name, iname) \ 178 case v8::k##name: \ 179 return native_context->iname(); 180 V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE) 181#undef GET_INTRINSIC_VALUE 182 } 183 return Object(); 184} 185 186template <typename TemplateInfoT> 187MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj, 188 Handle<TemplateInfoT> data) { 189 RCS_SCOPE(isolate, RuntimeCallCounterId::kConfigureInstance); 190 HandleScope scope(isolate); 191 // Disable access checks while instantiating the object. 192 AccessCheckDisableScope access_check_scope(isolate, obj); 193 194 // Walk the inheritance chain and copy all accessors to current object. 195 int max_number_of_properties = 0; 196 TemplateInfoT info = *data; 197 while (!info.is_null()) { 198 Object props = info.property_accessors(); 199 if (!props.IsUndefined(isolate)) { 200 max_number_of_properties += TemplateList::cast(props).length(); 201 } 202 info = info.GetParent(isolate); 203 } 204 205 if (max_number_of_properties > 0) { 206 int valid_descriptors = 0; 207 // Use a temporary FixedArray to accumulate unique accessors. 208 Handle<FixedArray> array = 209 isolate->factory()->NewFixedArray(max_number_of_properties); 210 211 for (Handle<TemplateInfoT> temp(*data, isolate); !temp->is_null(); 212 temp = handle(temp->GetParent(isolate), isolate)) { 213 // Accumulate accessors. 214 Object maybe_properties = temp->property_accessors(); 215 if (!maybe_properties.IsUndefined(isolate)) { 216 valid_descriptors = AccessorInfo::AppendUnique( 217 isolate, handle(maybe_properties, isolate), array, 218 valid_descriptors); 219 } 220 } 221 222 // Install accumulated accessors. 223 for (int i = 0; i < valid_descriptors; i++) { 224 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)), isolate); 225 Handle<Name> name(Name::cast(accessor->name()), isolate); 226 JSObject::SetAccessor(obj, name, accessor, 227 accessor->initial_property_attributes()) 228 .Assert(); 229 } 230 } 231 232 Object maybe_property_list = data->property_list(); 233 if (maybe_property_list.IsUndefined(isolate)) return obj; 234 Handle<TemplateList> properties(TemplateList::cast(maybe_property_list), 235 isolate); 236 if (properties->length() == 0) return obj; 237 238 int i = 0; 239 for (int c = 0; c < data->number_of_properties(); c++) { 240 auto name = handle(Name::cast(properties->get(i++)), isolate); 241 Object bit = properties->get(i++); 242 if (bit.IsSmi()) { 243 PropertyDetails details(Smi::cast(bit)); 244 PropertyAttributes attributes = details.attributes(); 245 PropertyKind kind = details.kind(); 246 247 if (kind == PropertyKind::kData) { 248 auto prop_data = handle(properties->get(i++), isolate); 249 RETURN_ON_EXCEPTION( 250 isolate, 251 DefineDataProperty(isolate, obj, name, prop_data, attributes), 252 JSObject); 253 } else { 254 auto getter = handle(properties->get(i++), isolate); 255 auto setter = handle(properties->get(i++), isolate); 256 RETURN_ON_EXCEPTION(isolate, 257 DefineAccessorProperty(isolate, obj, name, getter, 258 setter, attributes), 259 JSObject); 260 } 261 } else { 262 // Intrinsic data property --- Get appropriate value from the current 263 // context. 264 PropertyDetails details(Smi::cast(properties->get(i++))); 265 PropertyAttributes attributes = details.attributes(); 266 DCHECK_EQ(PropertyKind::kData, details.kind()); 267 268 v8::Intrinsic intrinsic = 269 static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++))); 270 auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate); 271 272 RETURN_ON_EXCEPTION( 273 isolate, 274 DefineDataProperty(isolate, obj, name, prop_data, attributes), 275 JSObject); 276 } 277 } 278 return obj; 279} 280 281// Whether or not to cache every instance: when we materialize a getter or 282// setter from an lazy AccessorPair, we rely on this cache to be able to always 283// return the same getter or setter. However, objects will be cloned anyways, 284// so it's not observable if we didn't cache an instance. Furthermore, a badly 285// behaved embedder might create an unlimited number of objects, so we limit 286// the cache for those cases. 287enum class CachingMode { kLimited, kUnlimited }; 288 289MaybeHandle<JSObject> ProbeInstantiationsCache( 290 Isolate* isolate, Handle<NativeContext> native_context, int serial_number, 291 CachingMode caching_mode) { 292 DCHECK_NE(serial_number, TemplateInfo::kDoNotCache); 293 if (serial_number == TemplateInfo::kUncached) { 294 return {}; 295 } 296 297 if (serial_number < TemplateInfo::kFastTemplateInstantiationsCacheSize) { 298 FixedArray fast_cache = 299 native_context->fast_template_instantiations_cache(); 300 Handle<Object> object{fast_cache.get(serial_number), isolate}; 301 if (object->IsTheHole(isolate)) return {}; 302 return Handle<JSObject>::cast(object); 303 } 304 if (caching_mode == CachingMode::kUnlimited || 305 (serial_number < TemplateInfo::kSlowTemplateInstantiationsCacheSize)) { 306 SimpleNumberDictionary slow_cache = 307 native_context->slow_template_instantiations_cache(); 308 InternalIndex entry = slow_cache.FindEntry(isolate, serial_number); 309 if (entry.is_found()) { 310 return handle(JSObject::cast(slow_cache.ValueAt(entry)), isolate); 311 } 312 } 313 return {}; 314} 315 316void CacheTemplateInstantiation(Isolate* isolate, 317 Handle<NativeContext> native_context, 318 Handle<TemplateInfo> data, 319 CachingMode caching_mode, 320 Handle<JSObject> object) { 321 DCHECK_NE(TemplateInfo::kDoNotCache, data->serial_number()); 322 323 int serial_number = data->serial_number(); 324 if (serial_number == TemplateInfo::kUncached) { 325 serial_number = isolate->heap()->GetNextTemplateSerialNumber(); 326 } 327 328 if (serial_number < TemplateInfo::kFastTemplateInstantiationsCacheSize) { 329 Handle<FixedArray> fast_cache = 330 handle(native_context->fast_template_instantiations_cache(), isolate); 331 Handle<FixedArray> new_cache = 332 FixedArray::SetAndGrow(isolate, fast_cache, serial_number, object); 333 if (*new_cache != *fast_cache) { 334 native_context->set_fast_template_instantiations_cache(*new_cache); 335 } 336 data->set_serial_number(serial_number); 337 } else if (caching_mode == CachingMode::kUnlimited || 338 (serial_number < 339 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) { 340 Handle<SimpleNumberDictionary> cache = 341 handle(native_context->slow_template_instantiations_cache(), isolate); 342 auto new_cache = 343 SimpleNumberDictionary::Set(isolate, cache, serial_number, object); 344 if (*new_cache != *cache) { 345 native_context->set_slow_template_instantiations_cache(*new_cache); 346 } 347 data->set_serial_number(serial_number); 348 } else { 349 // we've overflowed the cache limit, no more caching 350 data->set_serial_number(TemplateInfo::kDoNotCache); 351 } 352} 353 354void UncacheTemplateInstantiation(Isolate* isolate, 355 Handle<NativeContext> native_context, 356 Handle<TemplateInfo> data, 357 CachingMode caching_mode) { 358 int serial_number = data->serial_number(); 359 if (serial_number < 0) return; 360 361 if (serial_number < TemplateInfo::kFastTemplateInstantiationsCacheSize) { 362 FixedArray fast_cache = 363 native_context->fast_template_instantiations_cache(); 364 DCHECK(!fast_cache.get(serial_number).IsUndefined(isolate)); 365 fast_cache.set_undefined(serial_number); 366 data->set_serial_number(TemplateInfo::kUncached); 367 } else if (caching_mode == CachingMode::kUnlimited || 368 (serial_number < 369 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) { 370 Handle<SimpleNumberDictionary> cache = 371 handle(native_context->slow_template_instantiations_cache(), isolate); 372 InternalIndex entry = cache->FindEntry(isolate, serial_number); 373 DCHECK(entry.is_found()); 374 cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry); 375 native_context->set_slow_template_instantiations_cache(*cache); 376 data->set_serial_number(TemplateInfo::kUncached); 377 } 378} 379 380bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo info, 381 JSReceiver new_target) { 382 DisallowGarbageCollection no_gc; 383 384 if (!new_target.IsJSFunction()) return false; 385 JSFunction fun = JSFunction::cast(new_target); 386 if (fun.shared().function_data(kAcquireLoad) != info.constructor()) 387 return false; 388 if (info.immutable_proto()) return false; 389 return fun.native_context() == isolate->raw_native_context(); 390} 391 392MaybeHandle<JSObject> InstantiateObject(Isolate* isolate, 393 Handle<ObjectTemplateInfo> info, 394 Handle<JSReceiver> new_target, 395 bool is_prototype) { 396 RCS_SCOPE(isolate, RuntimeCallCounterId::kInstantiateObject); 397 Handle<JSFunction> constructor; 398 bool should_cache = info->should_cache(); 399 if (!new_target.is_null()) { 400 if (IsSimpleInstantiation(isolate, *info, *new_target)) { 401 constructor = Handle<JSFunction>::cast(new_target); 402 } else { 403 // Disable caching for subclass instantiation. 404 should_cache = false; 405 } 406 } 407 // Fast path. 408 Handle<JSObject> result; 409 if (should_cache && info->is_cached()) { 410 if (ProbeInstantiationsCache(isolate, isolate->native_context(), 411 info->serial_number(), CachingMode::kLimited) 412 .ToHandle(&result)) { 413 return isolate->factory()->CopyJSObject(result); 414 } 415 } 416 417 if (constructor.is_null()) { 418 Object maybe_constructor_info = info->constructor(); 419 if (maybe_constructor_info.IsUndefined(isolate)) { 420 constructor = isolate->object_function(); 421 } else { 422 // Enter a new scope. Recursion could otherwise create a lot of handles. 423 HandleScope scope(isolate); 424 Handle<FunctionTemplateInfo> cons_templ( 425 FunctionTemplateInfo::cast(maybe_constructor_info), isolate); 426 Handle<JSFunction> tmp_constructor; 427 ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor, 428 InstantiateFunction(isolate, cons_templ), 429 JSObject); 430 constructor = scope.CloseAndEscape(tmp_constructor); 431 } 432 433 if (new_target.is_null()) new_target = constructor; 434 } 435 436 Handle<JSObject> object; 437 ASSIGN_RETURN_ON_EXCEPTION( 438 isolate, object, 439 JSObject::New(constructor, new_target, Handle<AllocationSite>::null()), 440 JSObject); 441 442 if (is_prototype) JSObject::OptimizeAsPrototype(object); 443 444 ASSIGN_RETURN_ON_EXCEPTION( 445 isolate, result, ConfigureInstance(isolate, object, info), JSObject); 446 if (info->immutable_proto()) { 447 JSObject::SetImmutableProto(object); 448 } 449 if (!is_prototype) { 450 // Keep prototypes in slow-mode. Let them be lazily turned fast later on. 451 // TODO(dcarney): is this necessary? 452 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject"); 453 // Don't cache prototypes. 454 if (should_cache) { 455 CacheTemplateInstantiation(isolate, isolate->native_context(), info, 456 CachingMode::kLimited, result); 457 result = isolate->factory()->CopyJSObject(result); 458 } 459 } 460 461 return result; 462} 463 464namespace { 465MaybeHandle<Object> GetInstancePrototype(Isolate* isolate, 466 Handle<Object> function_template) { 467 // Enter a new scope. Recursion could otherwise create a lot of handles. 468 HandleScope scope(isolate); 469 Handle<JSFunction> parent_instance; 470 ASSIGN_RETURN_ON_EXCEPTION( 471 isolate, parent_instance, 472 InstantiateFunction( 473 isolate, Handle<FunctionTemplateInfo>::cast(function_template)), 474 JSFunction); 475 Handle<Object> instance_prototype; 476 // TODO(cbruni): decide what to do here. 477 ASSIGN_RETURN_ON_EXCEPTION( 478 isolate, instance_prototype, 479 JSObject::GetProperty(isolate, parent_instance, 480 isolate->factory()->prototype_string()), 481 JSFunction); 482 return scope.CloseAndEscape(instance_prototype); 483} 484} // namespace 485 486MaybeHandle<JSFunction> InstantiateFunction( 487 Isolate* isolate, Handle<NativeContext> native_context, 488 Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) { 489 RCS_SCOPE(isolate, RuntimeCallCounterId::kInstantiateFunction); 490 bool should_cache = data->should_cache(); 491 if (should_cache && data->is_cached()) { 492 Handle<JSObject> result; 493 if (ProbeInstantiationsCache(isolate, native_context, data->serial_number(), 494 CachingMode::kUnlimited) 495 .ToHandle(&result)) { 496 return Handle<JSFunction>::cast(result); 497 } 498 } 499 Handle<Object> prototype; 500 if (!data->remove_prototype()) { 501 Handle<Object> prototype_templ(data->GetPrototypeTemplate(), isolate); 502 if (prototype_templ->IsUndefined(isolate)) { 503 Handle<Object> protoype_provider_templ( 504 data->GetPrototypeProviderTemplate(), isolate); 505 if (protoype_provider_templ->IsUndefined(isolate)) { 506 prototype = isolate->factory()->NewJSObject(isolate->object_function()); 507 } else { 508 ASSIGN_RETURN_ON_EXCEPTION( 509 isolate, prototype, 510 GetInstancePrototype(isolate, protoype_provider_templ), JSFunction); 511 } 512 } else { 513 ASSIGN_RETURN_ON_EXCEPTION( 514 isolate, prototype, 515 InstantiateObject(isolate, 516 Handle<ObjectTemplateInfo>::cast(prototype_templ), 517 Handle<JSReceiver>(), true), 518 JSFunction); 519 } 520 Handle<Object> parent(data->GetParentTemplate(), isolate); 521 if (!parent->IsUndefined(isolate)) { 522 Handle<Object> parent_prototype; 523 ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype, 524 GetInstancePrototype(isolate, parent), 525 JSFunction); 526 CHECK(parent_prototype->IsHeapObject()); 527 JSObject::ForceSetPrototype(isolate, Handle<JSObject>::cast(prototype), 528 Handle<HeapObject>::cast(parent_prototype)); 529 } 530 } 531 InstanceType function_type = JS_SPECIAL_API_OBJECT_TYPE; 532 if (!data->needs_access_check() && 533 data->GetNamedPropertyHandler().IsUndefined(isolate) && 534 data->GetIndexedPropertyHandler().IsUndefined(isolate)) { 535 function_type = FLAG_embedder_instance_types && data->HasInstanceType() 536 ? static_cast<InstanceType>(data->InstanceType()) 537 : JS_API_OBJECT_TYPE; 538 } 539 540 Handle<JSFunction> function = ApiNatives::CreateApiFunction( 541 isolate, native_context, data, prototype, function_type, maybe_name); 542 if (should_cache) { 543 // Cache the function. 544 CacheTemplateInstantiation(isolate, native_context, data, 545 CachingMode::kUnlimited, function); 546 } 547 MaybeHandle<JSObject> result = ConfigureInstance(isolate, function, data); 548 if (result.is_null()) { 549 // Uncache on error. 550 UncacheTemplateInstantiation(isolate, native_context, data, 551 CachingMode::kUnlimited); 552 return MaybeHandle<JSFunction>(); 553 } 554 data->set_published(true); 555 return function; 556} 557 558void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ, 559 int length, Handle<Object>* data) { 560 Object maybe_list = templ->property_list(); 561 Handle<TemplateList> list; 562 if (maybe_list.IsUndefined(isolate)) { 563 list = TemplateList::New(isolate, length); 564 } else { 565 list = handle(TemplateList::cast(maybe_list), isolate); 566 } 567 templ->set_number_of_properties(templ->number_of_properties() + 1); 568 for (int i = 0; i < length; i++) { 569 Handle<Object> value = 570 data[i].is_null() 571 ? Handle<Object>::cast(isolate->factory()->undefined_value()) 572 : data[i]; 573 list = TemplateList::Add(isolate, list, value); 574 } 575 templ->set_property_list(*list); 576} 577 578} // namespace 579 580MaybeHandle<JSFunction> ApiNatives::InstantiateFunction( 581 Isolate* isolate, Handle<NativeContext> native_context, 582 Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) { 583 InvokeScope invoke_scope(isolate); 584 return ::v8::internal::InstantiateFunction(isolate, native_context, data, 585 maybe_name); 586} 587 588MaybeHandle<JSFunction> ApiNatives::InstantiateFunction( 589 Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) { 590 Isolate* isolate = data->GetIsolate(); 591 InvokeScope invoke_scope(isolate); 592 return ::v8::internal::InstantiateFunction(isolate, data, maybe_name); 593} 594 595MaybeHandle<JSObject> ApiNatives::InstantiateObject( 596 Isolate* isolate, Handle<ObjectTemplateInfo> data, 597 Handle<JSReceiver> new_target) { 598 InvokeScope invoke_scope(isolate); 599 return ::v8::internal::InstantiateObject(isolate, data, new_target, false); 600} 601 602MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject( 603 Handle<ObjectTemplateInfo> data) { 604 Isolate* isolate = data->GetIsolate(); 605 InvokeScope invoke_scope(isolate); 606 607 Handle<FunctionTemplateInfo> constructor( 608 FunctionTemplateInfo::cast(data->constructor()), isolate); 609 Handle<Map> object_map = isolate->factory()->NewMap( 610 JS_SPECIAL_API_OBJECT_TYPE, 611 JSObject::kHeaderSize + 612 data->embedder_field_count() * kEmbedderDataSlotSize, 613 TERMINAL_FAST_ELEMENTS_KIND); 614 object_map->SetConstructor(*constructor); 615 object_map->set_is_access_check_needed(true); 616 object_map->set_may_have_interesting_symbols(true); 617 618 Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(object_map); 619 JSObject::ForceSetPrototype(isolate, object, 620 isolate->factory()->null_value()); 621 622 return object; 623} 624 625void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info, 626 Handle<Name> name, Handle<Object> value, 627 PropertyAttributes attributes) { 628 PropertyDetails details(PropertyKind::kData, attributes, 629 PropertyConstness::kMutable); 630 auto details_handle = handle(details.AsSmi(), isolate); 631 Handle<Object> data[] = {name, details_handle, value}; 632 AddPropertyToPropertyList(isolate, info, arraysize(data), data); 633} 634 635void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info, 636 Handle<Name> name, v8::Intrinsic intrinsic, 637 PropertyAttributes attributes) { 638 auto value = handle(Smi::FromInt(intrinsic), isolate); 639 auto intrinsic_marker = isolate->factory()->true_value(); 640 PropertyDetails details(PropertyKind::kData, attributes, 641 PropertyConstness::kMutable); 642 auto details_handle = handle(details.AsSmi(), isolate); 643 Handle<Object> data[] = {name, intrinsic_marker, details_handle, value}; 644 AddPropertyToPropertyList(isolate, info, arraysize(data), data); 645} 646 647void ApiNatives::AddAccessorProperty(Isolate* isolate, 648 Handle<TemplateInfo> info, 649 Handle<Name> name, 650 Handle<FunctionTemplateInfo> getter, 651 Handle<FunctionTemplateInfo> setter, 652 PropertyAttributes attributes) { 653 if (!getter.is_null()) getter->set_published(true); 654 if (!setter.is_null()) setter->set_published(true); 655 PropertyDetails details(PropertyKind::kAccessor, attributes, 656 PropertyConstness::kMutable); 657 auto details_handle = handle(details.AsSmi(), isolate); 658 Handle<Object> data[] = {name, details_handle, getter, setter}; 659 AddPropertyToPropertyList(isolate, info, arraysize(data), data); 660} 661 662void ApiNatives::AddNativeDataProperty(Isolate* isolate, 663 Handle<TemplateInfo> info, 664 Handle<AccessorInfo> property) { 665 Object maybe_list = info->property_accessors(); 666 Handle<TemplateList> list; 667 if (maybe_list.IsUndefined(isolate)) { 668 list = TemplateList::New(isolate, 1); 669 } else { 670 list = handle(TemplateList::cast(maybe_list), isolate); 671 } 672 list = TemplateList::Add(isolate, list, property); 673 info->set_property_accessors(*list); 674} 675 676Handle<JSFunction> ApiNatives::CreateApiFunction( 677 Isolate* isolate, Handle<NativeContext> native_context, 678 Handle<FunctionTemplateInfo> obj, Handle<Object> prototype, 679 InstanceType type, MaybeHandle<Name> maybe_name) { 680 RCS_SCOPE(isolate, RuntimeCallCounterId::kCreateApiFunction); 681 Handle<SharedFunctionInfo> shared = 682 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj, 683 maybe_name); 684 // To simplify things, API functions always have shared name. 685 DCHECK(shared->HasSharedName()); 686 687 Handle<JSFunction> result = 688 Factory::JSFunctionBuilder{isolate, shared, native_context}.Build(); 689 690 if (obj->remove_prototype()) { 691 DCHECK(prototype.is_null()); 692 DCHECK(result->shared().IsApiFunction()); 693 DCHECK(!result->IsConstructor()); 694 DCHECK(!result->has_prototype_slot()); 695 return result; 696 } 697 698 // Down from here is only valid for API functions that can be used as a 699 // constructor (don't set the "remove prototype" flag). 700 DCHECK(result->has_prototype_slot()); 701 702 if (obj->read_only_prototype()) { 703 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map()); 704 } 705 706 if (prototype->IsTheHole(isolate)) { 707 prototype = isolate->factory()->NewFunctionPrototype(result); 708 } else if (obj->GetPrototypeProviderTemplate().IsUndefined(isolate)) { 709 JSObject::AddProperty(isolate, Handle<JSObject>::cast(prototype), 710 isolate->factory()->constructor_string(), result, 711 DONT_ENUM); 712 } 713 714 int embedder_field_count = 0; 715 bool immutable_proto = false; 716 if (!obj->GetInstanceTemplate().IsUndefined(isolate)) { 717 Handle<ObjectTemplateInfo> GetInstanceTemplate = Handle<ObjectTemplateInfo>( 718 ObjectTemplateInfo::cast(obj->GetInstanceTemplate()), isolate); 719 embedder_field_count = GetInstanceTemplate->embedder_field_count(); 720 immutable_proto = GetInstanceTemplate->immutable_proto(); 721 } 722 723 // JSFunction requires information about the prototype slot. 724 DCHECK(!InstanceTypeChecker::IsJSFunction(type)); 725 int instance_size = JSObject::GetHeaderSize(type) + 726 kEmbedderDataSlotSize * embedder_field_count; 727 728 Handle<Map> map = isolate->factory()->NewMap(type, instance_size, 729 TERMINAL_FAST_ELEMENTS_KIND); 730 731 // Mark as undetectable if needed. 732 if (obj->undetectable()) { 733 // We only allow callable undetectable receivers here, since this whole 734 // undetectable business is only to support document.all, which is both 735 // undetectable and callable. If we ever see the need to have an object 736 // that is undetectable but not callable, we need to update the types.h 737 // to allow encoding this. 738 CHECK(!obj->GetInstanceCallHandler().IsUndefined(isolate)); 739 map->set_is_undetectable(true); 740 } 741 742 // Mark as needs_access_check if needed. 743 if (obj->needs_access_check()) { 744 map->set_is_access_check_needed(true); 745 map->set_may_have_interesting_symbols(true); 746 } 747 748 // Set interceptor information in the map. 749 if (!obj->GetNamedPropertyHandler().IsUndefined(isolate)) { 750 map->set_has_named_interceptor(true); 751 map->set_may_have_interesting_symbols(true); 752 } 753 if (!obj->GetIndexedPropertyHandler().IsUndefined(isolate)) { 754 map->set_has_indexed_interceptor(true); 755 } 756 757 // Mark instance as callable in the map. 758 if (!obj->GetInstanceCallHandler().IsUndefined(isolate)) { 759 map->set_is_callable(true); 760 map->set_is_constructor(!obj->undetectable()); 761 } 762 763 if (immutable_proto) map->set_is_immutable_proto(true); 764 765 JSFunction::SetInitialMap(isolate, result, map, 766 Handle<JSObject>::cast(prototype)); 767 return result; 768} 769 770} // namespace internal 771} // namespace v8 772