1// Copyright 2016 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/compilation-info.h"
6
7#include "src/api.h"
8#include "src/ast/ast.h"
9#include "src/ast/scopes.h"
10#include "src/debug/debug.h"
11#include "src/isolate.h"
12#include "src/objects-inl.h"
13#include "src/parsing/parse-info.h"
14#include "src/source-position.h"
15
16namespace v8 {
17namespace internal {
18
19#define PARSE_INFO_GETTER(type, name)  \
20  type CompilationInfo::name() const { \
21    CHECK(parse_info());               \
22    return parse_info()->name();       \
23  }
24
25#define PARSE_INFO_GETTER_WITH_DEFAULT(type, name, def) \
26  type CompilationInfo::name() const {                  \
27    return parse_info() ? parse_info()->name() : def;   \
28  }
29
30PARSE_INFO_GETTER(Handle<Script>, script)
31PARSE_INFO_GETTER(FunctionLiteral*, literal)
32PARSE_INFO_GETTER_WITH_DEFAULT(DeclarationScope*, scope, nullptr)
33PARSE_INFO_GETTER(Handle<SharedFunctionInfo>, shared_info)
34
35#undef PARSE_INFO_GETTER
36#undef PARSE_INFO_GETTER_WITH_DEFAULT
37
38bool CompilationInfo::is_debug() const {
39  return parse_info() ? parse_info()->is_debug() : false;
40}
41
42void CompilationInfo::set_is_debug() {
43  CHECK(parse_info());
44  parse_info()->set_is_debug();
45}
46
47void CompilationInfo::PrepareForSerializing() {
48  if (parse_info()) parse_info()->set_will_serialize();
49  SetFlag(kSerializing);
50}
51
52bool CompilationInfo::has_shared_info() const {
53  return parse_info_ && !parse_info_->shared_info().is_null();
54}
55
56CompilationInfo::CompilationInfo(Zone* zone, ParseInfo* parse_info,
57                                 Handle<JSFunction> closure)
58    : CompilationInfo(parse_info, {}, Code::ComputeFlags(Code::FUNCTION), BASE,
59                      parse_info->isolate(), zone) {
60  closure_ = closure;
61
62  // Compiling for the snapshot typically results in different code than
63  // compiling later on. This means that code recompiled with deoptimization
64  // support won't be "equivalent" (as defined by SharedFunctionInfo::
65  // EnableDeoptimizationSupport), so it will replace the old code and all
66  // its type feedback. To avoid this, always compile functions in the snapshot
67  // with deoptimization support.
68  if (isolate_->serializer_enabled()) EnableDeoptimizationSupport();
69
70  if (FLAG_function_context_specialization) MarkAsFunctionContextSpecializing();
71  if (FLAG_turbo_splitting) MarkAsSplittingEnabled();
72
73  // Collect source positions for optimized code when profiling or if debugger
74  // is active, to be able to get more precise source positions at the price of
75  // more memory consumption.
76  if (isolate_->NeedsSourcePositionsForProfiling()) {
77    MarkAsSourcePositionsEnabled();
78  }
79}
80
81CompilationInfo::CompilationInfo(Vector<const char> debug_name,
82                                 Isolate* isolate, Zone* zone,
83                                 Code::Flags code_flags)
84    : CompilationInfo(nullptr, debug_name, code_flags, STUB, isolate, zone) {}
85
86CompilationInfo::CompilationInfo(ParseInfo* parse_info,
87                                 Vector<const char> debug_name,
88                                 Code::Flags code_flags, Mode mode,
89                                 Isolate* isolate, Zone* zone)
90    : parse_info_(parse_info),
91      isolate_(isolate),
92      flags_(0),
93      code_flags_(code_flags),
94      mode_(mode),
95      osr_ast_id_(BailoutId::None()),
96      zone_(zone),
97      deferred_handles_(nullptr),
98      dependencies_(isolate, zone),
99      bailout_reason_(kNoReason),
100      prologue_offset_(Code::kPrologueOffsetNotSet),
101      parameter_count_(0),
102      optimization_id_(-1),
103      osr_expr_stack_height_(-1),
104      debug_name_(debug_name) {}
105
106CompilationInfo::~CompilationInfo() {
107  if (GetFlag(kDisableFutureOptimization) && has_shared_info()) {
108    shared_info()->DisableOptimization(bailout_reason());
109  }
110  dependencies()->Rollback();
111}
112
113int CompilationInfo::num_parameters() const {
114  return !IsStub() ? scope()->num_parameters() : parameter_count_;
115}
116
117int CompilationInfo::num_parameters_including_this() const {
118  return num_parameters() + (is_this_defined() ? 1 : 0);
119}
120
121bool CompilationInfo::is_this_defined() const { return !IsStub(); }
122
123// Primitive functions are unlikely to be picked up by the stack-walking
124// profiler, so they trigger their own optimization when they're called
125// for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time.
126bool CompilationInfo::ShouldSelfOptimize() {
127  return FLAG_opt && FLAG_crankshaft &&
128         !(literal()->flags() & AstProperties::kDontSelfOptimize) &&
129         !literal()->dont_optimize() &&
130         literal()->scope()->AllowsLazyCompilation() &&
131         !shared_info()->optimization_disabled();
132}
133
134void CompilationInfo::set_deferred_handles(
135    std::shared_ptr<DeferredHandles> deferred_handles) {
136  DCHECK(deferred_handles_.get() == nullptr);
137  deferred_handles_.swap(deferred_handles);
138}
139
140void CompilationInfo::set_deferred_handles(DeferredHandles* deferred_handles) {
141  DCHECK(deferred_handles_.get() == nullptr);
142  deferred_handles_.reset(deferred_handles);
143}
144
145void CompilationInfo::ReopenHandlesInNewHandleScope() {
146  if (!closure_.is_null()) {
147    closure_ = Handle<JSFunction>(*closure_);
148  }
149}
150
151bool CompilationInfo::has_simple_parameters() {
152  return scope()->has_simple_parameters();
153}
154
155std::unique_ptr<char[]> CompilationInfo::GetDebugName() const {
156  if (parse_info() && parse_info()->literal()) {
157    AllowHandleDereference allow_deref;
158    return parse_info()->literal()->debug_name()->ToCString();
159  }
160  if (parse_info() && !parse_info()->shared_info().is_null()) {
161    return parse_info()->shared_info()->DebugName()->ToCString();
162  }
163  Vector<const char> name_vec = debug_name_;
164  if (name_vec.is_empty()) name_vec = ArrayVector("unknown");
165  std::unique_ptr<char[]> name(new char[name_vec.length() + 1]);
166  memcpy(name.get(), name_vec.start(), name_vec.length());
167  name[name_vec.length()] = '\0';
168  return name;
169}
170
171StackFrame::Type CompilationInfo::GetOutputStackFrameType() const {
172  switch (output_code_kind()) {
173    case Code::STUB:
174    case Code::BYTECODE_HANDLER:
175    case Code::HANDLER:
176    case Code::BUILTIN:
177#define CASE_KIND(kind) case Code::kind:
178      IC_KIND_LIST(CASE_KIND)
179#undef CASE_KIND
180      return StackFrame::STUB;
181    case Code::WASM_FUNCTION:
182      return StackFrame::WASM_COMPILED;
183    case Code::JS_TO_WASM_FUNCTION:
184      return StackFrame::JS_TO_WASM;
185    case Code::WASM_TO_JS_FUNCTION:
186      return StackFrame::WASM_TO_JS;
187    case Code::WASM_INTERPRETER_ENTRY:
188      return StackFrame::WASM_INTERPRETER_ENTRY;
189    default:
190      UNIMPLEMENTED();
191      return StackFrame::NONE;
192  }
193}
194
195int CompilationInfo::GetDeclareGlobalsFlags() const {
196  DCHECK(DeclareGlobalsLanguageMode::is_valid(parse_info()->language_mode()));
197  return DeclareGlobalsEvalFlag::encode(parse_info()->is_eval()) |
198         DeclareGlobalsNativeFlag::encode(parse_info()->is_native()) |
199         DeclareGlobalsLanguageMode::encode(parse_info()->language_mode());
200}
201
202SourcePositionTableBuilder::RecordingMode
203CompilationInfo::SourcePositionRecordingMode() const {
204  return parse_info() && parse_info()->is_native()
205             ? SourcePositionTableBuilder::OMIT_SOURCE_POSITIONS
206             : SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS;
207}
208
209bool CompilationInfo::ExpectsJSReceiverAsReceiver() {
210  return is_sloppy(parse_info()->language_mode()) && !parse_info()->is_native();
211}
212
213bool CompilationInfo::has_context() const { return !closure().is_null(); }
214
215Context* CompilationInfo::context() const {
216  return has_context() ? closure()->context() : nullptr;
217}
218
219bool CompilationInfo::has_native_context() const {
220  return !closure().is_null() && (closure()->native_context() != nullptr);
221}
222
223Context* CompilationInfo::native_context() const {
224  return has_native_context() ? closure()->native_context() : nullptr;
225}
226
227bool CompilationInfo::has_global_object() const { return has_native_context(); }
228
229JSGlobalObject* CompilationInfo::global_object() const {
230  return has_global_object() ? native_context()->global_object() : nullptr;
231}
232
233void CompilationInfo::SetOptimizing() {
234  DCHECK(has_shared_info());
235  SetMode(OPTIMIZE);
236  optimization_id_ = isolate()->NextOptimizationId();
237  code_flags_ = Code::KindField::update(code_flags_, Code::OPTIMIZED_FUNCTION);
238}
239
240int CompilationInfo::AddInlinedFunction(
241    Handle<SharedFunctionInfo> inlined_function, SourcePosition pos) {
242  int id = static_cast<int>(inlined_functions_.size());
243  inlined_functions_.push_back(InlinedFunctionHolder(
244      inlined_function, handle(inlined_function->code()), pos));
245  return id;
246}
247
248Code::Kind CompilationInfo::output_code_kind() const {
249  return Code::ExtractKindFromFlags(code_flags_);
250}
251
252}  // namespace internal
253}  // namespace v8
254