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