1
+ import { Platform } from 'react-native' ;
2
+
3
+ import { ANDROID_DEFAULT_BUNDLE_NAME , IOS_DEFAULT_BUNDLE_NAME } from '../integrations/rewriteframes' ;
1
4
import { NATIVE } from '../wrapper' ;
2
5
import { convertToSentryProfile } from './convertHermesProfile' ;
3
6
import type { RawThreadCpuProfile } from './types' ;
@@ -28,10 +31,17 @@ export interface Sample {
28
31
}
29
32
30
33
export interface StackFrame {
34
+ // Hermes Bytecode
35
+ funcVirtAddr ?: string ;
36
+ offset ?: string ;
37
+
38
+ // JavaScript
31
39
line ?: string ;
32
40
column ?: string ;
33
41
funcLine ?: string ;
34
42
funcColumn ?: string ;
43
+
44
+ // Common
35
45
name : string ;
36
46
category : string ;
37
47
parent ?: number ;
@@ -43,15 +53,50 @@ export interface Profile {
43
53
stackFrames : Record < string , StackFrame > ;
44
54
}
45
55
56
+ export interface ParsedHermesStackFrame {
57
+ function : string ;
58
+ file ?: string ;
59
+ lineno ?: number ;
60
+ colno ?: number ;
61
+ }
62
+
63
+ const DEFAULT_BUNDLE_NAME =
64
+ Platform . OS === 'android' ? ANDROID_DEFAULT_BUNDLE_NAME : Platform . OS === 'ios' ? IOS_DEFAULT_BUNDLE_NAME : undefined ;
65
+ const ANONYMOUS_FUNCTION_NAME = 'anonymous' ;
66
+
46
67
/**
47
- * Hermes Profile Stack Frame Name contains function name and file path.
48
- *
49
- * `foo(/path/to/file.js:1:2)` -> `foo`
68
+ * Parses Hermes StackFrame to Sentry StackFrame.
69
+ * For native frames only function name is returned, for Hermes bytecode the line and column are calculated.
50
70
*/
51
- export function parseHermesStackFrameFunctionName ( hermesName : string ) : string {
52
- const indexOfLeftParenthesis = hermesName . indexOf ( '(' ) ;
53
- const name = indexOfLeftParenthesis !== - 1 ? hermesName . substring ( 0 , indexOfLeftParenthesis ) : hermesName ;
54
- return name ;
71
+ export function parseHermesJSStackFrame ( frame : StackFrame ) : ParsedHermesStackFrame {
72
+ if ( frame . category !== 'JavaScript' ) {
73
+ // Native
74
+ return { function : frame . name } ;
75
+ }
76
+
77
+ if ( frame . funcVirtAddr !== undefined && frame . offset !== undefined ) {
78
+ // Hermes Bytecode
79
+ return {
80
+ function : frame . name || ANONYMOUS_FUNCTION_NAME ,
81
+ file : DEFAULT_BUNDLE_NAME ,
82
+ // https://github.com/krystofwoldrich/metro/blob/417e6f276ff9422af6039fc4d1bce41fcf7d9f46/packages/metro-symbolicate/src/Symbolication.js#L298-L301
83
+ // Hermes lineno is hardcoded 1, currently only one bundle symbolication is supported by metro-symbolicate and thus by us.
84
+ lineno : 1 ,
85
+ // Hermes colno is 0-based, while Sentry is 1-based
86
+ colno : Number ( frame . funcVirtAddr ) + Number ( frame . offset ) + 1 ,
87
+ } ;
88
+ }
89
+
90
+ // JavaScript
91
+ const indexOfLeftParenthesis = frame . name . indexOf ( '(' ) ;
92
+ return {
93
+ function :
94
+ ( indexOfLeftParenthesis !== - 1 && ( frame . name . substring ( 0 , indexOfLeftParenthesis ) || ANONYMOUS_FUNCTION_NAME ) ) ||
95
+ frame . name ,
96
+ file : DEFAULT_BUNDLE_NAME ,
97
+ lineno : frame . line !== undefined ? Number ( frame . line ) : undefined ,
98
+ colno : frame . column !== undefined ? Number ( frame . column ) : undefined ,
99
+ } ;
55
100
}
56
101
57
102
const MS_TO_NS : number = 1e6 ;
0 commit comments