88#include <njs_main.h>
99
1010
11+ typedef struct {
12+ union {
13+ njs_function_t * function ;
14+ u_char * pc ;
15+ } u ;
16+ uint8_t native ;
17+ } njs_stack_entry_t ;
18+
19+
1120typedef struct {
1221 njs_str_t name ;
1322 njs_str_t file ;
@@ -16,7 +25,7 @@ typedef struct {
1625
1726
1827static njs_int_t njs_add_backtrace_entry (njs_vm_t * vm , njs_arr_t * stack ,
19- njs_native_frame_t * native_frame );
28+ njs_stack_entry_t * se );
2029static njs_int_t njs_backtrace_to_string (njs_vm_t * vm , njs_arr_t * backtrace ,
2130 njs_str_t * dst );
2231
@@ -87,33 +96,34 @@ njs_error_fmt_new(njs_vm_t *vm, njs_value_t *dst, njs_object_type_t type,
8796
8897
8998static njs_int_t
90- njs_error_stack_new (njs_vm_t * vm , njs_object_t * error , njs_value_t * retval )
99+ njs_error_stack_new (njs_vm_t * vm , njs_object_value_t * error )
91100{
92- njs_int_t ret ;
93- njs_str_t string ;
94101 njs_arr_t * stack ;
95- njs_value_t value ;
102+ njs_stack_entry_t * se ;
96103 njs_native_frame_t * frame ;
97104
98- njs_set_object (& value , error );
99-
100- ret = njs_error_to_string (vm , retval , & value );
101- if (njs_slow_path (ret != NJS_OK )) {
102- return ret ;
103- }
104-
105- stack = njs_arr_create (vm -> mem_pool , 4 , sizeof (njs_backtrace_entry_t ));
105+ stack = njs_arr_create (vm -> mem_pool , 4 , sizeof (njs_stack_entry_t ));
106106 if (njs_slow_path (stack == NULL )) {
107107 return NJS_ERROR ;
108108 }
109109
110110 frame = vm -> top_frame ;
111111
112112 for ( ;; ) {
113- if ((frame -> native || frame -> pc != NULL )
114- && njs_add_backtrace_entry (vm , stack , frame ) != NJS_OK )
115- {
116- break ;
113+ if (frame -> native || frame -> pc != NULL ) {
114+ se = njs_arr_add (stack );
115+ if (njs_slow_path (se == NULL )) {
116+ return NJS_ERROR ;
117+ }
118+
119+ se -> native = frame -> native ;
120+
121+ if (se -> native ) {
122+ se -> u .function = frame -> function ;
123+
124+ } else {
125+ se -> u .pc = frame -> pc ;
126+ }
117127 }
118128
119129 frame = frame -> previous ;
@@ -123,25 +133,16 @@ njs_error_stack_new(njs_vm_t *vm, njs_object_t *error, njs_value_t *retval)
123133 }
124134 }
125135
126- njs_string_get (retval , & string );
127-
128- ret = njs_backtrace_to_string (vm , stack , & string );
129-
130- njs_arr_destroy (stack );
136+ njs_data (& error -> value ) = stack ;
131137
132- if (njs_slow_path (ret != NJS_OK )) {
133- return ret ;
134- }
135-
136- return njs_string_create (vm , retval , string .start , string .length );
138+ return NJS_OK ;
137139}
138140
139141
140142njs_int_t
141143njs_error_stack_attach (njs_vm_t * vm , njs_value_t value )
142144{
143- njs_int_t ret ;
144- njs_value_t stack ;
145+ njs_int_t ret ;
145146
146147 if (njs_slow_path (!njs_is_error (& value ))
147148 || njs_object (& value )-> stack_attached )
@@ -153,18 +154,15 @@ njs_error_stack_attach(njs_vm_t *vm, njs_value_t value)
153154 return NJS_OK ;
154155 }
155156
156- ret = njs_error_stack_new (vm , njs_object ( & value ), & stack );
157+ ret = njs_error_stack_new (vm , value . data . u . object_value );
157158 if (njs_slow_path (ret != NJS_OK )) {
158159 njs_internal_error (vm , "njs_error_stack_new() failed" );
159160 return NJS_ERROR ;
160161 }
161162
162163 njs_object (& value )-> stack_attached = 1 ;
163164
164- return njs_object_prop_define (vm , & value ,
165- njs_value_arg (& njs_error_stack_string ),
166- & stack , NJS_OBJECT_PROP_VALUE_CW ,
167- NJS_STACK_HASH );
165+ return NJS_OK ;
168166}
169167
170168
@@ -194,16 +192,20 @@ njs_error_alloc(njs_vm_t *vm, njs_object_t *proto, const njs_value_t *name,
194192 njs_int_t ret ;
195193 njs_object_t * error ;
196194 njs_object_prop_t * prop ;
195+ njs_object_value_t * ov ;
197196 njs_lvlhsh_query_t lhq ;
198197
199- error = njs_mp_alloc (vm -> mem_pool , sizeof (njs_object_t ));
200- if (njs_slow_path (error == NULL )) {
198+ ov = njs_mp_alloc (vm -> mem_pool , sizeof (njs_object_value_t ));
199+ if (njs_slow_path (ov == NULL )) {
201200 goto memory_error ;
202201 }
203202
203+ njs_set_data (& ov -> value , NULL , NJS_DATA_TAG_ANY );
204+
205+ error = & ov -> object ;
204206 njs_lvlhsh_init (& error -> hash );
205207 njs_lvlhsh_init (& error -> shared_hash );
206- error -> type = NJS_OBJECT ;
208+ error -> type = NJS_OBJECT_VALUE ;
207209 error -> shared = 0 ;
208210 error -> extensible = 1 ;
209211 error -> fast_array = 0 ;
@@ -691,6 +693,81 @@ njs_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
691693}
692694
693695
696+ static njs_int_t
697+ njs_error_prototype_stack (njs_vm_t * vm , njs_object_prop_t * prop ,
698+ njs_value_t * value , njs_value_t * setval , njs_value_t * retval )
699+ {
700+ njs_int_t ret ;
701+ njs_str_t string ;
702+ njs_arr_t * stack , * backtrace ;
703+ njs_uint_t i ;
704+ njs_value_t rv ;
705+ njs_stack_entry_t * se ;
706+
707+ if (!njs_is_error (value )) {
708+ njs_type_error (vm , "\"this\" argument is not an Error object" );
709+ return NJS_ERROR ;
710+ }
711+
712+ if (retval != NULL ) {
713+ if (njs_is_string (njs_object_value (value ))) {
714+ * retval = * njs_object_value (value );
715+ return NJS_OK ;
716+ }
717+
718+ if (njs_object_data (value ) != NULL ) {
719+ stack = njs_object_data (value );
720+ se = stack -> start ;
721+
722+ backtrace = njs_arr_create (vm -> mem_pool , stack -> items ,
723+ sizeof (njs_backtrace_entry_t ));
724+ if (njs_slow_path (backtrace == NULL )) {
725+ return NJS_ERROR ;
726+ }
727+
728+ for (i = 0 ; i < stack -> items ; i ++ ) {
729+ if (njs_add_backtrace_entry (vm , backtrace , & se [i ]) != NJS_OK ) {
730+ return NJS_ERROR ;
731+ }
732+ }
733+
734+ ret = njs_error_to_string2 (vm , & rv , value , 0 );
735+ if (njs_slow_path (ret != NJS_OK )) {
736+ return ret ;
737+ }
738+
739+ njs_string_get (& rv , & string );
740+
741+ ret = njs_backtrace_to_string (vm , backtrace , & string );
742+
743+ njs_arr_destroy (backtrace );
744+ njs_arr_destroy (stack );
745+
746+ if (njs_slow_path (ret != NJS_OK )) {
747+ return ret ;
748+ }
749+
750+ ret = njs_string_create (vm , njs_object_value (value ), string .start ,
751+ string .length );
752+
753+ if (njs_slow_path (ret != NJS_OK )) {
754+ return ret ;
755+ }
756+
757+ njs_value_assign (retval , njs_object_value (value ));
758+
759+ return NJS_OK ;
760+ }
761+
762+ njs_set_undefined (retval );
763+ return NJS_OK ;
764+ }
765+
766+ njs_internal_error (vm , "\"stack\" property is read-only" );
767+ return NJS_ERROR ;
768+ }
769+
770+
694771njs_int_t
695772njs_error_to_string (njs_vm_t * vm , njs_value_t * retval , const njs_value_t * error )
696773{
@@ -717,6 +794,9 @@ static const njs_object_prop_t njs_error_prototype_properties[] =
717794 NJS_DECLARE_PROP_NATIVE ("valueOf" , njs_error_prototype_value_of , 0 , 0 ),
718795
719796 NJS_DECLARE_PROP_NATIVE ("toString" , njs_error_prototype_to_string , 0 , 0 ),
797+
798+ NJS_DECLARE_PROP_HANDLER ("stack" , njs_error_prototype_stack ,
799+ 0 , 0 , NJS_OBJECT_PROP_VALUE_CW ),
720800};
721801
722802
@@ -986,14 +1066,14 @@ const njs_object_type_init_t njs_aggregate_error_type_init = {
9861066
9871067static njs_int_t
9881068njs_add_backtrace_entry (njs_vm_t * vm , njs_arr_t * stack ,
989- njs_native_frame_t * native_frame )
1069+ njs_stack_entry_t * se )
9901070{
9911071 njs_int_t ret ;
9921072 njs_vm_code_t * code ;
9931073 njs_function_t * function ;
9941074 njs_backtrace_entry_t * be ;
9951075
996- function = native_frame -> function ;
1076+ function = se -> native ? se -> u . function : NULL ;
9971077
9981078 if (function != NULL && function -> bound != NULL ) {
9991079 /* Skip. */
@@ -1019,7 +1099,7 @@ njs_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
10191099 return NJS_OK ;
10201100 }
10211101
1022- code = njs_lookup_code (vm , native_frame -> pc );
1102+ code = njs_lookup_code (vm , se -> u . pc );
10231103
10241104 if (code != NULL ) {
10251105 be -> name = code -> name ;
@@ -1028,7 +1108,7 @@ njs_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
10281108 be -> name = njs_entry_anonymous ;
10291109 }
10301110
1031- be -> line = njs_lookup_line (code -> lines , native_frame -> pc - code -> start );
1111+ be -> line = njs_lookup_line (code -> lines , se -> u . pc - code -> start );
10321112 if (!vm -> options .quiet ) {
10331113 be -> file = code -> file ;
10341114 }
0 commit comments