Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(829)

Unified Diff: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart

Issue 2869463002: Better stack trace support (Closed)
Patch Set: Address comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
index 8e8a2cd130b78152f2ee78e6406ea2a16a3590eb..e3492c26da036582534094cd962c29c00c9ee084 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart
@@ -617,37 +617,70 @@ assert_(condition, [message]) => JS(
if (!$condition) $throwAssertionError(message);
})()''');
-var _stack = null;
-@JSExportName('throw')
-throw_(obj) => JS(
- '',
- '''(() => {
- $_stack = new Error();
- throw $obj;
-})()''');
+/// Store a JS error for an exception. For non-primitives, we store as an
+/// expando. For primitive, we use a side cache. To limit memory leakage, we
+/// only keep the last [_maxTraceCache] entries.
+final _error = JS('', 'Symbol("_error")');
+Map _primitiveErrorCache;
+const _maxErrorCache = 10;
+
+bool _isJsError(exception) {
+ return JS('bool', '#.Error != null && # instanceof #.Error', global_,
+ exception, global_);
+}
-getError(exception) => JS(
- '',
- '''(() => {
- var stack = $_stack;
- return stack !== null ? stack : $exception;
-})()''');
+// Record/return the JS error for an exception. If an error was already
+// recorded, prefer that to [newError].
+recordJsError(exception, [newError]) {
+ if (_isJsError(exception)) return exception;
+
+ var useExpando =
+ exception != null && JS('bool', 'typeof # == "object"', exception);
+ var error;
+ if (useExpando) {
+ error = JS('', '#[#]', exception, _error);
+ } else {
+ if (_primitiveErrorCache == null) _primitiveErrorCache = {};
+ error = _primitiveErrorCache[exception];
+ }
+ if (error != null) return error;
+ if (newError != null) {
+ error = newError;
+ } else {
+ // We should only hit this path when a non-Error was thrown from JS. In
+ // case, there is no stack trace on the exception, so we create one:
+ error = JS('', 'new Error()');
+ }
+ if (useExpando) {
+ JS('', '#[#] = #', exception, _error, error);
+ } else {
+ _primitiveErrorCache[exception] = error;
+ if (_primitiveErrorCache.length > _maxErrorCache) {
+ _primitiveErrorCache.remove(_primitiveErrorCache.keys.first);
+ }
+ }
+ return error;
+}
+
+@JSExportName('throw')
+throw_(obj) {
+ // Note, we create the error here to avoid the extra frame.
+ // package:stack_trace and tests appear to assume this. We could fix use
+ // cases instead, but we're already on the exceptional path here.
+ recordJsError(obj, JS('', 'new Error()'));
+ JS('', 'throw #', obj);
+}
// This is a utility function: it is only intended to be called from dev
// tools.
-stackPrint(exception) => JS(
- '',
- '''(() => {
- var error = $getError($exception);
- console.log(error.stack ? error.stack : 'No stack trace for: ' + error);
-})()''');
+stackPrint(exception) {
+ var error = recordJsError(exception);
+ JS('', 'console.log(#.stack ? #.stack : "No stack trace for: " + #)', error,
+ error, error);
+}
-stackTrace(exception) => JS(
- '',
- '''(() => {
- var error = $getError($exception);
- return $getTraceFromException(error);
-})()''');
+// Forward to dart:_js_helper to create a _StackTrace object.
+stackTrace(exception) => getTraceFromException(exception);
///
/// Implements a sequence of .? operations.

Powered by Google App Engine
This is Rietveld 408576698