7#if !defined(DART_PRECOMPILED_RUNTIME)
53 max_deoptimization_counter_threshold,
55 "How many times we allow deoptimization before we disallow optimization.");
59 "Optimize only named function");
60DEFINE_FLAG(
bool, print_flow_graph,
false,
"Print the IR flow graph.");
62 print_flow_graph_optimized,
64 "Print the IR flow graph when optimizing.");
68 "Print the deopt-id to ICData map in optimizing compiler.");
69DEFINE_FLAG(
bool, print_code_source_map,
false,
"Print code source map.");
71 stress_test_background_compilation,
73 "Keep background compiler running all the time");
75 stop_on_excessive_deoptimization,
77 "Debugging: stops program if deoptimizing same function too often");
78DEFINE_FLAG(
bool, trace_compiler,
false,
"Trace compiler operations.");
80 trace_failed_optimization_attempts,
82 "Traces all failed optimization attempts");
84 trace_optimizing_compiler,
86 "Trace only optimizing compiler operations.");
87DEFINE_FLAG(
bool, trace_bailout,
false,
"Print bailout from ssa compiler.");
93#if defined(TARGET_ARCH_IA32)
94 FATAL(
"Precompilation not supported on IA32");
97 FLAG_background_compilation =
false;
98 FLAG_enable_mirrors =
false;
99 FLAG_interpret_irregexp =
true;
100 FLAG_link_natives_lazily =
true;
101 FLAG_optimization_counter_threshold = -1;
102 FLAG_polymorphic_with_deopt =
false;
103 FLAG_precompiled_mode =
true;
104 FLAG_reorder_basic_blocks =
true;
105 FLAG_use_field_guards =
false;
106 FLAG_use_cha_deopt =
false;
108#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
111 FLAG_deoptimize_alot =
false;
112 FLAG_deoptimize_every = 0;
113 FLAG_use_osr =
false;
120 "Precompilation mode");
122#ifndef DART_PRECOMPILED_RUNTIME
146 VMTag::kCompileParseRegExpTagId);
147 Zone* zone = parsed_function->
zone();
158 if (compile_data->
simple) {
178 parsed_function, *ic_data_array, osr_id);
179 if (
result.error_message !=
nullptr) {
183 backtrack_goto_ =
result.backtrack_goto;
193 result.graph_entry->RelinkToOsrEntry(zone,
result.num_blocks);
203 if (
function.IsIrregexpFunction()) {
213 ASSERT(thread->IsDartMutatorThread());
214 const Function&
function = Function::CheckedHandle(zone, arguments.ArgAt(0));
247 if (
function.deoptimization_counter() >=
248 FLAG_max_deoptimization_counter_threshold) {
249 if (FLAG_trace_failed_optimization_attempts ||
250 FLAG_stop_on_excessive_deoptimization) {
251 THR_Print(
"Too many deoptimizations: %s\n",
252 function.ToFullyQualifiedCString());
253 if (FLAG_stop_on_excessive_deoptimization) {
254 FATAL(
"Stop on excessive deoptimization");
260 function.SetUsageCounter(INT32_MIN);
263 if (FLAG_optimization_filter !=
nullptr) {
268 intptr_t
len = strlen(FLAG_optimization_filter) + 1;
269 char* filter =
new char[
len];
270 strncpy(filter, FLAG_optimization_filter,
len);
271 char* token = strtok_r(filter,
",", &save_ptr);
273 while (token !=
nullptr) {
278 token = strtok_r(
nullptr,
",", &save_ptr);
282 function.SetUsageCounter(INT32_MIN);
289 if (FLAG_trace_failed_optimization_attempts) {
292 function.SetUsageCounter(INT32_MIN);
308 : parsed_function_(parsed_function),
309 optimized_(optimized),
311 thread_(
Thread::Current()) {}
316 ParsedFunction* parsed_function()
const {
return parsed_function_; }
317 bool optimized()
const {
return optimized_; }
318 intptr_t osr_id()
const {
return osr_id_; }
319 Thread* thread()
const {
return thread_; }
320 IsolateGroup* isolate_group()
const {
return thread_->
isolate_group(); }
321 CodePtr FinalizeCompilation(compiler::Assembler* assembler,
322 FlowGraphCompiler* graph_compiler,
323 FlowGraph* flow_graph);
325 ParsedFunction* parsed_function_;
326 const bool optimized_;
327 const intptr_t osr_id_;
328 Thread*
const thread_;
333CodePtr CompileParsedFunctionHelper::FinalizeCompilation(
334 compiler::Assembler* assembler,
335 FlowGraphCompiler* graph_compiler,
336 FlowGraph* flow_graph) {
347 if (optimized() &&
function.ForceOptimize() &&
function.HasOptimizedCode()) {
350 Zone*
const zone = thread()->
zone();
354 Array& deopt_info_array =
Array::Handle(zone, Object::empty_array().ptr());
355 deopt_info_array = graph_compiler->CreateDeoptInfo(assembler);
362 code.set_is_optimized(optimized());
368 function.SetUsageCounter(INT32_MIN);
371 graph_compiler->FinalizePcDescriptors(
code);
372 code.set_deopt_info_array(deopt_info_array);
374 graph_compiler->FinalizeStackMaps(
code);
375 graph_compiler->FinalizeVarDescriptors(
code);
376 graph_compiler->FinalizeExceptionHandlers(
code);
377 graph_compiler->FinalizeCatchEntryMovesMap(
code);
378 graph_compiler->FinalizeStaticCallTargetsTable(
code);
379 graph_compiler->FinalizeCodeSourceMap(
code);
382 ASSERT(optimized() && thread()->IsDartMutatorThread());
383 code.set_is_force_optimized(
true);
386 }
else if (optimized()) {
397 const bool trace_compiler =
398 FLAG_trace_compiler || FLAG_trace_optimizing_compiler;
399 bool code_is_valid =
true;
400 if (flow_graph->parsed_function().guarded_fields()->Length() != 0) {
402 flow_graph->parsed_function().guarded_fields();
404 FieldSet::Iterator it = guarded_fields->GetIterator();
405 while (
const Field** field = it.Next()) {
406 ASSERT(!(*field)->IsOriginal());
407 original = (*field)->Original();
408 if (!(*field)->IsConsistentWith(original)) {
409 code_is_valid =
false;
410 if (trace_compiler) {
411 THR_Print(
"--> FAIL: Field %s guarded state changed.",
412 (*field)->ToCString());
419 if (!thread()->compiler_state().cha().IsConsistentWithCurrentHierarchy()) {
420 code_is_valid =
false;
421 if (trace_compiler) {
422 THR_Print(
"--> FAIL: Class hierarchy has new subclasses.");
445 thread()->isolate_group()->optimization_counter_threshold() - 100);
449 if (!
code.IsNull()) {
456 flow_graph->parsed_function().guarded_fields();
458 FieldSet::Iterator it = guarded_fields->GetIterator();
459 while (
const Field** guarded_field = it.Next()) {
460 field = (*guarded_field)->Original();
461 field.RegisterDependentCode(
code);
466 graph_compiler->deopt_id_to_ic_data(),
468 flow_graph->coverage_array());
479 if (
function.IsFfiCallbackTrampoline()) {
488 ASSERT(!FLAG_precompiled_mode);
490 if (optimized() && !
function.IsOptimizable()) {
493 Zone*
const zone = thread()->
zone();
502 volatile bool done =
false;
504 volatile intptr_t far_branch_level = 0;
514 if (setjmp(*jump.
Set()) == 0) {
530 function.RestoreICDataMap(ic_data_array, clone_ic_data);
537 if (FLAG_print_ic_data_map) {
538 for (intptr_t
i = 0;
i < ic_data_array->
length();
i++) {
539 if ((*ic_data_array)[
i] !=
nullptr) {
548 zone, parsed_function(), ic_data_array, osr_id(), optimized());
551 const bool print_flow_graph =
552 (FLAG_print_flow_graph ||
553 (optimized() && FLAG_print_flow_graph_optimized)) &&
556 if (print_flow_graph && !optimized()) {
562 "BlockScheduler::AssignEdgeWeights");
582 &assembler, flow_graph, *parsed_function(), optimized(),
592 auto install_code_fun = [&]() {
594 FinalizeCompilation(&assembler, &graph_compiler, flow_graph);
617 thread()->isolate_group()->program_lock());
632 install_code_fun,
true);
640 }
else if (FLAG_disassemble_optimized && optimized() &&
651 if (
error.ptr() == Object::branch_offset_error().ptr()) {
657 }
else if (
error.ptr() == Object::speculative_inlining_error().ptr()) {
663 if (FLAG_trace_bailout) {
684 volatile bool optimized,
689 ASSERT(!FLAG_precompiled_mode);
691 if (
function.ForceOptimize()) optimized =
true;
693 if (setjmp(*jump.
Set()) == 0) {
696 const bool trace_compiler =
697 FLAG_trace_compiler || (FLAG_trace_optimizing_compiler && optimized);
698 Timer per_compile_timer;
699 per_compile_timer.
Start();
703 if (trace_compiler) {
704 const intptr_t token_size =
function.SourceSize();
705 THR_Print(
"Compiling %s%sfunction %s: '%s' @ token %s, size %" Pd "\n",
707 (optimized ?
"optimized " :
""),
710 function.token_pos().ToCString(), token_size);
728 if (FLAG_trace_compiler) {
729 THR_Print(
"Aborted background compilation: %s\n",
730 function.ToFullyQualifiedCString());
735 if (
error.ptr() == Object::background_compilation_error().ptr()) {
736 if (FLAG_trace_compiler) {
738 "--> discarding background compilation for '%s' (will "
739 "try to re-compile again later)\n",
740 function.ToFullyQualifiedCString());
747 }
else if (
error.IsLanguageError() &&
749 if (FLAG_trace_compiler) {
750 THR_Print(
"--> disabling optimizations for '%s'\n",
751 function.ToFullyQualifiedCString());
763 if (
error.IsLanguageError() &&
768 if (trace_compiler) {
769 THR_Print(
"--> disabling optimizations for '%s'\n",
770 function.ToFullyQualifiedCString());
771 }
else if (FLAG_trace_failed_optimization_attempts) {
773 function.ToFullyQualifiedCString());
785 (
error.IsLanguageError() &&
792 per_compile_timer.
Stop();
794 if (trace_compiler) {
797 function.ToFullyQualifiedCString(),
code.PayloadStart(),
808 if (
error.ptr() == Object::background_compilation_error().ptr()) {
810 if (FLAG_trace_bailout) {
811 THR_Print(
"Aborted background compilation: %s\n",
812 function.ToFullyQualifiedCString());
825#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
829#if defined(DART_PRECOMPILED_RUNTIME)
830 FATAL(
"Precompilation missed function %s (%s, %s)\n",
831 function.ToLibNamePrefixedQualifiedCString(),
836 VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
837#if defined(SUPPORT_TIMELINE)
838 const char* event_name;
840 event_name =
"CompileFunctionUnoptimizedBackground";
842 event_name =
"CompileFunction";
850 const bool optimized =
function.ForceOptimize();
862 original_code =
function.CurrentCode();
870 return Error::Cast(
result).ptr();
880 if (FLAG_trace_compiler) {
889 VMTagScope tag_scope(thread, VMTag::kCompileOptimizedTagId);
891#if defined(SUPPORT_TIMELINE)
892 const char* event_name;
894 event_name =
"CompileFunctionOptimizedOSR";
896 event_name =
"CompileFunctionOptimizedBackground";
898 event_name =
"CompileFunctionOptimized";
911 ASSERT(!FLAG_precompiled_mode);
922 if (setjmp(*jump.
Set()) == 0) {
931 parsed_function, ic_data_array, context_level_array,
940 ASSERT(!var_descs.IsNull());
941 code.set_var_descriptors(var_descs);
957 for (
int i = 0;
i < functions.
Length();
i++) {
958 func ^= functions.
At(
i);
960 if (!func.
HasCode() && !func.is_abstract()) {
963 return Error::Cast(
result).ptr();
972 if (FLAG_trace_compiler) {
973 THR_Print(
"ABORT background compilation: %s\n", msg);
978 TimelineEvent*
event =
stream->StartEvent();
979 if (
event !=
nullptr) {
980 event->Instant(
"AbortBackgroundCompilation");
981 event->SetNumArguments(1);
982 event->CopyArgument(0,
"reason", msg);
988 deopt_id, Object::background_compilation_error());
995 : next_(nullptr), function_(
function.ptr()) {}
1009 return reinterpret_cast<ObjectPtr*
>(&function_);
1014 FunctionPtr function_;
1027 ASSERT(visitor !=
nullptr);
1029 while (
p !=
nullptr) {
1035 bool IsEmpty()
const {
return first_ ==
nullptr; }
1040 if (first_ ==
nullptr) {
1042 ASSERT(last_ ==
nullptr);
1044 ASSERT(last_ !=
nullptr);
1048 ASSERT(first_ !=
nullptr && last_ !=
nullptr);
1058 return e->Function();
1063 ASSERT(first_ !=
nullptr);
1065 first_ = first_->
next();
1066 if (first_ ==
nullptr) {
1074 while (
p !=
nullptr) {
1075 if (
p->function() == obj.
ptr()) {
1088 ASSERT((first_ ==
nullptr) && (last_ ==
nullptr));
1101 : background_compiler_(background_compiler) {}
1105 virtual void Run() { background_compiler_->
Run(); }
1113 : isolate_group_(isolate_group),
1118 disabled_depth_(0) {}
1122 delete function_queue_;
1143 if (element !=
nullptr) {
1151 FLAG_stress_test_background_compilation) {
1185 if (disabled_depth_ > 0)
return false;
1186 if (!running_ && done_) {
1214void BackgroundCompiler::Stop() {
1220 StopLocked(thread, &ml);
1223void BackgroundCompiler::StopLocked(Thread* thread,
1224 SafepointMonitorLocker* locker) {
1226 function_queue_->
Clear();
1232void BackgroundCompiler::Enable() {
1234 ASSERT(!thread->BypassSafepoints());
1235 ASSERT(thread->CanAcquireSafepointLocks());
1237 SafepointMonitorLocker ml(&monitor_);
1239 if (disabled_depth_ < 0) {
1240 FATAL(
"Mismatched number of calls to BackgroundCompiler::Enable/Disable.");
1244void BackgroundCompiler::Disable() {
1246 ASSERT(!thread->BypassSafepoints());
1247 ASSERT(thread->CanAcquireSafepointLocks());
1249 SafepointMonitorLocker ml(&monitor_);
1252 StopLocked(thread, &ml);
1264 const Function&
function = Function::CheckedHandle(zone, arguments.ArgAt(0));
1265 FATAL(
"Precompilation missed function %s (%s, %s)\n",
1266 function.ToLibNamePrefixedQualifiedCString(),
1281 FATAL(
"Attempt to compile function %s",
function.ToCString());
1287 FATAL(
"Attempt to compile function %s",
function.ToCString());
1294 FATAL(
"Attempt to compile function %s",
function.ToCString());
1303 FATAL(
"Attempt to compile class %s", cls.ToCString());
1320void BackgroundCompiler::Stop() {
1324void BackgroundCompiler::Enable() {
1328void BackgroundCompiler::Disable() {
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
#define DEBUG_ASSERT(cond)
#define RELEASE_ASSERT(cond)
ObjectPtr At(intptr_t index) const
void Add(QueueElement *value)
BackgroundCompilationQueue()
virtual ~BackgroundCompilationQueue()
void VisitObjectPointers(ObjectPointerVisitor *visitor)
QueueElement * Peek() const
bool ContainsObj(const Object &obj) const
FunctionPtr PeekFunction() const
BackgroundCompilerTask(BackgroundCompiler *background_compiler)
virtual ~BackgroundCompilerTask()
void VisitPointers(ObjectPointerVisitor *visitor)
BackgroundCompiler(IsolateGroup *isolate_group)
bool EnqueueCompilation(const Function &function)
BackgroundCompilationQueue * function_queue() const
virtual ~BackgroundCompiler()
static void AssignEdgeWeights(FlowGraph *flow_graph)
void RegisterDependencies(const Code &code) const
bool is_finalized() const
ArrayPtr current_functions() const
static void NotifyCodeObservers(const Code &code, bool optimized)
static CodePtr FinalizeCode(FlowGraphCompiler *compiler, compiler::Assembler *assembler, PoolAttachment pool_attachment, bool optimized, CodeStatistics *stats)
virtual FlowGraph * BuildFlowGraph(Zone *zone, ParsedFunction *parsed_function, ZoneGrowableArray< const ICData * > *ic_data_array, intptr_t osr_id, bool optimized)=0
virtual void ParseFunction(ParsedFunction *parsed_function)=0
static CompilationPipeline * New(Zone *zone, const Function &function)
CompileParsedFunctionHelper(ParsedFunction *parsed_function, bool optimized, intptr_t osr_id)
CodePtr Compile(CompilationPipeline *pipeline)
static void GenerateCode(CompilerPassState *state)
static DART_WARN_UNUSED_RESULT FlowGraph * RunPipeline(PipelineMode mode, CompilerPassState *state, bool compute_ssa=true)
void set_function(const Function &function)
static bool ShouldTrace()
static CompilerState & Current()
static bool IsBackgroundCompilation()
static bool CanOptimizeFunction(Thread *thread, const Function &function)
static constexpr intptr_t kNoOSRDeoptId
static ErrorPtr EnsureUnoptimizedCode(Thread *thread, const Function &function)
static ObjectPtr CompileFunction(Thread *thread, const Function &function)
static ObjectPtr CompileOptimizedFunction(Thread *thread, const Function &function, intptr_t osr_id=kNoOSRDeoptId)
static ErrorPtr CompileAllFunctions(const Class &cls)
static void ComputeLocalVarDescriptors(const Code &code)
static void AbortBackgroundCompilation(intptr_t deopt_id, const char *msg)
void ParseFunction(ParsedFunction *parsed_function) override
FlowGraph * BuildFlowGraph(Zone *zone, ParsedFunction *parsed_function, ZoneGrowableArray< const ICData * > *ic_data_array, intptr_t osr_id, bool optimized) override
static ThreadPool * thread_pool()
static void DisassembleCode(const Function &function, const Code &code, bool optimized)
static void PrintGraph(const char *phase, FlowGraph *flow_graph)
static bool ShouldPrint(const Function &function, uint8_t **compiler_pass_filter=nullptr)
static void PrintICData(const ICData &ic_data, intptr_t num_checks_to_print=kPrintAll)
static constexpr CompilationMode CompilationModeFrom(bool is_optimizing)
bool should_reorder_blocks() const
static const char * KindToCString(UntaggedFunction::Kind kind)
bool IsDebugging(Thread *thread, const Function &function)
void NotifyCompilation(const Function &func)
void ParseFunction(ParsedFunction *parsed_function) override
FlowGraph * BuildFlowGraph(Zone *zone, ParsedFunction *parsed_function, ZoneGrowableArray< const ICData * > *ic_data_array, intptr_t osr_id, bool optimized) override
GroupDebugger * debugger() const
intptr_t optimization_counter_threshold() const
static IsolateGroup * Current()
void RunWithStoppedMutators(T single_current_mutator, S otherwise, bool use_force_growth_in_otherwise=false)
LocalVarDescriptorsPtr GetVarDescriptors(const Function &func, ZoneGrowableArray< intptr_t > *context_level_array)
DART_NORETURN void Jump(int value, const Error &error)
void VisitPointer(ObjectPtr *p)
static Object & ZoneHandle()
void SetRegExpCompileData(RegExpCompileData *regexp_compile_data)
const Function & function() const
LocalScope * scope() const
void AllocateIrregexpVariables(intptr_t num_stack_locals)
RegExpCompileData * regexp_compile_data() const
void set_next(QueueElement *elem)
ObjectPtr function() const
ObjectPtr * function_untag()
QueueElement(const Function &function)
QueueElement * next() const
FunctionPtr Function() const
static CompilationResult CompileIR(RegExpCompileData *input, const ParsedFunction *parsed_function, const ZoneGrowableArray< const ICData * > &ic_data_array, intptr_t osr_id)
static void ParseRegExp(const String &input, RegExpFlags regexp_flags, RegExpCompileData *result)
void set_is_simple() const
StringPtr pattern() const
void set_is_complex() const
void set_num_bracket_expressions(SmiPtr value) const
void set_capture_name_map(const Array &array) const
RegExpFlags flags() const
static DART_NORETURN void LongJump(const Error &error)
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
LongJumpScope * long_jump_base() const
bool CanAcquireSafepointLocks() const
static Thread * Current()
DART_WARN_UNUSED_RESULT ErrorPtr StealStickyError()
CompilerState & compiler_state()
void set_sticky_error(const Error &value)
static void ExitIsolateGroupAsHelper(bool bypass_safepoint)
bool IsDartMutatorThread() const
Isolate * isolate() const
bool BypassSafepoints() const
IsolateGroup * isolate_group() const
static bool EnterIsolateGroupAsHelper(IsolateGroup *isolate_group, TaskKind kind, bool bypass_safepoint)
int64_t TotalElapsedTime() const
#define THR_Print(format,...)
const uint8_t uint32_t uint32_t GError ** error
Dart_NativeFunction function
#define HANDLESCOPE(thread)
void SetFfiCallbackCode(Thread *thread, const Function &ffi_trampoline, const Code &code)
static void PrecompilationModeHandler(bool value)
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
DirectChainedHashMap< FieldKeyValueTrait > FieldSet
DEFINE_FLAG_HANDLER(PrecompilationModeHandler, precompilation, "Precompilation mode")
DEFINE_RUNTIME_ENTRY(CompileFunction, 1)
const char *const function_name
static ObjectPtr CompileFunctionHelper(CompilationPipeline *pipeline, const Function &function, volatile bool optimized, intptr_t osr_id)
DECLARE_FLAG(bool, show_invisible_frames)
bool EMSCRIPTEN_KEEPALIVE IsEmpty(const SkPath &path)
CallSpecializer * call_specializer
GrowableArray< TokenPosition > inline_id_to_token_pos
GrowableArray< intptr_t > caller_inline_id
GrowableArray< const Function * > inline_id_to_function
FlowGraphCompiler * graph_compiler
#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function)
#define TIMELINE_DURATION(thread, stream, name)