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