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
8 namespace v8 {
9 namespace internal {
10
11 constexpr int kMaxJSStructFields = 999;
12
13 #ifdef V8_ENABLE_WEBASSEMBLY
14 #include "src/wasm/wasm-limits.h"
15 static_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
BUILTIN(SharedStructTypeConstructor)20 BUILTIN(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
BUILTIN(SharedStructConstructor)102 BUILTIN(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