Files
sdk/runtime/vm/method_recognizer.cc
T
John McCutchan a0ee5b24db Track async causal stack traces
This CL improves the stack traces that accompany exceptions. Whenever an
async function is entered, we remember how we got there. This is similar
in spirit to package:stack_trace but the implementation is more efficient
and memory usage can be more easily reasoned about.

Tracking causal stack traces:

- [x] Upon entry to an async function, capture the synchronous stack trace prefix and store it into the closure.
- [x] Upon entry to an async* function, capture the synchronous stack trace prefix and store it into the closure.
- [x] Before returning from an async function, clear the Thread's asynchronous stack trace.
- [x] After resuming an async function, load the sychronous stack trace prefix into the Thread.
- [x] Filter stack traces to remove async machinery.

Service protocol changes:

- [x] Send causal async stack trace.

Observatory changes:

- [x] Display causal async stack trace below async functions.

Fixes https://github.com/dart-lang/sdk/issues/27661

R=asiva@google.com, rmacnak@google.com

Comparisons: https://docs.google.com/a/google.com/document/d/10r6jEqr8OCiDZ4y9SYU_uOimcHiOGAZMly2ghTErALI/edit?usp=sharing
Review-Url: https://codereview.chromium.org/2646443005 .
2017-02-09 15:39:44 -08:00

190 lines
6.1 KiB
C++

// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/method_recognizer.h"
#include "vm/object.h"
#include "vm/symbols.h"
namespace dart {
MethodRecognizer::Kind MethodRecognizer::RecognizeKind(
const Function& function) {
return function.recognized_kind();
}
bool MethodRecognizer::AlwaysInline(const Function& function) {
return function.always_inline();
}
bool MethodRecognizer::PolymorphicTarget(const Function& function) {
return function.is_polymorphic_target();
}
intptr_t MethodRecognizer::ResultCid(const Function& function) {
switch (function.recognized_kind()) {
#define DEFINE_CASE(cname, fname, ename, result_type, fingerprint) \
case k##ename: \
return k##result_type##Cid;
RECOGNIZED_LIST(DEFINE_CASE)
#undef DEFINE_CASE
default:
return kDynamicCid;
}
}
intptr_t MethodRecognizer::MethodKindToReceiverCid(Kind kind) {
switch (kind) {
case kImmutableArrayGetIndexed:
return kImmutableArrayCid;
case kObjectArrayGetIndexed:
case kObjectArraySetIndexed:
return kArrayCid;
case kGrowableArrayGetIndexed:
case kGrowableArraySetIndexed:
return kGrowableObjectArrayCid;
case kFloat32ArrayGetIndexed:
case kFloat32ArraySetIndexed:
return kTypedDataFloat32ArrayCid;
case kFloat64ArrayGetIndexed:
case kFloat64ArraySetIndexed:
return kTypedDataFloat64ArrayCid;
case kInt8ArrayGetIndexed:
case kInt8ArraySetIndexed:
return kTypedDataInt8ArrayCid;
case kUint8ArrayGetIndexed:
case kUint8ArraySetIndexed:
return kTypedDataUint8ArrayCid;
case kUint8ClampedArrayGetIndexed:
case kUint8ClampedArraySetIndexed:
return kTypedDataUint8ClampedArrayCid;
case kExternalUint8ArrayGetIndexed:
case kExternalUint8ArraySetIndexed:
return kExternalTypedDataUint8ArrayCid;
case kExternalUint8ClampedArrayGetIndexed:
case kExternalUint8ClampedArraySetIndexed:
return kExternalTypedDataUint8ClampedArrayCid;
case kInt16ArrayGetIndexed:
case kInt16ArraySetIndexed:
return kTypedDataInt16ArrayCid;
case kUint16ArrayGetIndexed:
case kUint16ArraySetIndexed:
return kTypedDataUint16ArrayCid;
case kInt32ArrayGetIndexed:
case kInt32ArraySetIndexed:
return kTypedDataInt32ArrayCid;
case kUint32ArrayGetIndexed:
case kUint32ArraySetIndexed:
return kTypedDataUint32ArrayCid;
case kInt64ArrayGetIndexed:
case kInt64ArraySetIndexed:
return kTypedDataInt64ArrayCid;
case kFloat32x4ArrayGetIndexed:
case kFloat32x4ArraySetIndexed:
return kTypedDataFloat32x4ArrayCid;
case kInt32x4ArrayGetIndexed:
case kInt32x4ArraySetIndexed:
return kTypedDataInt32x4ArrayCid;
case kFloat64x2ArrayGetIndexed:
case kFloat64x2ArraySetIndexed:
return kTypedDataFloat64x2ArrayCid;
default:
break;
}
UNREACHABLE();
return kIllegalCid;
}
#define KIND_TO_STRING(class_name, function_name, enum_name, type, fp) \
#enum_name,
static const char* recognized_list_method_name[] = {
"Unknown", RECOGNIZED_LIST(KIND_TO_STRING)};
#undef KIND_TO_STRING
const char* MethodRecognizer::KindToCString(Kind kind) {
if (kind > kUnknown && kind < kNumRecognizedMethods)
return recognized_list_method_name[kind];
return "?";
}
#if !defined(DART_PRECOMPILED_RUNTIME)
void MethodRecognizer::InitializeState() {
GrowableArray<Library*> libs(3);
libs.Add(&Library::ZoneHandle(Library::CoreLibrary()));
libs.Add(&Library::ZoneHandle(Library::CollectionLibrary()));
libs.Add(&Library::ZoneHandle(Library::MathLibrary()));
libs.Add(&Library::ZoneHandle(Library::TypedDataLibrary()));
libs.Add(&Library::ZoneHandle(Library::InternalLibrary()));
libs.Add(&Library::ZoneHandle(Library::DeveloperLibrary()));
libs.Add(&Library::ZoneHandle(Library::AsyncLibrary()));
Function& func = Function::Handle();
#define SET_RECOGNIZED_KIND(class_name, function_name, enum_name, type, fp) \
func = Library::GetFunction(libs, #class_name, #function_name); \
if (func.IsNull()) { \
OS::PrintErr("Missing %s::%s\n", #class_name, #function_name); \
UNREACHABLE(); \
} \
CHECK_FINGERPRINT3(func, class_name, function_name, enum_name, fp); \
func.set_recognized_kind(k##enum_name);
RECOGNIZED_LIST(SET_RECOGNIZED_KIND);
#define SET_FUNCTION_BIT(class_name, function_name, dest, fp, setter, value) \
func = Library::GetFunction(libs, #class_name, #function_name); \
if (func.IsNull()) { \
OS::PrintErr("Missing %s::%s\n", #class_name, #function_name); \
UNREACHABLE(); \
} \
CHECK_FINGERPRINT3(func, class_name, function_name, dest, fp); \
func.setter(value);
#define SET_IS_ALWAYS_INLINE(class_name, function_name, dest, fp) \
SET_FUNCTION_BIT(class_name, function_name, dest, fp, set_always_inline, true)
#define SET_IS_NEVER_INLINE(class_name, function_name, dest, fp) \
SET_FUNCTION_BIT(class_name, function_name, dest, fp, set_is_inlinable, false)
#define SET_IS_POLYMORPHIC_TARGET(class_name, function_name, dest, fp) \
SET_FUNCTION_BIT(class_name, function_name, dest, fp, \
set_is_polymorphic_target, true)
INLINE_WHITE_LIST(SET_IS_ALWAYS_INLINE);
INLINE_BLACK_LIST(SET_IS_NEVER_INLINE);
POLYMORPHIC_TARGET_LIST(SET_IS_POLYMORPHIC_TARGET);
#undef SET_RECOGNIZED_KIND
#undef SET_IS_ALWAYS_INLINE
#undef SET_IS_POLYMORPHIC_TARGET
#undef SET_FUNCTION_BIT
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
} // namespace dart