v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
templates.cc
Go to the documentation of this file.
1// Copyright 2021 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
6
7#include <algorithm>
8#include <cstdint>
9#include <optional>
10
11#include "src/api/api-inl.h"
12#include "src/base/macros.h"
13#include "src/common/globals.h"
15#include "src/heap/factory.h"
20#include "src/objects/map-inl.h"
22#include "src/objects/objects.h"
25
26namespace v8::internal {
27
29 return instance_type() != kNoJSApiObjectType;
30}
31
34 MaybeDirectHandle<Name> maybe_name) {
35 Tagged<Object> current_info = info->shared_function_info();
36 if (IsSharedFunctionInfo(current_info)) {
37 return handle(Cast<SharedFunctionInfo>(current_info), isolate);
38 }
40 DirectHandle<String> name_string;
41 if (maybe_name.ToHandle(&name) && IsString(*name)) {
42 name_string = Cast<String>(name);
43 } else if (IsString(info->class_name())) {
44 name_string = direct_handle(Cast<String>(info->class_name()), isolate);
45 } else {
46 name_string = isolate->factory()->empty_string();
47 }
48 FunctionKind function_kind;
49 if (info->remove_prototype()) {
50 function_kind = FunctionKind::kConciseMethod;
51 } else {
52 function_kind = FunctionKind::kNormalFunction;
53 }
55 isolate->factory()->NewSharedFunctionInfoForApiFunction(name_string, info,
56 function_kind);
57 DCHECK(sfi->IsApiFunction());
58 info->set_shared_function_info(*sfi);
59 return sfi;
60}
61
64 LocalHeap::Current() == nullptr
65 ? GetIsolateChecked()->counters()->runtime_call_stats()
66 : LocalIsolate::FromHeap(LocalHeap::Current())->runtime_call_stats(),
67 RuntimeCallCounterId::kIsTemplateFor);
68
69 // There is a constraint on the object; check.
70 if (!IsJSObjectMap(map)) return false;
71
72 if (v8_flags.experimental_embedder_instance_types) {
73 DCHECK_IMPLIES(allowed_receiver_instance_type_range_start() == 0,
75 if (base::IsInRange(map->instance_type(),
76 allowed_receiver_instance_type_range_start(),
78 return true;
79 }
80 }
81
82 // Fetch the constructor function of the object.
83 Tagged<Object> cons_obj = map->GetConstructor();
85 if (IsJSFunction(cons_obj)) {
87 if (!fun->shared()->IsApiFunction()) return false;
88 type = fun->shared()->api_func_data();
89 } else if (IsFunctionTemplateInfo(cons_obj)) {
90 type = Cast<FunctionTemplateInfo>(cons_obj);
91 } else {
92 return false;
93 }
94 DCHECK(IsFunctionTemplateInfo(type));
95 // Iterate through the chain of inheriting function templates to
96 // see if the required one occurs.
97 while (IsFunctionTemplateInfo(type)) {
98 if (type == *this) return true;
99 type = Cast<FunctionTemplateInfo>(type)->GetParentTemplate();
100 }
101 // Didn't find the required type in the inheritance chain.
102 return false;
103}
104
106 Tagged<Object> object) const {
108
109 if (!IsJSApiObject(object)) {
110 return false;
111 }
112
113 bool result = false;
114 Tagged<Map> map = Cast<HeapObject>(object)->map();
115 Tagged<Object> constructor_obj = map->GetConstructor();
116 if (IsJSFunction(constructor_obj)) {
117 Tagged<JSFunction> fun = Cast<JSFunction>(constructor_obj);
118 result = (*this == fun->shared()->api_func_data());
119 } else if (IsFunctionTemplateInfo(constructor_obj)) {
120 result = (*this == constructor_obj);
121 }
123 return result;
124}
125
126// static
129 if (info->should_promote_to_read_only()) return;
131
132 info->EnsureHasSerialNumber(isolate);
133
134 GetOrCreateSharedFunctionInfo(isolate, info,
135 isolate->factory()->empty_string());
136
137 info->set_should_promote_to_read_only(true);
138 info->set_published(true);
139}
140
141// static
144 Isolate* isolate,
145 DirectHandle<FunctionTemplateInfo> function_template_info) {
146 DCHECK(IsUndefined(function_template_info->rare_data(kAcquireLoad), isolate));
148 isolate->factory()->NewFunctionTemplateRareData();
149 function_template_info->set_rare_data(*rare_data, kReleaseStore);
150 return *rare_data;
151}
152
154 Isolate* isolate, Tagged<Object> getter) {
156 if (!IsFunctionTemplateInfo(getter)) {
157 if (!IsJSFunction(getter)) return {};
159 if (!info->IsApiFunction()) return {};
160 getter = info->api_func_data();
161 }
162 // Check if the accessor uses a cached property.
163 Tagged<Object> maybe_name =
164 Cast<FunctionTemplateInfo>(getter)->cached_property_name();
165 if (IsTheHole(maybe_name, isolate)) return {};
166 return Cast<Name>(maybe_name);
167}
168
171 return Cast<FixedArray>(GetCFunctionOverloads())->length() /
173}
174
178 isolate, Cast<FixedArray>(GetCFunctionOverloads())
179 ->get(index * kFunctionOverloadEntrySize));
180}
181
183 int index) const {
186 isolate, Cast<FixedArray>(GetCFunctionOverloads())
187 ->get(index * kFunctionOverloadEntrySize + 1));
188}
189
190// static
192 Isolate* isolate, const v8::MemorySpan<const std::string_view>& names) {
193 DirectHandle<FixedArray> property_names = isolate->factory()->NewFixedArray(
194 static_cast<int>(names.size()), AllocationType::kOld);
195 int index = 0;
196 uint32_t unused_array_index;
197 for (const std::string_view& name : names) {
198 DirectHandle<String> internalized_name =
199 isolate->factory()->InternalizeString(
200 base::Vector<const char>(name.data(), name.length()));
201 // Check that property name cannot be used as index.
202 CHECK(!internalized_name->AsArrayIndex(&unused_array_index));
203 property_names->set(index, *internalized_name);
204 ++index;
205 }
206 return isolate->factory()->NewDictionaryTemplateInfo(property_names);
207}
208
209namespace {
210
211DirectHandle<JSObject> CreateSlowJSObjectWithProperties(
212 Isolate* isolate, DirectHandle<FixedArray> property_names,
213 const MemorySpan<MaybeLocal<Value>>& property_values,
214 int num_properties_set) {
215 DirectHandle<JSObject> object = isolate->factory()->NewSlowJSObjectFromMap(
216 isolate->slow_object_with_object_prototype_map(), num_properties_set,
218 Handle<Object> properties = handle(object->raw_properties_or_hash(), isolate);
219 for (int i = 0; i < static_cast<int>(property_values.size()); ++i) {
220 Local<Value> property_value;
221 if (!property_values[i].ToLocal(&property_value)) {
222 continue;
223 }
224 properties = PropertyDictionary::Add(
225 isolate, Cast<PropertyDictionary>(properties),
226 Cast<String>(handle(property_names->get(i), isolate)),
228 }
229 object->set_raw_properties_or_hash(*properties);
230 return object;
231}
232
233} // namespace
234
235// static
239 const MemorySpan<MaybeLocal<Value>>& property_values) {
240 Isolate* isolate = context->GetIsolate();
241 DirectHandle<FixedArray> property_names(self->property_names(), isolate);
242
243 const int property_names_len = property_names->length();
244 CHECK_EQ(property_names_len, static_cast<int>(property_values.size()));
245 const int num_properties_set = static_cast<int>(std::count_if(
246 property_values.begin(), property_values.end(),
247 [](const auto& maybe_value) { return !maybe_value.IsEmpty(); }));
248
249 if (V8_UNLIKELY(num_properties_set > JSObject::kMaxInObjectProperties)) {
250 return CreateSlowJSObjectWithProperties(
251 isolate, property_names, property_values, num_properties_set);
252 }
253
254 const bool can_use_map_cache = num_properties_set == property_names_len;
255 MaybeDirectHandle<Map> maybe_cached_map;
256 if (V8_LIKELY(can_use_map_cache)) {
258 isolate, context, self, TemplateInfo::CachingMode::kUnlimited);
259 }
260 DirectHandle<Map> cached_map;
261 if (V8_LIKELY(can_use_map_cache && maybe_cached_map.ToHandle(&cached_map))) {
262 DCHECK(!cached_map->is_dictionary_map());
263 bool can_use_cached_map = !cached_map->is_deprecated();
264 if (V8_LIKELY(can_use_cached_map)) {
265 // Verify that the cached map can be reused.
266 auto descriptors = handle(cached_map->instance_descriptors(), isolate);
267 for (int i = 0; i < static_cast<int>(property_values.size()); ++i) {
269 Utils::OpenDirectHandle(*property_values[i].ToLocalChecked());
270 InternalIndex descriptor{static_cast<size_t>(i)};
271 const auto details = descriptors->GetDetails(descriptor);
272
273 if (!Object::FitsRepresentation(*value, details.representation()) ||
274 !FieldType::NowContains(descriptors->GetFieldType(descriptor),
275 value)) {
276 can_use_cached_map = false;
277 break;
278 }
279 // Double representation means mutable heap number. In this case we need
280 // to allocate a new heap number to put in the dictionary.
281 if (details.representation().Equals(Representation::Double())) {
282 // We allowed coercion in `FitsRepresentation` above which means that
283 // we may deal with a Smi here.
284 property_values[i] =
285 ToApiHandle<v8::Object>(isolate->factory()->NewHeapNumber(
287 }
288 }
289 if (V8_LIKELY(can_use_cached_map)) {
290 // Create the object from the cached map.
291 CHECK(!cached_map->is_deprecated());
292 CHECK_EQ(context->object_function_prototype(), cached_map->prototype());
293 auto object = isolate->factory()->NewJSObjectFromMap(
294 cached_map, AllocationType::kYoung);
296 for (int i = 0; i < static_cast<int>(property_values.size()); ++i) {
297 Local<Value> property_value = property_values[i].ToLocalChecked();
298 DirectHandle<Object> value = Utils::OpenDirectHandle(*property_value);
300 *cached_map, i, Representation::Tagged());
301 object->FastPropertyAtPut(index, *value,
303 }
304 return object;
305 }
306 }
307 // A cached map was either deprecated or the descriptors changed in
308 // incompatible ways. We clear the cached map and continue with the generic
309 // path.
311 isolate, context, self, TemplateInfo::CachingMode::kUnlimited);
312 }
313
314 // General case: We either don't have a cached map, or it is unusable for the
315 // values provided.
316 DirectHandle<Map> current_map = isolate->factory()->ObjectLiteralMapFromCache(
317 context, num_properties_set);
319 isolate->factory()->NewJSObjectFromMap(current_map);
320 int current_property_index = 0;
321 for (int i = 0; i < static_cast<int>(property_values.size()); ++i) {
322 Local<Value> property_value;
323 if (!property_values[i].ToLocal(&property_value)) {
324 continue;
325 }
326 auto name = Cast<String>(handle(property_names->get(i), isolate));
327 DirectHandle<Object> value = Utils::OpenDirectHandle(*property_value);
328 constexpr PropertyAttributes attributes = PropertyAttributes::NONE;
329 constexpr PropertyConstness constness = PropertyConstness::kConst;
330 current_map = Map::TransitionToDataProperty(isolate, current_map, name,
331 value, attributes, constness,
333 if (current_map->is_dictionary_map()) {
334 return CreateSlowJSObjectWithProperties(
335 isolate, property_names, property_values, num_properties_set);
336 }
337 JSObject::MigrateToMap(isolate, object, current_map);
338 PropertyDetails details = current_map->GetLastDescriptorDetails(isolate);
339 object->WriteToField(InternalIndex(current_property_index), details,
340 *value);
341 current_property_index++;
342 }
343 if (V8_LIKELY(can_use_map_cache)) {
345 isolate, context, self, TemplateInfo::CachingMode::kUnlimited,
346 direct_handle(object->map(), isolate));
347 }
348 return object;
349}
350
351} // namespace v8::internal
PropertyT * getter
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
Definition api.h:279
static DirectHandle< JSObject > NewInstance(DirectHandle< NativeContext > context, DirectHandle< DictionaryTemplateInfo > self, const MemorySpan< MaybeLocal< Value > > &property_values)
Definition templates.cc:236
static DirectHandle< DictionaryTemplateInfo > Create(Isolate *isolate, const v8::MemorySpan< const std::string_view > &names)
Definition templates.cc:191
static FieldIndex ForPropertyIndex(Tagged< Map > map, int index, Representation representation=Representation::Tagged())
static bool NowContains(Tagged< FieldType > type, Tagged< Object > value)
static const int kFunctionOverloadEntrySize
Definition templates.h:255
const CFunctionInfo * GetCSignature(Isolate *isolate, int index) const
Definition templates.cc:182
static std::optional< Tagged< Name > > TryGetCachedPropertyName(Isolate *isolate, Tagged< Object > getter)
Definition templates.cc:153
static void SealAndPrepareForPromotionToReadOnly(Isolate *isolate, DirectHandle< FunctionTemplateInfo > info)
Definition templates.cc:127
Address GetCFunction(Isolate *isolate, int index) const
Definition templates.cc:175
bool IsLeafTemplateForApiObject(Tagged< Object > object) const
Definition templates.cc:105
bool IsTemplateFor(Tagged< JSObject > object) const
static Handle< SharedFunctionInfo > GetOrCreateSharedFunctionInfo(Isolate *isolate, DirectHandle< FunctionTemplateInfo > info, MaybeDirectHandle< Name > maybe_name)
Definition templates.cc:32
static Tagged< FunctionTemplateRareData > AllocateFunctionTemplateRareData(Isolate *isolate, DirectHandle< FunctionTemplateInfo > function_template_info)
Definition templates.cc:143
static V8_INLINE bool InReadOnlySpace(Tagged< HeapObject > object)
static const int kMaxInObjectProperties
Definition js-objects.h:959
static V8_EXPORT_PRIVATE void MigrateToMap(Isolate *isolate, DirectHandle< JSObject > object, DirectHandle< Map > new_map, int expected_additional_properties=0)
static LocalIsolate * FromHeap(LocalHeap *heap)
static V8_EXPORT_PRIVATE DirectHandle< Map > TransitionToDataProperty(Isolate *isolate, DirectHandle< Map > map, DirectHandle< Name > name, DirectHandle< Object > value, PropertyAttributes attributes, PropertyConstness constness, StoreOrigin store_origin)
Definition map.cc:1987
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(DirectHandle< S > *out) const
static double NumberValue(Tagged< Number > obj)
static bool FitsRepresentation(Tagged< Object > obj, Representation representation, bool allow_coercion=true)
static constexpr PropertyDetails Empty(PropertyCellType cell_type=PropertyCellType::kNoCell)
static constexpr Representation Double()
static constexpr Representation Tagged()
static void CacheTemplateInstantiation(Isolate *isolate, DirectHandle< NativeContext > native_context, DirectHandle< TemplateInfo > info, CachingMode caching_mode, DirectHandle< Object > object)
static void UncacheTemplateInstantiation(Isolate *isolate, DirectHandle< NativeContext > native_context, DirectHandle< TemplateInfo > info, CachingMode caching_mode)
static MaybeHandle< ReturnType > ProbeInstantiationsCache(Isolate *isolate, DirectHandle< NativeContext > native_context, DirectHandle< TemplateInfo > info, CachingMode caching_mode)
Definition templates.h:70
ZoneVector< RpoNumber > & result
constexpr bool IsInRange(T value, U lower_limit, U higher_limit)
Definition bounds.h:20
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
@ SKIP_WRITE_BARRIER
Definition objects.h:52
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
V8_EXPORT_PRIVATE FlagValues v8_flags
allowed_receiver_instance_type_range_end
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr ReleaseStoreTag kReleaseStore
Definition globals.h:2910
bool ToLocal(v8::internal::MaybeDirectHandle< v8::internal::Object > maybe, Local< T > *local)
Definition api.h:303
v8::Local< T > ToApiHandle(v8::internal::DirectHandle< v8::internal::Object > obj)
Definition api.h:297
T ToCData(i::Isolate *isolate, v8::internal::Tagged< v8::internal::Object > obj)
Definition api-inl.h:23
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
#define RCS_SCOPE(...)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define V8_LIKELY(condition)
Definition v8config.h:661
#define V8_UNLIKELY(condition)
Definition v8config.h:660
wasm::ValueType type