| Index: runtime/vm/code_generator.cc
|
| diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
|
| index 8eee03d0c66b665d7023c44ceab630f4157825ad..0266e1b675377d7ab0c8f21c17ff0be7314316b5 100644
|
| --- a/runtime/vm/code_generator.cc
|
| +++ b/runtime/vm/code_generator.cc
|
| @@ -60,7 +60,14 @@ DECLARE_FLAG(bool, report_usage_count);
|
| DEFINE_FLAG(bool, use_osr, true, "Use on-stack replacement.");
|
| DEFINE_FLAG(bool, trace_osr, false, "Trace attempts at on-stack replacement.");
|
|
|
| -DECLARE_FLAG(charp, deoptimize_filter);
|
| +DEFINE_FLAG(int, stacktrace_every, 0,
|
| + "Compute debugger stacktrace on every N stack overflow checks");
|
| +DEFINE_FLAG(charp, stacktrace_filter, NULL,
|
| + "Compute stacktrace in named function on stack overflow checks");
|
| +DEFINE_FLAG(int, deoptimize_every, 0,
|
| + "Deoptimize on every N stack overflow checks");
|
| +DEFINE_FLAG(charp, deoptimize_filter, NULL,
|
| + "Deoptimize in named function on stack overflow checks");
|
|
|
|
|
| DEFINE_RUNTIME_ENTRY(TraceFunctionEntry, 1) {
|
| @@ -1022,9 +1029,14 @@ DEFINE_RUNTIME_ENTRY(StackOverflow, 0) {
|
| #else
|
| uword stack_pos = reinterpret_cast<uword>(&arguments);
|
| #endif
|
| + // Always clear the stack overflow flags. They are meant for this
|
| + // particular stack overflow runtime call and are not meant to
|
| + // persist.
|
| + uword stack_overflow_flags = isolate->GetAndClearStackOverflowFlags();
|
|
|
| // If an interrupt happens at the same time as a stack overflow, we
|
| - // process the stack overflow first.
|
| + // process the stack overflow now and leave the interrupt for next
|
| + // time.
|
| if (stack_pos < isolate->saved_stack_limit()) {
|
| // Use the preallocated stack overflow exception to avoid calling
|
| // into dart code.
|
| @@ -1035,16 +1047,16 @@ DEFINE_RUNTIME_ENTRY(StackOverflow, 0) {
|
| }
|
|
|
| uword interrupt_bits = isolate->GetAndClearInterrupts();
|
| - if (interrupt_bits & Isolate::kStoreBufferInterrupt) {
|
| + if ((interrupt_bits & Isolate::kStoreBufferInterrupt) != 0) {
|
| if (FLAG_verbose_gc) {
|
| OS::PrintErr("Scavenge scheduled by store buffer overflow.\n");
|
| }
|
| isolate->heap()->CollectGarbage(Heap::kNew);
|
| }
|
| - if (interrupt_bits & Isolate::kMessageInterrupt) {
|
| + if ((interrupt_bits & Isolate::kMessageInterrupt) != 0) {
|
| isolate->message_handler()->HandleOOBMessages();
|
| }
|
| - if (interrupt_bits & Isolate::kApiInterrupt) {
|
| + if ((interrupt_bits & Isolate::kApiInterrupt) != 0) {
|
| // Signal isolate interrupt event.
|
| Debugger::SignalIsolateInterrupted();
|
|
|
| @@ -1058,14 +1070,15 @@ DEFINE_RUNTIME_ENTRY(StackOverflow, 0) {
|
| }
|
| }
|
| }
|
| - if (interrupt_bits & Isolate::kVmStatusInterrupt) {
|
| + if ((interrupt_bits & Isolate::kVmStatusInterrupt) != 0) {
|
| Dart_IsolateInterruptCallback callback = isolate->VmStatsCallback();
|
| if (callback) {
|
| (*callback)();
|
| }
|
| }
|
|
|
| - if (FLAG_use_osr && (interrupt_bits == 0)) {
|
| + if ((stack_overflow_flags & Isolate::kOsrRequest) != 0) {
|
| + ASSERT(FLAG_use_osr);
|
| DartFrameIterator iterator;
|
| StackFrame* frame = iterator.NextFrame();
|
| ASSERT(frame != NULL);
|
| @@ -1112,24 +1125,65 @@ DEFINE_RUNTIME_ENTRY(StackOverflow, 0) {
|
| }
|
| }
|
|
|
| - if (FLAG_deoptimize_filter != NULL) {
|
| + // The following code is used to stress test deoptimization and
|
| + // debugger stack tracing.
|
| + bool do_deopt = false;
|
| + bool do_stacktrace = false;
|
| + if (FLAG_deoptimize_every > 0 ||
|
| + FLAG_stacktrace_every > 0) {
|
| + // TODO(turnidge): To make --deoptimize_every and
|
| + // --stacktrace-every faster we could move this increment/test to
|
| + // the generated code.
|
| + int32_t count = isolate->IncrementAndGetStackOverflowCount();
|
| + if (FLAG_deoptimize_every > 0 &&
|
| + (count % FLAG_deoptimize_every) == 0) {
|
| + do_deopt = true;
|
| + }
|
| + if (FLAG_stacktrace_every > 0 &&
|
| + (count % FLAG_stacktrace_every) == 0) {
|
| + do_stacktrace = true;
|
| + }
|
| + }
|
| + if (FLAG_deoptimize_filter != NULL ||
|
| + FLAG_stacktrace_filter != NULL) {
|
| DartFrameIterator iterator;
|
| StackFrame* frame = iterator.NextFrame();
|
| ASSERT(frame != NULL);
|
| const Code& code = Code::Handle(frame->LookupDartCode());
|
| ASSERT(!code.IsNull());
|
| - if (code.is_optimized()) {
|
| - const Function& function = Function::Handle(code.function());
|
| - ASSERT(!function.IsNull());
|
| - if (strstr(function.ToFullyQualifiedCString(),
|
| - FLAG_deoptimize_filter) != NULL) {
|
| - if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
|
| - OS::PrintErr("*** Forcing deoptimization (%s)\n",
|
| - function.ToFullyQualifiedCString());
|
| - // TODO(turnidge): Consider changing to DeoptimizeAt for
|
| - // just the top frame.
|
| - DeoptimizeAll();
|
| - }
|
| + const Function& function = Function::Handle(code.function());
|
| + ASSERT(!function.IsNull());
|
| + const char* function_name = function.ToFullyQualifiedCString();
|
| + ASSERT(function_name != NULL);
|
| + if (code.is_optimized() &&
|
| + FLAG_deoptimize_filter != NULL &&
|
| + strstr(function_name, FLAG_deoptimize_filter) != NULL) {
|
| + OS::PrintErr("*** Forcing deoptimization (%s)\n",
|
| + function.ToFullyQualifiedCString());
|
| + do_deopt = true;
|
| + }
|
| + if (FLAG_stacktrace_filter != NULL &&
|
| + strstr(function_name, FLAG_stacktrace_filter) != NULL) {
|
| + OS::PrintErr("*** Computing stacktrace (%s)\n",
|
| + function.ToFullyQualifiedCString());
|
| + do_stacktrace = true;
|
| + }
|
| + }
|
| + if (do_deopt) {
|
| + // TODO(turnidge): Consider using DeoptimizeAt instead.
|
| + DeoptimizeAll();
|
| + }
|
| + if (do_stacktrace) {
|
| + String& var_name = String::Handle();
|
| + Instance& var_value = Instance::Handle();
|
| + DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
|
| + intptr_t num_frames = stack->Length();
|
| + for (intptr_t i = 0; i < num_frames; i++) {
|
| + ActivationFrame* frame = stack->FrameAt(i);
|
| + const int num_vars = frame->NumLocalVariables();
|
| + intptr_t unused;
|
| + for (intptr_t v = 0; v < num_vars; v++) {
|
| + frame->VariableAt(v, &var_name, &unused, &unused, &var_value);
|
| }
|
| }
|
| }
|
|
|