• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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