1 // Copyright 2020 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/objects/shared-function-info.h"
6
7 #include "src/ast/ast.h"
8 #include "src/ast/scopes.h"
9 #include "src/codegen/compilation-cache.h"
10 #include "src/codegen/compiler.h"
11 #include "src/diagnostics/code-tracer.h"
12 #include "src/objects/shared-function-info-inl.h"
13 #include "src/strings/string-builder-inl.h"
14
15 namespace v8 {
16 namespace internal {
17
18 V8_EXPORT_PRIVATE constexpr Smi SharedFunctionInfo::kNoSharedNameSentinel;
19
Hash()20 uint32_t SharedFunctionInfo::Hash() {
21 // Hash SharedFunctionInfo based on its start position and script id. Note: we
22 // don't use the function's literal id since getting that is slow for compiled
23 // funcitons.
24 int start_pos = StartPosition();
25 int script_id = script().IsScript() ? Script::cast(script()).id() : 0;
26 return static_cast<uint32_t>(base::hash_combine(start_pos, script_id));
27 }
28
Init(ReadOnlyRoots ro_roots,int unique_id)29 void SharedFunctionInfo::Init(ReadOnlyRoots ro_roots, int unique_id) {
30 DisallowHeapAllocation no_allocation;
31
32 // Set the function data to the "illegal" builtin. Ideally we'd use some sort
33 // of "uninitialized" marker here, but it's cheaper to use a valid buitin and
34 // avoid having to do uninitialized checks elsewhere.
35 set_builtin_id(Builtins::kIllegal);
36
37 // Set the name to the no-name sentinel, this can be updated later.
38 set_name_or_scope_info(SharedFunctionInfo::kNoSharedNameSentinel,
39 kReleaseStore, SKIP_WRITE_BARRIER);
40
41 // Generally functions won't have feedback, unless they have been created
42 // from a FunctionLiteral. Those can just reset this field to keep the
43 // SharedFunctionInfo in a consistent state.
44 set_raw_outer_scope_info_or_feedback_metadata(ro_roots.the_hole_value(),
45 SKIP_WRITE_BARRIER);
46 set_script_or_debug_info(ro_roots.undefined_value(), kReleaseStore,
47 SKIP_WRITE_BARRIER);
48 set_function_literal_id(kFunctionLiteralIdInvalid);
49 #if V8_SFI_HAS_UNIQUE_ID
50 set_unique_id(unique_id);
51 #endif
52
53 // Set integer fields (smi or int, depending on the architecture).
54 set_length(0);
55 set_internal_formal_parameter_count(0);
56 set_expected_nof_properties(0);
57 set_raw_function_token_offset(0);
58
59 // All flags default to false or 0, except ConstructAsBuiltinBit just because
60 // we're using the kIllegal builtin.
61 set_flags(ConstructAsBuiltinBit::encode(true));
62 set_flags2(0);
63
64 UpdateFunctionMapIndex();
65
66 clear_padding();
67 }
68
GetCode() const69 Code SharedFunctionInfo::GetCode() const {
70 // ======
71 // NOTE: This chain of checks MUST be kept in sync with the equivalent CSA
72 // GetSharedFunctionInfoCode method in code-stub-assembler.cc.
73 // ======
74
75 Isolate* isolate = GetIsolate();
76 Object data = function_data(kAcquireLoad);
77 if (data.IsSmi()) {
78 // Holding a Smi means we are a builtin.
79 DCHECK(HasBuiltinId());
80 return isolate->builtins()->builtin(builtin_id());
81 } else if (data.IsBytecodeArray()) {
82 // Having a bytecode array means we are a compiled, interpreted function.
83 DCHECK(HasBytecodeArray());
84 return isolate->builtins()->builtin(Builtins::kInterpreterEntryTrampoline);
85 } else if (data.IsAsmWasmData()) {
86 // Having AsmWasmData means we are an asm.js/wasm function.
87 DCHECK(HasAsmWasmData());
88 return isolate->builtins()->builtin(Builtins::kInstantiateAsmJs);
89 } else if (data.IsUncompiledData()) {
90 // Having uncompiled data (with or without scope) means we need to compile.
91 DCHECK(HasUncompiledData());
92 return isolate->builtins()->builtin(Builtins::kCompileLazy);
93 } else if (data.IsFunctionTemplateInfo()) {
94 // Having a function template info means we are an API function.
95 DCHECK(IsApiFunction());
96 return isolate->builtins()->builtin(Builtins::kHandleApiCall);
97 } else if (data.IsWasmExportedFunctionData()) {
98 // Having a WasmExportedFunctionData means the code is in there.
99 DCHECK(HasWasmExportedFunctionData());
100 return wasm_exported_function_data().wrapper_code();
101 } else if (data.IsInterpreterData()) {
102 Code code = InterpreterTrampoline();
103 DCHECK(code.IsCode());
104 DCHECK(code.is_interpreter_trampoline_builtin());
105 return code;
106 } else if (data.IsWasmJSFunctionData()) {
107 return wasm_js_function_data().wrapper_code();
108 } else if (data.IsWasmCapiFunctionData()) {
109 return wasm_capi_function_data().wrapper_code();
110 }
111 UNREACHABLE();
112 }
113
wasm_exported_function_data() const114 WasmExportedFunctionData SharedFunctionInfo::wasm_exported_function_data()
115 const {
116 DCHECK(HasWasmExportedFunctionData());
117 return WasmExportedFunctionData::cast(function_data(kAcquireLoad));
118 }
119
wasm_js_function_data() const120 WasmJSFunctionData SharedFunctionInfo::wasm_js_function_data() const {
121 DCHECK(HasWasmJSFunctionData());
122 return WasmJSFunctionData::cast(function_data(kAcquireLoad));
123 }
124
wasm_capi_function_data() const125 WasmCapiFunctionData SharedFunctionInfo::wasm_capi_function_data() const {
126 DCHECK(HasWasmCapiFunctionData());
127 return WasmCapiFunctionData::cast(function_data(kAcquireLoad));
128 }
129
ScriptIterator(Isolate * isolate,Script script)130 SharedFunctionInfo::ScriptIterator::ScriptIterator(Isolate* isolate,
131 Script script)
132 : ScriptIterator(handle(script.shared_function_infos(), isolate)) {}
133
ScriptIterator(Handle<WeakFixedArray> shared_function_infos)134 SharedFunctionInfo::ScriptIterator::ScriptIterator(
135 Handle<WeakFixedArray> shared_function_infos)
136 : shared_function_infos_(shared_function_infos), index_(0) {}
137
Next()138 SharedFunctionInfo SharedFunctionInfo::ScriptIterator::Next() {
139 while (index_ < shared_function_infos_->length()) {
140 MaybeObject raw = shared_function_infos_->Get(index_++);
141 HeapObject heap_object;
142 if (!raw->GetHeapObject(&heap_object) || heap_object.IsUndefined()) {
143 continue;
144 }
145 return SharedFunctionInfo::cast(heap_object);
146 }
147 return SharedFunctionInfo();
148 }
149
Reset(Isolate * isolate,Script script)150 void SharedFunctionInfo::ScriptIterator::Reset(Isolate* isolate,
151 Script script) {
152 shared_function_infos_ = handle(script.shared_function_infos(), isolate);
153 index_ = 0;
154 }
155
SetScript(ReadOnlyRoots roots,HeapObject script_object,int function_literal_id,bool reset_preparsed_scope_data)156 void SharedFunctionInfo::SetScript(ReadOnlyRoots roots,
157 HeapObject script_object,
158 int function_literal_id,
159 bool reset_preparsed_scope_data) {
160 DisallowHeapAllocation no_gc;
161
162 if (script() == script_object) return;
163
164 if (reset_preparsed_scope_data && HasUncompiledDataWithPreparseData()) {
165 ClearPreparseData();
166 }
167
168 // Add shared function info to new script's list. If a collection occurs,
169 // the shared function info may be temporarily in two lists.
170 // This is okay because the gc-time processing of these lists can tolerate
171 // duplicates.
172 if (script_object.IsScript()) {
173 DCHECK(!script().IsScript());
174 Script script = Script::cast(script_object);
175 WeakFixedArray list = script.shared_function_infos();
176 #ifdef DEBUG
177 DCHECK_LT(function_literal_id, list.length());
178 MaybeObject maybe_object = list.Get(function_literal_id);
179 HeapObject heap_object;
180 if (maybe_object->GetHeapObjectIfWeak(&heap_object)) {
181 DCHECK_EQ(heap_object, *this);
182 }
183 #endif
184 list.Set(function_literal_id, HeapObjectReference::Weak(*this));
185 } else {
186 DCHECK(script().IsScript());
187
188 // Remove shared function info from old script's list.
189 Script old_script = Script::cast(script());
190
191 // Due to liveedit, it might happen that the old_script doesn't know
192 // about the SharedFunctionInfo, so we have to guard against that.
193 WeakFixedArray infos = old_script.shared_function_infos();
194 if (function_literal_id < infos.length()) {
195 MaybeObject raw =
196 old_script.shared_function_infos().Get(function_literal_id);
197 HeapObject heap_object;
198 if (raw->GetHeapObjectIfWeak(&heap_object) && heap_object == *this) {
199 old_script.shared_function_infos().Set(
200 function_literal_id,
201 HeapObjectReference::Strong(roots.undefined_value()));
202 }
203 }
204 }
205
206 // Finally set new script.
207 set_script(script_object);
208 }
209
HasBreakInfo() const210 bool SharedFunctionInfo::HasBreakInfo() const {
211 if (!HasDebugInfo()) return false;
212 DebugInfo info = GetDebugInfo();
213 bool has_break_info = info.HasBreakInfo();
214 return has_break_info;
215 }
216
BreakAtEntry() const217 bool SharedFunctionInfo::BreakAtEntry() const {
218 if (!HasDebugInfo()) return false;
219 DebugInfo info = GetDebugInfo();
220 bool break_at_entry = info.BreakAtEntry();
221 return break_at_entry;
222 }
223
HasCoverageInfo() const224 bool SharedFunctionInfo::HasCoverageInfo() const {
225 if (!HasDebugInfo()) return false;
226 DebugInfo info = GetDebugInfo();
227 bool has_coverage_info = info.HasCoverageInfo();
228 return has_coverage_info;
229 }
230
GetCoverageInfo() const231 CoverageInfo SharedFunctionInfo::GetCoverageInfo() const {
232 DCHECK(HasCoverageInfo());
233 return CoverageInfo::cast(GetDebugInfo().coverage_info());
234 }
235
DebugName()236 String SharedFunctionInfo::DebugName() {
237 DisallowHeapAllocation no_gc;
238 String function_name = Name();
239 if (function_name.length() > 0) return function_name;
240 return inferred_name();
241 }
242
PassesFilter(const char * raw_filter)243 bool SharedFunctionInfo::PassesFilter(const char* raw_filter) {
244 Vector<const char> filter = CStrVector(raw_filter);
245 std::unique_ptr<char[]> cstrname(DebugName().ToCString());
246 return v8::internal::PassesFilter(CStrVector(cstrname.get()), filter);
247 }
248
HasSourceCode() const249 bool SharedFunctionInfo::HasSourceCode() const {
250 ReadOnlyRoots roots = GetReadOnlyRoots();
251 return !script().IsUndefined(roots) &&
252 !Script::cast(script()).source().IsUndefined(roots) &&
253 String::cast(Script::cast(script()).source()).length() > 0;
254 }
255
DiscardCompiledMetadata(Isolate * isolate,std::function<void (HeapObject object,ObjectSlot slot,HeapObject target)> gc_notify_updated_slot)256 void SharedFunctionInfo::DiscardCompiledMetadata(
257 Isolate* isolate,
258 std::function<void(HeapObject object, ObjectSlot slot, HeapObject target)>
259 gc_notify_updated_slot) {
260 DisallowHeapAllocation no_gc;
261 if (is_compiled()) {
262 if (FLAG_trace_flush_bytecode) {
263 CodeTracer::Scope scope(GetIsolate()->GetCodeTracer());
264 PrintF(scope.file(), "[discarding compiled metadata for ");
265 ShortPrint(scope.file());
266 PrintF(scope.file(), "]\n");
267 }
268
269 HeapObject outer_scope_info;
270 if (scope_info().HasOuterScopeInfo()) {
271 outer_scope_info = scope_info().OuterScopeInfo();
272 } else {
273 outer_scope_info = ReadOnlyRoots(isolate).the_hole_value();
274 }
275
276 // Raw setter to avoid validity checks, since we're performing the unusual
277 // task of decompiling.
278 set_raw_outer_scope_info_or_feedback_metadata(outer_scope_info);
279 gc_notify_updated_slot(
280 *this,
281 RawField(SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset),
282 outer_scope_info);
283 } else {
284 DCHECK(outer_scope_info().IsScopeInfo() || outer_scope_info().IsTheHole());
285 }
286
287 // TODO(rmcilroy): Possibly discard ScopeInfo here as well.
288 }
289
290 // static
DiscardCompiled(Isolate * isolate,Handle<SharedFunctionInfo> shared_info)291 void SharedFunctionInfo::DiscardCompiled(
292 Isolate* isolate, Handle<SharedFunctionInfo> shared_info) {
293 DCHECK(shared_info->CanDiscardCompiled());
294
295 Handle<String> inferred_name_val =
296 handle(shared_info->inferred_name(), isolate);
297 int start_position = shared_info->StartPosition();
298 int end_position = shared_info->EndPosition();
299
300 shared_info->DiscardCompiledMetadata(isolate);
301
302 // Replace compiled data with a new UncompiledData object.
303 if (shared_info->HasUncompiledDataWithPreparseData()) {
304 // If this is uncompiled data with a pre-parsed scope data, we can just
305 // clear out the scope data and keep the uncompiled data.
306 shared_info->ClearPreparseData();
307 } else {
308 // Create a new UncompiledData, without pre-parsed scope, and update the
309 // function data to point to it. Use the raw function data setter to avoid
310 // validity checks, since we're performing the unusual task of decompiling.
311 Handle<UncompiledData> data =
312 isolate->factory()->NewUncompiledDataWithoutPreparseData(
313 inferred_name_val, start_position, end_position);
314 shared_info->set_function_data(*data, kReleaseStore);
315 }
316 }
317
318 // static
GetSourceCode(Handle<SharedFunctionInfo> shared)319 Handle<Object> SharedFunctionInfo::GetSourceCode(
320 Handle<SharedFunctionInfo> shared) {
321 Isolate* isolate = shared->GetIsolate();
322 if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
323 Handle<String> source(String::cast(Script::cast(shared->script()).source()),
324 isolate);
325 return isolate->factory()->NewSubString(source, shared->StartPosition(),
326 shared->EndPosition());
327 }
328
329 // static
GetSourceCodeHarmony(Handle<SharedFunctionInfo> shared)330 Handle<Object> SharedFunctionInfo::GetSourceCodeHarmony(
331 Handle<SharedFunctionInfo> shared) {
332 Isolate* isolate = shared->GetIsolate();
333 if (!shared->HasSourceCode()) return isolate->factory()->undefined_value();
334 Handle<String> script_source(
335 String::cast(Script::cast(shared->script()).source()), isolate);
336 int start_pos = shared->function_token_position();
337 DCHECK_NE(start_pos, kNoSourcePosition);
338 Handle<String> source = isolate->factory()->NewSubString(
339 script_source, start_pos, shared->EndPosition());
340 if (!shared->is_wrapped()) return source;
341
342 DCHECK(!shared->name_should_print_as_anonymous());
343 IncrementalStringBuilder builder(isolate);
344 builder.AppendCString("function ");
345 builder.AppendString(Handle<String>(shared->Name(), isolate));
346 builder.AppendCString("(");
347 Handle<FixedArray> args(Script::cast(shared->script()).wrapped_arguments(),
348 isolate);
349 int argc = args->length();
350 for (int i = 0; i < argc; i++) {
351 if (i > 0) builder.AppendCString(", ");
352 builder.AppendString(Handle<String>(String::cast(args->get(i)), isolate));
353 }
354 builder.AppendCString(") {\n");
355 builder.AppendString(source);
356 builder.AppendCString("\n}");
357 return builder.Finish().ToHandleChecked();
358 }
359
GetInlineability() const360 SharedFunctionInfo::Inlineability SharedFunctionInfo::GetInlineability() const {
361 if (!script().IsScript()) return kHasNoScript;
362
363 if (GetIsolate()->is_precise_binary_code_coverage() &&
364 !has_reported_binary_coverage()) {
365 // We may miss invocations if this function is inlined.
366 return kNeedsBinaryCoverage;
367 }
368
369 if (optimization_disabled()) return kHasOptimizationDisabled;
370
371 // Built-in functions are handled by the JSCallReducer.
372 if (HasBuiltinId()) return kIsBuiltin;
373
374 if (!IsUserJavaScript()) return kIsNotUserCode;
375
376 // If there is no bytecode array, it is either not compiled or it is compiled
377 // with WebAssembly for the asm.js pipeline. In either case we don't want to
378 // inline.
379 if (!HasBytecodeArray()) return kHasNoBytecode;
380
381 if (GetBytecodeArray().length() > FLAG_max_inlined_bytecode_size) {
382 return kExceedsBytecodeLimit;
383 }
384
385 if (HasBreakInfo()) return kMayContainBreakPoints;
386
387 return kIsInlineable;
388 }
389
SourceSize()390 int SharedFunctionInfo::SourceSize() { return EndPosition() - StartPosition(); }
391
392 // Output the source code without any allocation in the heap.
operator <<(std::ostream & os,const SourceCodeOf & v)393 std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
394 const SharedFunctionInfo s = v.value;
395 // For some native functions there is no source.
396 if (!s.HasSourceCode()) return os << "<No Source>";
397
398 // Get the source for the script which this function came from.
399 // Don't use String::cast because we don't want more assertion errors while
400 // we are already creating a stack dump.
401 String script_source =
402 String::unchecked_cast(Script::cast(s.script()).source());
403
404 if (!script_source.LooksValid()) return os << "<Invalid Source>";
405
406 if (!s.is_toplevel()) {
407 os << "function ";
408 String name = s.Name();
409 if (name.length() > 0) {
410 name.PrintUC16(os);
411 }
412 }
413
414 int len = s.EndPosition() - s.StartPosition();
415 if (len <= v.max_length || v.max_length < 0) {
416 script_source.PrintUC16(os, s.StartPosition(), s.EndPosition());
417 return os;
418 } else {
419 script_source.PrintUC16(os, s.StartPosition(),
420 s.StartPosition() + v.max_length);
421 return os << "...\n";
422 }
423 }
424
TryGetCachedCode(Isolate * isolate)425 MaybeHandle<Code> SharedFunctionInfo::TryGetCachedCode(Isolate* isolate) {
426 if (!may_have_cached_code()) return {};
427 Handle<SharedFunctionInfo> zis(*this, isolate);
428 return isolate->compilation_cache()->LookupCode(zis);
429 }
430
DisableOptimization(BailoutReason reason)431 void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
432 DCHECK_NE(reason, BailoutReason::kNoReason);
433
434 set_flags(DisabledOptimizationReasonBits::update(flags(), reason));
435 // Code should be the lazy compilation stub or else interpreted.
436 DCHECK(abstract_code().kind() == CodeKind::INTERPRETED_FUNCTION ||
437 abstract_code().kind() == CodeKind::BUILTIN);
438 PROFILE(GetIsolate(),
439 CodeDisableOptEvent(handle(abstract_code(), GetIsolate()),
440 handle(*this, GetIsolate())));
441 if (FLAG_trace_opt) {
442 CodeTracer::Scope scope(GetIsolate()->GetCodeTracer());
443 PrintF(scope.file(), "[disabled optimization for ");
444 ShortPrint(scope.file());
445 PrintF(scope.file(), ", reason: %s]\n", GetBailoutReason(reason));
446 }
447 }
448
449 // static
450 template <typename LocalIsolate>
InitFromFunctionLiteral(LocalIsolate * isolate,Handle<SharedFunctionInfo> shared_info,FunctionLiteral * lit,bool is_toplevel)451 void SharedFunctionInfo::InitFromFunctionLiteral(
452 LocalIsolate* isolate, Handle<SharedFunctionInfo> shared_info,
453 FunctionLiteral* lit, bool is_toplevel) {
454 DCHECK(!shared_info->name_or_scope_info(kAcquireLoad).IsScopeInfo());
455
456 // When adding fields here, make sure DeclarationScope::AnalyzePartially is
457 // updated accordingly.
458 shared_info->set_internal_formal_parameter_count(lit->parameter_count());
459 shared_info->SetFunctionTokenPosition(lit->function_token_position(),
460 lit->start_position());
461 shared_info->set_syntax_kind(lit->syntax_kind());
462 shared_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
463 shared_info->set_language_mode(lit->language_mode());
464 shared_info->set_function_literal_id(lit->function_literal_id());
465 // FunctionKind must have already been set.
466 DCHECK(lit->kind() == shared_info->kind());
467 shared_info->set_needs_home_object(lit->scope()->NeedsHomeObject());
468 DCHECK_IMPLIES(lit->requires_instance_members_initializer(),
469 IsClassConstructor(lit->kind()));
470 shared_info->set_requires_instance_members_initializer(
471 lit->requires_instance_members_initializer());
472 DCHECK_IMPLIES(lit->class_scope_has_private_brand(),
473 IsClassConstructor(lit->kind()));
474 shared_info->set_class_scope_has_private_brand(
475 lit->class_scope_has_private_brand());
476 DCHECK_IMPLIES(lit->has_static_private_methods_or_accessors(),
477 IsClassConstructor(lit->kind()));
478 shared_info->set_has_static_private_methods_or_accessors(
479 lit->has_static_private_methods_or_accessors());
480
481 shared_info->set_is_toplevel(is_toplevel);
482 DCHECK(shared_info->outer_scope_info().IsTheHole());
483 if (!is_toplevel) {
484 Scope* outer_scope = lit->scope()->GetOuterScopeWithContext();
485 if (outer_scope) {
486 shared_info->set_outer_scope_info(*outer_scope->scope_info());
487 shared_info->set_private_name_lookup_skips_outer_class(
488 lit->scope()->private_name_lookup_skips_outer_class());
489 }
490 }
491
492 shared_info->set_length(lit->function_length());
493
494 // For lazy parsed functions, the following flags will be inaccurate since we
495 // don't have the information yet. They're set later in
496 // SetSharedFunctionFlagsFromLiteral (compiler.cc), when the function is
497 // really parsed and compiled.
498 if (lit->ShouldEagerCompile()) {
499 shared_info->set_has_duplicate_parameters(lit->has_duplicate_parameters());
500 shared_info->UpdateAndFinalizeExpectedNofPropertiesFromEstimate(lit);
501 DCHECK_NULL(lit->produced_preparse_data());
502
503 // If we're about to eager compile, we'll have the function literal
504 // available, so there's no need to wastefully allocate an uncompiled data.
505 return;
506 }
507
508 shared_info->UpdateExpectedNofPropertiesFromEstimate(lit);
509
510 Handle<UncompiledData> data;
511
512 ProducedPreparseData* scope_data = lit->produced_preparse_data();
513 if (scope_data != nullptr) {
514 Handle<PreparseData> preparse_data = scope_data->Serialize(isolate);
515
516 data = isolate->factory()->NewUncompiledDataWithPreparseData(
517 lit->GetInferredName(isolate), lit->start_position(),
518 lit->end_position(), preparse_data);
519 } else {
520 data = isolate->factory()->NewUncompiledDataWithoutPreparseData(
521 lit->GetInferredName(isolate), lit->start_position(),
522 lit->end_position());
523 }
524
525 shared_info->set_uncompiled_data(*data);
526 }
527
528 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void SharedFunctionInfo::
529 InitFromFunctionLiteral<Isolate>(Isolate* isolate,
530 Handle<SharedFunctionInfo> shared_info,
531 FunctionLiteral* lit, bool is_toplevel);
532 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void SharedFunctionInfo::
533 InitFromFunctionLiteral<LocalIsolate>(
534 LocalIsolate* isolate, Handle<SharedFunctionInfo> shared_info,
535 FunctionLiteral* lit, bool is_toplevel);
536
get_property_estimate_from_literal(FunctionLiteral * literal)537 uint16_t SharedFunctionInfo::get_property_estimate_from_literal(
538 FunctionLiteral* literal) {
539 int estimate = literal->expected_property_count();
540
541 // If this is a class constructor, we may have already parsed fields.
542 if (is_class_constructor()) {
543 estimate += expected_nof_properties();
544 }
545 return estimate;
546 }
547
UpdateExpectedNofPropertiesFromEstimate(FunctionLiteral * literal)548 void SharedFunctionInfo::UpdateExpectedNofPropertiesFromEstimate(
549 FunctionLiteral* literal) {
550 // Limit actual estimate to fit in a 8 bit field, we will never allocate
551 // more than this in any case.
552 STATIC_ASSERT(JSObject::kMaxInObjectProperties <= kMaxUInt8);
553 int estimate = get_property_estimate_from_literal(literal);
554 set_expected_nof_properties(std::min(estimate, kMaxUInt8));
555 }
556
UpdateAndFinalizeExpectedNofPropertiesFromEstimate(FunctionLiteral * literal)557 void SharedFunctionInfo::UpdateAndFinalizeExpectedNofPropertiesFromEstimate(
558 FunctionLiteral* literal) {
559 DCHECK(literal->ShouldEagerCompile());
560 if (are_properties_final()) {
561 return;
562 }
563 int estimate = get_property_estimate_from_literal(literal);
564
565 // If no properties are added in the constructor, they are more likely
566 // to be added later.
567 if (estimate == 0) estimate = 2;
568
569 // Limit actual estimate to fit in a 8 bit field, we will never allocate
570 // more than this in any case.
571 STATIC_ASSERT(JSObject::kMaxInObjectProperties <= kMaxUInt8);
572 estimate = std::min(estimate, kMaxUInt8);
573
574 set_expected_nof_properties(estimate);
575 set_are_properties_final(true);
576 }
577
SetFunctionTokenPosition(int function_token_position,int start_position)578 void SharedFunctionInfo::SetFunctionTokenPosition(int function_token_position,
579 int start_position) {
580 int offset;
581 if (function_token_position == kNoSourcePosition) {
582 offset = 0;
583 } else {
584 offset = start_position - function_token_position;
585 }
586
587 if (offset > kMaximumFunctionTokenOffset) {
588 offset = kFunctionTokenOutOfRange;
589 }
590 set_raw_function_token_offset(offset);
591 }
592
StartPosition() const593 int SharedFunctionInfo::StartPosition() const {
594 Object maybe_scope_info = name_or_scope_info(kAcquireLoad);
595 if (maybe_scope_info.IsScopeInfo()) {
596 ScopeInfo info = ScopeInfo::cast(maybe_scope_info);
597 if (info.HasPositionInfo()) {
598 return info.StartPosition();
599 }
600 }
601 if (HasUncompiledData()) {
602 // Works with or without scope.
603 return uncompiled_data().start_position();
604 }
605 if (IsApiFunction() || HasBuiltinId()) {
606 DCHECK_IMPLIES(HasBuiltinId(), builtin_id() != Builtins::kCompileLazy);
607 return 0;
608 }
609 if (HasWasmExportedFunctionData()) {
610 WasmInstanceObject instance = wasm_exported_function_data().instance();
611 int func_index = wasm_exported_function_data().function_index();
612 auto& function = instance.module()->functions[func_index];
613 return static_cast<int>(function.code.offset());
614 }
615 return kNoSourcePosition;
616 }
617
EndPosition() const618 int SharedFunctionInfo::EndPosition() const {
619 Object maybe_scope_info = name_or_scope_info(kAcquireLoad);
620 if (maybe_scope_info.IsScopeInfo()) {
621 ScopeInfo info = ScopeInfo::cast(maybe_scope_info);
622 if (info.HasPositionInfo()) {
623 return info.EndPosition();
624 }
625 }
626 if (HasUncompiledData()) {
627 // Works with or without scope.
628 return uncompiled_data().end_position();
629 }
630 if (IsApiFunction() || HasBuiltinId()) {
631 DCHECK_IMPLIES(HasBuiltinId(), builtin_id() != Builtins::kCompileLazy);
632 return 0;
633 }
634 if (HasWasmExportedFunctionData()) {
635 WasmInstanceObject instance = wasm_exported_function_data().instance();
636 int func_index = wasm_exported_function_data().function_index();
637 auto& function = instance.module()->functions[func_index];
638 return static_cast<int>(function.code.end_offset());
639 }
640 return kNoSourcePosition;
641 }
642
SetPosition(int start_position,int end_position)643 void SharedFunctionInfo::SetPosition(int start_position, int end_position) {
644 Object maybe_scope_info = name_or_scope_info(kAcquireLoad);
645 if (maybe_scope_info.IsScopeInfo()) {
646 ScopeInfo info = ScopeInfo::cast(maybe_scope_info);
647 if (info.HasPositionInfo()) {
648 info.SetPositionInfo(start_position, end_position);
649 }
650 } else if (HasUncompiledData()) {
651 if (HasUncompiledDataWithPreparseData()) {
652 // Clear out preparsed scope data, since the position setter invalidates
653 // any scope data.
654 ClearPreparseData();
655 }
656 uncompiled_data().set_start_position(start_position);
657 uncompiled_data().set_end_position(end_position);
658 } else {
659 UNREACHABLE();
660 }
661 }
662
AreSourcePositionsAvailable() const663 bool SharedFunctionInfo::AreSourcePositionsAvailable() const {
664 if (FLAG_enable_lazy_source_positions) {
665 return !HasBytecodeArray() || GetBytecodeArray().HasSourcePositionTable();
666 }
667 return true;
668 }
669
670 // static
EnsureSourcePositionsAvailable(Isolate * isolate,Handle<SharedFunctionInfo> shared_info)671 void SharedFunctionInfo::EnsureSourcePositionsAvailable(
672 Isolate* isolate, Handle<SharedFunctionInfo> shared_info) {
673 if (FLAG_enable_lazy_source_positions && shared_info->HasBytecodeArray() &&
674 !shared_info->GetBytecodeArray().HasSourcePositionTable()) {
675 Compiler::CollectSourcePositions(isolate, shared_info);
676 }
677 }
678
679 } // namespace internal
680 } // namespace v8
681