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 );
131-
132- if (njs_slow_path (ret != NJS_OK )) {
133- return ret ;
134- }
136+ njs_data (& error -> value ) = stack ;
135137
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 ;
@@ -485,15 +487,18 @@ const njs_object_init_t njs_aggregate_error_constructor_init = {
485487void
486488njs_memory_error_set (njs_vm_t * vm , njs_value_t * value )
487489{
488- njs_object_t * object ;
490+ njs_object_t * object ;
491+ njs_object_value_t * ov ;
489492
490- object = & vm -> memory_error_object ;
493+ ov = & vm -> memory_error_object ;
494+ njs_set_data (& ov -> value , NULL , NJS_DATA_TAG_ANY );
491495
496+ object = & ov -> object ;
492497 njs_lvlhsh_init (& object -> hash );
493498 njs_lvlhsh_init (& object -> shared_hash );
494499 object -> __proto__ = njs_vm_proto (vm , NJS_OBJ_TYPE_INTERNAL_ERROR );
495500 object -> slots = NULL ;
496- object -> type = NJS_OBJECT ;
501+ object -> type = NJS_OBJECT_VALUE ;
497502 object -> shared = 1 ;
498503
499504 /*
@@ -691,6 +696,92 @@ njs_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
691696}
692697
693698
699+ static njs_int_t
700+ njs_error_prototype_stack (njs_vm_t * vm , njs_object_prop_t * prop ,
701+ njs_value_t * value , njs_value_t * setval , njs_value_t * retval )
702+ {
703+ njs_int_t ret ;
704+ njs_str_t string ;
705+ njs_arr_t * stack , * backtrace ;
706+ njs_uint_t i ;
707+ njs_value_t rv , * stackval ;
708+ njs_stack_entry_t * se ;
709+
710+ if (retval != NULL ) {
711+ if (!njs_is_error (value )) {
712+ njs_set_undefined (retval );
713+ return NJS_DECLINED ;
714+ }
715+
716+ stackval = njs_object_value (value );
717+
718+ if (setval != NULL ) {
719+ njs_value_assign (stackval , setval );
720+ return NJS_OK ;
721+ }
722+
723+ if (!njs_is_data (stackval , NJS_DATA_TAG_ANY )) {
724+ njs_value_assign (retval , stackval );
725+ return NJS_OK ;
726+ }
727+
728+ stack = njs_data (stackval );
729+ if (stack == NULL ) {
730+ njs_set_undefined (retval );
731+ return NJS_OK ;
732+ }
733+
734+ se = stack -> start ;
735+
736+ backtrace = njs_arr_create (vm -> mem_pool , stack -> items ,
737+ sizeof (njs_backtrace_entry_t ));
738+ if (njs_slow_path (backtrace == NULL )) {
739+ return NJS_ERROR ;
740+ }
741+
742+ for (i = 0 ; i < stack -> items ; i ++ ) {
743+ if (njs_add_backtrace_entry (vm , backtrace , & se [i ]) != NJS_OK ) {
744+ return NJS_ERROR ;
745+ }
746+ }
747+
748+ ret = njs_error_to_string2 (vm , & rv , value , 0 );
749+ if (njs_slow_path (ret != NJS_OK )) {
750+ return ret ;
751+ }
752+
753+ njs_string_get (& rv , & string );
754+
755+ ret = njs_backtrace_to_string (vm , backtrace , & string );
756+
757+ njs_arr_destroy (backtrace );
758+ njs_arr_destroy (stack );
759+
760+ if (njs_slow_path (ret != NJS_OK )) {
761+ return ret ;
762+ }
763+
764+ ret = njs_string_create (vm , stackval , string .start , string .length );
765+ if (njs_slow_path (ret != NJS_OK )) {
766+ return ret ;
767+ }
768+
769+ njs_value_assign (retval , stackval );
770+
771+ return NJS_OK ;
772+ }
773+
774+ /* Delete. */
775+
776+ if (njs_is_error (value )) {
777+ stackval = njs_object_value (value );
778+ njs_set_data (stackval , NULL , NJS_DATA_TAG_ANY );
779+ }
780+
781+ return NJS_OK ;
782+ }
783+
784+
694785njs_int_t
695786njs_error_to_string (njs_vm_t * vm , njs_value_t * retval , const njs_value_t * error )
696787{
@@ -717,6 +808,9 @@ static const njs_object_prop_t njs_error_prototype_properties[] =
717808 NJS_DECLARE_PROP_NATIVE ("valueOf" , njs_error_prototype_value_of , 0 , 0 ),
718809
719810 NJS_DECLARE_PROP_NATIVE ("toString" , njs_error_prototype_to_string , 0 , 0 ),
811+
812+ NJS_DECLARE_PROP_HANDLER ("stack" , njs_error_prototype_stack ,
813+ 0 , 0 , NJS_OBJECT_PROP_VALUE_CW ),
720814};
721815
722816
@@ -986,14 +1080,14 @@ const njs_object_type_init_t njs_aggregate_error_type_init = {
9861080
9871081static njs_int_t
9881082njs_add_backtrace_entry (njs_vm_t * vm , njs_arr_t * stack ,
989- njs_native_frame_t * native_frame )
1083+ njs_stack_entry_t * se )
9901084{
9911085 njs_int_t ret ;
9921086 njs_vm_code_t * code ;
9931087 njs_function_t * function ;
9941088 njs_backtrace_entry_t * be ;
9951089
996- function = native_frame -> function ;
1090+ function = se -> native ? se -> u . function : NULL ;
9971091
9981092 if (function != NULL && function -> bound != NULL ) {
9991093 /* Skip. */
@@ -1019,7 +1113,7 @@ njs_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
10191113 return NJS_OK ;
10201114 }
10211115
1022- code = njs_lookup_code (vm , native_frame -> pc );
1116+ code = njs_lookup_code (vm , se -> u . pc );
10231117
10241118 if (code != NULL ) {
10251119 be -> name = code -> name ;
@@ -1028,7 +1122,7 @@ njs_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
10281122 be -> name = njs_entry_anonymous ;
10291123 }
10301124
1031- be -> line = njs_lookup_line (code -> lines , native_frame -> pc - code -> start );
1125+ be -> line = njs_lookup_line (code -> lines , se -> u . pc - code -> start );
10321126 if (!vm -> options .quiet ) {
10331127 be -> file = code -> file ;
10341128 }
0 commit comments