From ae121690eb89a03d23e7faa2a93081437ae0ff05 Mon Sep 17 00:00:00 2001 From: Alex Dvornikov Date: Tue, 18 Dec 2018 15:56:39 -0800 Subject: [PATCH] Update JSStackTrace to support segment ids Reviewed By: jeanlauliac Differential Revision: D13504222 fbshipit-source-id: ffda11697838ea03d15a28704d401e1051058b49 --- .../com/facebook/react/util/JSStackTrace.java | 20 +++++----- .../test/java/com/facebook/react/util/BUCK | 19 +++++++++ .../facebook/react/util/JSStackTraceTest.java | 40 +++++++++++++++++++ 3 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 ReactAndroid/src/test/java/com/facebook/react/util/BUCK create mode 100644 ReactAndroid/src/test/java/com/facebook/react/util/JSStackTraceTest.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/util/JSStackTrace.java b/ReactAndroid/src/main/java/com/facebook/react/util/JSStackTrace.java index 2e1dfa2d1..a80101533 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/util/JSStackTrace.java +++ b/ReactAndroid/src/main/java/com/facebook/react/util/JSStackTrace.java @@ -15,7 +15,7 @@ import com.facebook.react.bridge.ReadableType; public class JSStackTrace { - final private static Pattern mJsModuleIdPattern = Pattern.compile("(?:^|[/\\\\])(\\d+\\.js)$"); + private static final Pattern FILE_ID_PATTERN = Pattern.compile("\\b((?:seg-\\d+(?:_\\d+)?|\\d+)\\.js)"); public static String format(String message, ReadableArray stack) { StringBuilder stringBuilder = new StringBuilder(message).append(", stack:\n"); @@ -24,7 +24,7 @@ public class JSStackTrace { stringBuilder .append(frame.getString("methodName")) .append("@") - .append(stackFrameToModuleId(frame)) + .append(parseFileId(frame)) .append(frame.getInt("lineNumber")); if (frame.hasKey("column") && !frame.isNull("column") && @@ -38,16 +38,18 @@ public class JSStackTrace { return stringBuilder.toString(); } - // If the file name of a stack frame is numeric (+ ".js"), we assume it's a lazily injected module - // coming from a "random access bundle". We are using special source maps for these bundles, so - // that we can symbolicate stack traces for multiple injected files with a single source map. - // We have to include the module id in the stack for that, though. The ".js" suffix is kept to - // avoid ambiguities between "module-id:line" and "line:column". - private static String stackFrameToModuleId(ReadableMap frame) { + // Besides a regular bundle (e.g. "bundle.js"), a stack frame can be produced by: + // 1) "random access bundle (RAM)", e.g. "1.js", where "1" is a module name + // 2) "segment file", e.g. "seg-1.js", where "1" is a segment name + // 3) "RAM segment file", e.g. "seg-1_2.js", where "1" is a segment name and "2" is a module name + // We are using a special source map format for such cases, so that we could symbolicate + // stack traces with a single source map file. + // NOTE: The ".js" suffix is kept to avoid ambiguities between "module-id:line" and "line:column". + private static String parseFileId(ReadableMap frame) { if (frame.hasKey("file") && !frame.isNull("file") && frame.getType("file") == ReadableType.String) { - final Matcher matcher = mJsModuleIdPattern.matcher(frame.getString("file")); + final Matcher matcher = FILE_ID_PATTERN.matcher(frame.getString("file")); if (matcher.find()) { return matcher.group(1) + ":"; } diff --git a/ReactAndroid/src/test/java/com/facebook/react/util/BUCK b/ReactAndroid/src/test/java/com/facebook/react/util/BUCK new file mode 100644 index 000000000..12a2a521f --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/util/BUCK @@ -0,0 +1,19 @@ +load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_target", "rn_robolectric_test") + +rn_robolectric_test( + name = "util", + srcs = glob(["**/*.java"]), + visibility = [ + "PUBLIC", + ], + deps = [ + react_native_dep("libraries/fbcore/src/test/java/com/facebook/powermock:powermock"), + react_native_dep("third-party/java/fest:fest"), + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_dep("third-party/java/junit:junit"), + react_native_dep("third-party/java/mockito:mockito"), + react_native_dep("third-party/java/robolectric3/robolectric:robolectric"), + react_native_target("java/com/facebook/react/util:util"), + react_native_target("java/com/facebook/react/bridge:bridge"), + ], +) diff --git a/ReactAndroid/src/test/java/com/facebook/react/util/JSStackTraceTest.java b/ReactAndroid/src/test/java/com/facebook/react/util/JSStackTraceTest.java new file mode 100644 index 000000000..d614cee98 --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/util/JSStackTraceTest.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.util; + +import org.junit.Test; +import org.junit.Assert; +import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.JavaOnlyArray; + +public class JSStackTraceTest { + + @Test + public void testSymbolication() { + JavaOnlyArray values = JavaOnlyArray.of( + JavaOnlyMap.of("methodName", "method_from_bundle", "column", 11, "lineNumber", 7, "file", "Fb4aBundle.js"), + JavaOnlyMap.of("methodName", "method_from_ram_bundle", "column", 13, "lineNumber", 18, "file", "199.js"), + JavaOnlyMap.of("methodName", "method_from_ram_bundle_with_address", "column", 13, "lineNumber", 18, "file", "address at 199.js"), + JavaOnlyMap.of("methodName", "method_from_segment", "column", 18, "lineNumber", 9, "file", "seg-1.js"), + JavaOnlyMap.of("methodName", "method_from_segment_with_address", "column", 18, "lineNumber", 9, "file", "address at seg-1.js"), + JavaOnlyMap.of("methodName", "method_from_ram_segment", "column", 20, "lineNumber", 10, "file", "seg-3_198.js"), + JavaOnlyMap.of("methodName", "method_from_ram_segment_with_address", "column", 20, "lineNumber", 10, "file", "address at seg-3_198.js") + ); + String message = JSStackTrace.format("Error", values); + Assert.assertEquals(message, "Error, stack:\n" + + "method_from_bundle@7:11\n" + + "method_from_ram_bundle@199.js:18:13\n" + + "method_from_ram_bundle_with_address@199.js:18:13\n" + + "method_from_segment@seg-1.js:9:18\n" + + "method_from_segment_with_address@seg-1.js:9:18\n" + + "method_from_ram_segment@seg-3_198.js:10:20\n" + + "method_from_ram_segment_with_address@seg-3_198.js:10:20\n" + ); + } + +}