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