From b29829660bcdee7eb394e6fd4635ff7a6a77ef01 Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Wed, 15 Feb 2017 14:17:29 +0100 Subject: [PATCH] Enable causal stacktrace in kernel R=kustermann@google.com Review-Url: https://codereview.chromium.org/2690873005 . --- .../lib/transformations/continuation.dart | 15 ++++++ runtime/vm/kernel_to_il.cc | 53 ++++++++++++++++++- tests/language/language_kernel.status | 5 +- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/pkg/kernel/lib/transformations/continuation.dart b/pkg/kernel/lib/transformations/continuation.dart index 112ea43b827..65d492e2d6a 100644 --- a/pkg/kernel/lib/transformations/continuation.dart +++ b/pkg/kernel/lib/transformations/continuation.dart @@ -198,6 +198,8 @@ abstract class AsyncRewriterBase extends ContinuationRewriterBase { new VariableDeclaration(":async_op_then"); final VariableDeclaration catchErrorContinuationVariable = new VariableDeclaration(":async_op_error"); + final VariableDeclaration asyncStackTrace = + new VariableDeclaration(":async_stack_trace"); LabeledStatement labeledBody; @@ -215,6 +217,9 @@ abstract class AsyncRewriterBase extends ContinuationRewriterBase { // var :async_op_error; statements.add(catchErrorContinuationVariable); + // var :async_stack_trace; + statements.add(asyncStackTrace); + // :async_op([:result, :exception, :stack_trace]) { // modified ; // } @@ -258,6 +263,13 @@ abstract class AsyncRewriterBase extends ContinuationRewriterBase { new VariableSet( catchErrorContinuationVariable, boundCatchErrorClosure)); statements.add(catchErrorClosureVariableAssign); + + // :async_stack_trace = _asyncStackTraceHelper(); + final boundAsyncStackTrace = new StaticInvocation( + helper.asyncStackTraceHelper, new Arguments.empty()); + final asyncStackTraceVariableAssign = new ExpressionStatement( + new VariableSet(asyncStackTrace, boundAsyncStackTrace)); + statements.add(asyncStackTraceVariableAssign); } Statement buildWrappedBody() { @@ -874,6 +886,7 @@ class HelperNodes { final Constructor streamIteratorConstructor; final Procedure asyncThenWrapper; final Procedure asyncErrorWrapper; + final Procedure asyncStackTraceHelper; final Procedure awaitHelper; final CoreTypes coreTypes; @@ -891,6 +904,7 @@ class HelperNodes { this.streamControllerConstructor, this.asyncThenWrapper, this.asyncErrorWrapper, + this.asyncStackTraceHelper, this.awaitHelper, this.coreTypes); @@ -973,6 +987,7 @@ class HelperNodes { findConstructor(streamControllerClass, ''), findProcedure(asyncLibrary, '_asyncThenWrapperHelper'), findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'), + findProcedure(asyncLibrary, '_asyncStackTraceHelper'), findProcedure(asyncLibrary, '_awaitHelper'), new CoreTypes(program)); } diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc index 984de1d4aea..fd383f817ff 100644 --- a/runtime/vm/kernel_to_il.cc +++ b/runtime/vm/kernel_to_il.cc @@ -720,6 +720,15 @@ void ScopeBuilder::VisitFunctionNode(FunctionNode* node) { scope_->CaptureVariable(temp); } } + if (FLAG_causal_async_stacks) { + // TODO(28777): Either remove the variable here, or update the dart side + // so we don't always generate it if this flag is not set. + LocalVariable* temp = + scope_->LookupVariable(Symbols::AsyncStackTraceVar(), true); + if (temp != NULL) { + scope_->CaptureVariable(temp); + } + } } } @@ -2555,6 +2564,17 @@ Fragment FlowGraphBuilder::Return(TokenPosition position) { new (Z) DebugStepCheckInstr(position, RawPcDescriptors::kRuntimeCall); } + if (FLAG_causal_async_stacks && + function.name() == Symbols::AsyncOperation().raw()) { + // We are returning from an asynchronous closure. Before we do that, be + // sure to clear the thread's asynchronous stack trace. + const Function& target = Function::ZoneHandle( + Z, I->object_store()->async_clear_thread_stack_trace()); + ASSERT(!target.IsNull()); + instructions += StaticCall(TokenPosition::kNoSource, target, 0); + instructions += Drop(); + } + ReturnInstr* return_instr = new (Z) ReturnInstr(position, value); if (exit_collector_ != NULL) exit_collector_->AddExit(return_instr); @@ -3171,7 +3191,7 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function, // The code we are building will be executed right after we enter // the function and before any nested contexts are allocated. // Reset current context_depth_ to match this. - intptr_t current_context_depth = context_depth_; + const intptr_t current_context_depth = context_depth_; context_depth_ = scopes_->yield_jump_variable->owner()->context_level(); // Prepend an entry corresponding to normal entry to the function. @@ -3237,6 +3257,37 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function, context_depth_ = current_context_depth; } + if (FLAG_causal_async_stacks && + dart_function.name() == Symbols::AsyncOperation().raw()) { + // The code we are building will be executed right after we enter + // the function and before any nested contexts are allocated. + // Reset current context_depth_ to match this. + const intptr_t current_context_depth = context_depth_; + context_depth_ = scopes_->yield_jump_variable->owner()->context_level(); + + Fragment instructions; + LocalScope* scope = parsed_function_->node_sequence()->scope(); + + const Function& target = Function::ZoneHandle( + Z, I->object_store()->async_set_thread_stack_trace()); + ASSERT(!target.IsNull()); + + // Fetch and load :async_stack_trace + LocalVariable* async_stack_trace_var = + scope->LookupVariable(Symbols::AsyncStackTraceVar(), false); + ASSERT((async_stack_trace_var != NULL) && + async_stack_trace_var->is_captured()); + instructions += LoadLocal(async_stack_trace_var); + instructions += PushArgument(); + + // Call _asyncSetThreadStackTrace + instructions += StaticCall(TokenPosition::kNoSource, target, 1); + instructions += Drop(); + + body = instructions + body; + context_depth_ = current_context_depth; + } + if (FLAG_support_debugger && function->position().IsDebugPause() && !dart_function.is_native() && dart_function.is_debuggable()) { // If a switch was added above: Start the switch by injecting a debugable diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status index 90433a90492..4726c9f9a76 100644 --- a/tests/language/language_kernel.status +++ b/tests/language/language_kernel.status @@ -44,7 +44,7 @@ vm/debug_break_enabled_vm_test/01: CompileTimeError vm/debug_break_enabled_vm_test/none: CompileTimeError vm/reflect_core_vm_test: CompileTimeError vm/regress_27201_test: CompileTimeError -vm/regress_28325_test: RuntimeError # Issue 28055. +# vm/regress_28325_test: RuntimeError # Issue 28055. Passes by mistake. # dartk: JIT failures [ $compiler == dartk && $runtime == vm ] @@ -203,9 +203,8 @@ library_env_test/has_no_mirror_support: RuntimeError main_not_a_function_test/01: Crash redirecting_factory_reflection_test: RuntimeError -# Casual async stack traces are not implemented for Kernel. +# Casual async stack traces does not give exactly same stacktrace on kernel vm/causal_async_exception_stack_test: RuntimeError -vm/causal_async_exception_stack2_test: RuntimeError # dartk: JIT failures (debug) [ $compiler == dartk && $runtime == vm && $mode == debug ]