1// Copyright 2022 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/builtins/builtins-utils-inl.h" 6#include "src/objects/js-struct-inl.h" 7 8namespace v8 { 9namespace internal { 10 11constexpr int kMaxJSStructFields = 999; 12 13#ifdef V8_ENABLE_WEBASSEMBLY 14#include "src/wasm/wasm-limits.h" 15static_assert(wasm::kV8MaxWasmStructFields == kMaxJSStructFields, 16 "Max number of fields should be the same for both JS and " 17 "WebAssembly structs"); 18#endif // V8_ENABLE_WEBASSEMBLY 19 20BUILTIN(SharedStructTypeConstructor) { 21 DCHECK(FLAG_shared_string_table); 22 23 HandleScope scope(isolate); 24 static const char method_name[] = "SharedStructType"; 25 auto* factory = isolate->factory(); 26 27 Handle<JSReceiver> field_names_arg; 28 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 29 isolate, field_names_arg, 30 Object::ToObject(isolate, args.atOrUndefined(isolate, 1), method_name)); 31 32 // Treat field_names_arg as arraylike. 33 Handle<Object> raw_length_number; 34 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 35 isolate, raw_length_number, 36 Object::GetLengthFromArrayLike(isolate, field_names_arg)); 37 double num_properties_double = raw_length_number->Number(); 38 if (num_properties_double < 0 || num_properties_double > kMaxJSStructFields) { 39 THROW_NEW_ERROR_RETURN_FAILURE( 40 isolate, NewRangeError(MessageTemplate::kStructFieldCountOutOfRange)); 41 } 42 int num_properties = static_cast<int>(num_properties_double); 43 44 Handle<DescriptorArray> descriptors = factory->NewDescriptorArray( 45 num_properties, 0, AllocationType::kSharedOld); 46 47 // Build up the descriptor array. 48 for (int i = 0; i < num_properties; ++i) { 49 Handle<Object> raw_field_name; 50 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 51 isolate, raw_field_name, 52 JSReceiver::GetElement(isolate, field_names_arg, i)); 53 Handle<Name> field_name; 54 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, field_name, 55 Object::ToName(isolate, raw_field_name)); 56 field_name = factory->InternalizeName(field_name); 57 58 // Shared structs' fields need to be aligned, so make it all tagged. 59 PropertyDetails details( 60 PropertyKind::kData, SEALED, PropertyLocation::kField, 61 PropertyConstness::kMutable, Representation::Tagged(), i); 62 descriptors->Set(InternalIndex(i), *field_name, 63 MaybeObject::FromObject(FieldType::Any()), details); 64 } 65 descriptors->Sort(); 66 67 Handle<SharedFunctionInfo> info = 68 isolate->factory()->NewSharedFunctionInfoForBuiltin( 69 isolate->factory()->empty_string(), Builtin::kSharedStructConstructor, 70 FunctionKind::kNormalFunction); 71 info->set_internal_formal_parameter_count(JSParameterCount(0)); 72 info->set_length(0); 73 74 Handle<JSFunction> constructor = 75 Factory::JSFunctionBuilder{isolate, info, isolate->native_context()} 76 .set_map(isolate->strict_function_map()) 77 .Build(); 78 79 int instance_size; 80 int in_object_properties; 81 JSFunction::CalculateInstanceSizeHelper(JS_SHARED_STRUCT_TYPE, false, 0, 82 num_properties, &instance_size, 83 &in_object_properties); 84 Handle<Map> instance_map = factory->NewMap( 85 JS_SHARED_STRUCT_TYPE, instance_size, TERMINAL_FAST_ELEMENTS_KIND, 86 in_object_properties, AllocationType::kSharedMap); 87 88 instance_map->InitializeDescriptors(isolate, *descriptors); 89 // Structs have fixed layout ahead of time, so there's no slack. 90 instance_map->SetInObjectUnusedPropertyFields(0); 91 instance_map->set_is_extensible(false); 92 JSFunction::SetInitialMap(isolate, constructor, instance_map, 93 factory->null_value()); 94 95 // The constructor is not a shared object, so the shared map should not point 96 // to it. 97 instance_map->set_constructor_or_back_pointer(*factory->null_value()); 98 99 return *constructor; 100} 101 102BUILTIN(SharedStructConstructor) { 103 HandleScope scope(isolate); 104 auto* factory = isolate->factory(); 105 106 Handle<JSObject> instance = 107 factory->NewJSObject(args.target(), AllocationType::kSharedOld); 108 109 Handle<Map> instance_map(instance->map(), isolate); 110 if (instance_map->HasOutOfObjectProperties()) { 111 int num_oob_fields = 112 instance_map->NumberOfFields(ConcurrencyMode::kSynchronous) - 113 instance_map->GetInObjectProperties(); 114 Handle<PropertyArray> property_array = 115 factory->NewPropertyArray(num_oob_fields, AllocationType::kSharedOld); 116 instance->SetProperties(*property_array); 117 } 118 119 return *instance; 120} 121 122} // namespace internal 123} // namespace v8 124