1818#include "ecma-builtin-helpers.h"
1919#include "ecma-conversion.h"
2020#include "ecma-eval.h"
21+ #include "ecma-function-object.h"
2122#include "ecma-objects.h"
2223#include "jcontext.h"
2324#include "jerryscript-port.h"
@@ -37,9 +38,9 @@ typedef struct
3738 * The number of message types in the debugger should reflect the
3839 * debugger versioning.
3940 */
40- JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 28
41- && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 19
42- && JERRY_DEBUGGER_VERSION == 6 ,
41+ JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 32
42+ && JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21
43+ && JERRY_DEBUGGER_VERSION == 7 ,
4344 debugger_version_correlates_to_message_type_count );
4445
4546/**
@@ -195,6 +196,329 @@ jerry_debugger_send_backtrace (const uint8_t *recv_buffer_p) /**< pointer to the
195196 jerry_debugger_send (sizeof (jerry_debugger_send_type_t ) + message_size );
196197} /* jerry_debugger_send_backtrace */
197198
199+
200+ /**
201+ * Send the scope chain types.
202+ */
203+ static void
204+ jerry_debugger_send_scope_chain (void )
205+ {
206+ vm_frame_ctx_t * iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p );
207+
208+ const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t );
209+ const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count , uint8_t );
210+
211+ JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t , message_type_p );
212+ message_type_p -> type = JERRY_DEBUGGER_SCOPE_CHAIN ;
213+
214+ size_t buffer_pos = 0 ;
215+ uint8_t level_type ;
216+ bool next_func_is_local = true;
217+
218+ for (ecma_object_t * lex_env_p = iter_frame_ctx_p -> lex_env_p ;
219+ lex_env_p != NULL ;
220+ lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p ))
221+ {
222+ JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p ));
223+
224+ if (ecma_get_lex_env_type (lex_env_p ) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE )
225+ {
226+ if ((lex_env_p -> type_flags_refs & ECMA_OBJECT_FLAG_EXTENSIBLE ) != 0 )
227+ {
228+ level_type = JERRY_DEBUGGER_SCOPE_CATCH ;
229+ }
230+ else if (next_func_is_local )
231+ {
232+ level_type = JERRY_DEBUGGER_SCOPE_LOCAL ;
233+ next_func_is_local = false;
234+ }
235+ else
236+ {
237+ level_type = JERRY_DEBUGGER_SCOPE_CLOSURE ;
238+ next_func_is_local = false;
239+ }
240+ }
241+ else
242+ {
243+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p ) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND );
244+
245+ if (ecma_get_lex_env_outer_reference (lex_env_p ) == NULL )
246+ {
247+ level_type = JERRY_DEBUGGER_SCOPE_GLOBAL ;
248+ }
249+ else
250+ {
251+ level_type = JERRY_DEBUGGER_SCOPE_WITH ;
252+ next_func_is_local = true;
253+ }
254+ }
255+
256+ message_type_p -> string [buffer_pos ++ ] = level_type ;
257+
258+ if (buffer_pos == max_byte_count )
259+ {
260+ if (!jerry_debugger_send (max_message_size ))
261+ {
262+ return ;
263+ }
264+
265+ buffer_pos = 0 ;
266+ }
267+ }
268+
269+ message_type_p -> type = JERRY_DEBUGGER_SCOPE_CHAIN_END ;
270+
271+ jerry_debugger_send (sizeof (jerry_debugger_send_type_t ) + buffer_pos );
272+ } /* jerry_debugger_send_scope_chain */
273+
274+ /**
275+ * Get type of the scope variable property.
276+ */
277+ static jerry_debugger_scope_variable_type_t
278+ ecma_get_typeof_scope_variable (ecma_value_t value ) /**< input ecma value */
279+ {
280+ jerry_debugger_scope_variable_type_t ret_value = JERRY_DEBUGGER_VARIABLE_NONE ;
281+
282+ if (ecma_is_value_undefined (value ))
283+ {
284+ ret_value = JERRY_DEBUGGER_VARIABLE_UNDEFINED ;
285+ }
286+ else if (ecma_is_value_null (value ))
287+ {
288+ ret_value = JERRY_DEBUGGER_VARIABLE_NULL ;
289+ }
290+ else if (ecma_is_value_boolean (value ))
291+ {
292+ ret_value = JERRY_DEBUGGER_VARIABLE_BOOLEAN ;
293+ }
294+ else if (ecma_is_value_number (value ))
295+ {
296+ ret_value = JERRY_DEBUGGER_VARIABLE_NUMBER ;
297+ }
298+ else if (ecma_is_value_string (value ))
299+ {
300+ ret_value = JERRY_DEBUGGER_VARIABLE_STRING ;
301+ }
302+ else
303+ {
304+ JERRY_ASSERT (ecma_is_value_object (value ));
305+
306+ if (ecma_object_get_class_name (ecma_get_object_from_value (value )) == LIT_MAGIC_STRING_ARRAY_UL )
307+ {
308+ ret_value = JERRY_DEBUGGER_VARIABLE_ARRAY ;
309+ }
310+ else
311+ {
312+ ret_value = ecma_op_is_callable (value ) ? JERRY_DEBUGGER_VARIABLE_FUNCTION : JERRY_DEBUGGER_VARIABLE_OBJECT ;
313+ }
314+ }
315+
316+ JERRY_ASSERT (ret_value != JERRY_DEBUGGER_VARIABLE_NONE );
317+
318+ return ret_value ;
319+ } /* ecma_get_typeof_scope_variable */
320+
321+ /**
322+ * Helper function for jerry_debugger_send_scope_variables.
323+ *
324+ * It will copies the given scope values type, length and value into the outgoing message string.
325+ *
326+ * @return true - if the copy was successfully
327+ * false - otherwise
328+ */
329+ static bool
330+ copy_scope_variables_to_string_message (jerry_debugger_scope_variable_type_t variable_type , /**< variable type */
331+ ecma_string_t * value_str , /**< property name or value string */
332+ jerry_debugger_send_string_t * message_string_p , /**< message pointer */
333+ size_t * buffer_pos ) /**< string data position of the message */
334+ {
335+ const size_t max_byte_count = JERRY_DEBUGGER_SEND_MAX (uint8_t );
336+ const size_t max_message_size = JERRY_DEBUGGER_SEND_SIZE (max_byte_count , uint8_t );
337+
338+ ECMA_STRING_TO_UTF8_STRING (value_str , str_buff , str_buff_size );
339+
340+ int copied_values = 3 ; // type, length, value
341+ size_t str_size = 0 ;
342+ size_t str_limit = 255 ;
343+ bool result = true;
344+
345+ while (copied_values > 0 )
346+ {
347+ if (* buffer_pos == max_byte_count )
348+ {
349+ if (!jerry_debugger_send (max_message_size ))
350+ {
351+ result = false;
352+ break ;
353+ }
354+
355+ * buffer_pos = 0 ;
356+ }
357+
358+ if (copied_values == 3 )
359+ {
360+ if (variable_type != JERRY_DEBUGGER_VARIABLE_NONE )
361+ {
362+ message_string_p -> string [* buffer_pos ] = variable_type ;
363+ * buffer_pos += 1 ;
364+ }
365+ }
366+ else if (copied_values == 2 )
367+ {
368+ if (variable_type == JERRY_DEBUGGER_VARIABLE_FUNCTION )
369+ {
370+ str_size = 0 ; // do not copy function values
371+ }
372+ else
373+ {
374+ str_size = (str_buff_size > str_limit ) ? str_limit : str_buff_size ;
375+ }
376+
377+ message_string_p -> string [* buffer_pos ] = (uint8_t ) str_size ;
378+ * buffer_pos += 1 ;
379+ }
380+ else
381+ {
382+ size_t free_bytes = max_byte_count - * buffer_pos ;
383+ const uint8_t * string_p = str_buff ;
384+
385+ while (str_size > free_bytes )
386+ {
387+ memcpy (message_string_p -> string + * buffer_pos , string_p , free_bytes );
388+
389+ if (!jerry_debugger_send (max_message_size ))
390+ {
391+ result = false;
392+ break ;
393+ }
394+
395+ string_p += free_bytes ;
396+ str_size -= free_bytes ;
397+ free_bytes = max_byte_count ;
398+ * buffer_pos = 0 ;
399+ }
400+
401+ if (result == false)
402+ {
403+ break ;
404+ }
405+
406+ memcpy (message_string_p -> string + * buffer_pos , string_p , str_size );
407+ * buffer_pos += str_size ;
408+ }
409+
410+ copied_values -- ;
411+ }
412+
413+ ECMA_FINALIZE_UTF8_STRING (str_buff , str_buff_size );
414+
415+ return result ;
416+ } /* copy_scope_variables_to_string_message */
417+
418+ /**
419+ * Send variables of the given scope chain level.
420+ */
421+ static void
422+ jerry_debugger_send_scope_variables (const uint8_t * recv_buffer_p ) /**< pointer to the received data */
423+ {
424+ JERRY_DEBUGGER_RECEIVE_BUFFER_AS (jerry_debugger_receive_get_scope_variables_t , get_scope_variables_p );
425+
426+ uint32_t chain_index ;
427+ memcpy (& chain_index , get_scope_variables_p -> chain_index , sizeof (uint32_t ));
428+
429+ vm_frame_ctx_t * iter_frame_ctx_p = JERRY_CONTEXT (vm_top_context_p );
430+ ecma_object_t * lex_env_p = iter_frame_ctx_p -> lex_env_p ;
431+
432+ while (chain_index != 0 )
433+ {
434+ lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p );
435+
436+ if (lex_env_p == NULL )
437+ {
438+ jerry_debugger_send_type (JERRY_DEBUGGER_SCOPE_VARIABLES_END );
439+ return ;
440+ }
441+
442+ chain_index -- ;
443+ }
444+
445+ ecma_property_header_t * prop_iter_p ;
446+
447+ if (ecma_get_lex_env_type (lex_env_p ) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE )
448+ {
449+ prop_iter_p = ecma_get_property_list (lex_env_p );
450+ }
451+ else
452+ {
453+ JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p ) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND );
454+ ecma_object_t * binding_obj_p = ecma_get_lex_env_binding_object (lex_env_p );
455+ prop_iter_p = ecma_get_property_list (binding_obj_p );
456+ }
457+
458+ JERRY_DEBUGGER_SEND_BUFFER_AS (jerry_debugger_send_string_t , message_string_p );
459+ message_string_p -> type = JERRY_DEBUGGER_SCOPE_VARIABLES ;
460+
461+ size_t buffer_pos = 0 ;
462+
463+ while (prop_iter_p != NULL )
464+ {
465+ JERRY_ASSERT (ECMA_PROPERTY_IS_PROPERTY_PAIR (prop_iter_p ));
466+
467+ ecma_property_pair_t * prop_pair_p = (ecma_property_pair_t * ) prop_iter_p ;
468+
469+ for (int i = 0 ; i < ECMA_PROPERTY_PAIR_ITEM_COUNT ; i ++ )
470+ {
471+ if (ECMA_PROPERTY_IS_NAMED_PROPERTY (prop_iter_p -> types [i ]))
472+ {
473+ ecma_string_t * prop_name = ecma_string_from_property_name (prop_iter_p -> types [i ],
474+ prop_pair_p -> names_cp [i ]);
475+
476+ if (!copy_scope_variables_to_string_message (JERRY_DEBUGGER_VARIABLE_NONE ,
477+ prop_name ,
478+ message_string_p ,
479+ & buffer_pos ))
480+ {
481+ ecma_deref_ecma_string (prop_name );
482+ return ;
483+ }
484+
485+ ecma_deref_ecma_string (prop_name );
486+
487+ ecma_property_value_t prop_value_p = prop_pair_p -> values [i ];
488+ ecma_value_t property_value ;
489+
490+ jerry_debugger_scope_variable_type_t variable_type = ecma_get_typeof_scope_variable (prop_value_p .value );
491+
492+ if (variable_type == JERRY_DEBUGGER_VARIABLE_OBJECT )
493+ {
494+ property_value = ecma_builtin_json_string_from_object (prop_value_p .value );
495+ }
496+ else
497+ {
498+ property_value = ecma_op_to_string (prop_value_p .value );
499+ }
500+
501+ if (!copy_scope_variables_to_string_message (variable_type ,
502+ ecma_get_string_from_value (property_value ),
503+ message_string_p ,
504+ & buffer_pos ))
505+ {
506+ ecma_free_value (property_value );
507+ return ;
508+ }
509+
510+ ecma_free_value (property_value );
511+ }
512+ }
513+
514+ prop_iter_p = ECMA_GET_POINTER (ecma_property_header_t ,
515+ prop_iter_p -> next_property_cp );
516+ }
517+
518+ message_string_p -> type = JERRY_DEBUGGER_SCOPE_VARIABLES_END ;
519+ jerry_debugger_send (sizeof (jerry_debugger_send_type_t ) + buffer_pos );
520+ } /* jerry_debugger_send_scope_variables */
521+
198522/**
199523 * Send result of evaluated expression or throw an error.
200524 *
@@ -525,6 +849,24 @@ jerry_debugger_process_message (const uint8_t *recv_buffer_p, /**< pointer to th
525849 return true;
526850 }
527851
852+ case JERRY_DEBUGGER_GET_SCOPE_CHAIN :
853+ {
854+ JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_type_t );
855+
856+ jerry_debugger_send_scope_chain ();
857+
858+ return true;
859+ }
860+
861+ case JERRY_DEBUGGER_GET_SCOPE_VARIABLES :
862+ {
863+ JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_get_scope_variables_t );
864+
865+ jerry_debugger_send_scope_variables (recv_buffer_p );
866+
867+ return true;
868+ }
869+
528870 case JERRY_DEBUGGER_EXCEPTION_CONFIG :
529871 {
530872 JERRY_DEBUGGER_CHECK_PACKET_SIZE (jerry_debugger_receive_exception_config_t );
0 commit comments