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