Skip to content

Commit 47fa590

Browse files
authored
Improve the evaluate requests (jerryscript-project#2583)
Currently it evaluates the given expression in the context of the top most stack frame. The expression should access to any variables and arguments that are in the scope chain. Implement the eval_at request with the level of the scope chain as a further argument. JerryScript-DCO-1.0-Signed-off-by: Robert Sipka rsipka.uszeged@partner.samsung.com
1 parent 6c4b316 commit 47fa590

File tree

10 files changed

+170
-13
lines changed

10 files changed

+170
-13
lines changed

jerry-core/debugger/debugger.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ typedef struct
4040
*/
4141
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 32
4242
&& JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21
43-
&& JERRY_DEBUGGER_VERSION == 7,
43+
&& JERRY_DEBUGGER_VERSION == 8,
4444
debugger_version_correlates_to_message_type_count);
4545

4646
/**
@@ -529,12 +529,17 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s
529529
JERRY_ASSERT (!(JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_IGNORE));
530530

531531
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_IGNORE);
532-
ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p + 1, eval_string_size - 1, ECMA_PARSE_DIRECT_EVAL);
532+
533+
uint32_t chain_index;
534+
memcpy (&chain_index, eval_string_p, sizeof (uint32_t));
535+
uint32_t parse_opts = ECMA_PARSE_DIRECT_EVAL | (chain_index << ECMA_PARSE_CHAIN_INDEX_SHIFT);
536+
537+
ecma_value_t result = ecma_op_eval_chars_buffer (eval_string_p + 5, eval_string_size - 5, parse_opts);
533538
JERRY_DEBUGGER_CLEAR_FLAGS (JERRY_DEBUGGER_VM_IGNORE);
534539

535540
if (!ECMA_IS_VALUE_ERROR (result))
536541
{
537-
if (eval_string_p[0] != JERRY_DEBUGGER_EVAL_EVAL)
542+
if (eval_string_p[4] != JERRY_DEBUGGER_EVAL_EVAL)
538543
{
539544
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_EXCEPTION_THROWN);
540545
JERRY_CONTEXT (error_value) = result;
@@ -543,7 +548,7 @@ jerry_debugger_send_eval (const lit_utf8_byte_t *eval_string_p, /**< evaluated s
543548
JERRY_DEBUGGER_SET_FLAGS (JERRY_DEBUGGER_VM_STOP);
544549
JERRY_CONTEXT (debugger_stop_context) = NULL;
545550

546-
if (eval_string_p[0] == JERRY_DEBUGGER_EVAL_THROW)
551+
if (eval_string_p[4] == JERRY_DEBUGGER_EVAL_THROW)
547552
{
548553
JERRY_CONTEXT (status_flags) |= ECMA_STATUS_EXCEPTION;
549554
}
@@ -918,7 +923,7 @@ jerry_debugger_process_message (const uint8_t *recv_buffer_p, /**< pointer to th
918923

919924
case JERRY_DEBUGGER_EVAL:
920925
{
921-
if (message_size < sizeof (jerry_debugger_receive_eval_first_t) + 1)
926+
if (message_size < sizeof (jerry_debugger_receive_eval_first_t) + 5)
922927
{
923928
JERRY_ERROR_MSG ("Invalid message size\n");
924929
jerry_debugger_transport_close ();

jerry-core/ecma/base/ecma-globals.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,18 @@ typedef enum
8080
ECMA_TYPE___MAX = ECMA_TYPE_ERROR /** highest value for ecma types */
8181
} ecma_type_t;
8282

83+
#ifdef JERRY_DEBUGGER
84+
/**
85+
* Shift for scope chain index part in ecma_parse_opts
86+
*/
87+
#define ECMA_PARSE_CHAIN_INDEX_SHIFT 16
88+
#endif
89+
8390
/**
8491
* Option flags for script parsing.
8592
* Note:
8693
* The enum members must be kept in sync with parser_general_flags_t
94+
* The last 16 bits are reserved for scope chain index
8795
*/
8896
typedef enum
8997
{

jerry-core/include/jerryscript-debugger.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ extern "C"
3131
/**
3232
* JerryScript debugger protocol version.
3333
*/
34-
#define JERRY_DEBUGGER_VERSION (7)
34+
#define JERRY_DEBUGGER_VERSION (8)
3535

3636
/**
3737
* Types for the client source wait and run method.

jerry-core/vm/vm.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,26 @@ vm_run_eval (ecma_compiled_code_t *bytecode_data_p, /**< byte-code data */
252252
{
253253
this_binding = ecma_copy_value (JERRY_CONTEXT (vm_top_context_p)->this_binding);
254254
lex_env_p = JERRY_CONTEXT (vm_top_context_p)->lex_env_p;
255+
256+
#ifdef JERRY_DEBUGGER
257+
uint32_t chain_index = parse_opts >> ECMA_PARSE_CHAIN_INDEX_SHIFT;
258+
259+
while (chain_index != 0)
260+
{
261+
lex_env_p = ecma_get_lex_env_outer_reference (lex_env_p);
262+
263+
if (JERRY_UNLIKELY (lex_env_p == NULL))
264+
{
265+
return ecma_raise_range_error (ECMA_ERR_MSG ("Invalid scope chain index for eval"));
266+
}
267+
268+
if ((ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_THIS_OBJECT_BOUND)
269+
|| (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE))
270+
{
271+
chain_index--;
272+
}
273+
}
274+
#endif
255275
}
256276
else
257277
{

jerry-debugger/jerry_client.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,29 @@ def do_eval(self, args):
171171
self.stop = True
172172
do_e = do_eval
173173

174+
def do_eval_at(self, args):
175+
""" Evaluate JavaScript source code at a scope chain level """
176+
177+
code = ''
178+
index = 0
179+
try:
180+
args = args.split(" ", 1)
181+
182+
index = int(args[0])
183+
184+
if len(args) == 2:
185+
code = args[1]
186+
187+
if index < 0 or index > 65535:
188+
raise ValueError("Invalid scope chain index: %d (must be between 0 and 65535)" % index)
189+
190+
except ValueError as val_errno:
191+
print("Error: %s" % (val_errno))
192+
return
193+
194+
self.debugger.eval_at(code, index)
195+
self.stop = True
196+
174197
def do_memstats(self, _):
175198
""" Memory statistics """
176199
self.debugger.memstats()

jerry-debugger/jerry_client_ws.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import sys
2525

2626
# Expected debugger protocol version.
27-
JERRY_DEBUGGER_VERSION = 7
27+
JERRY_DEBUGGER_VERSION = 8
2828

2929
# Messages sent by the server to client.
3030
JERRY_DEBUGGER_CONFIGURATION = 1
@@ -553,6 +553,10 @@ def eval(self, code):
553553
self._send_string(JERRY_DEBUGGER_EVAL_EVAL + code, JERRY_DEBUGGER_EVAL)
554554
self.prompt = False
555555

556+
def eval_at(self, code, index):
557+
self._send_string(JERRY_DEBUGGER_EVAL_EVAL + code, JERRY_DEBUGGER_EVAL, index)
558+
self.prompt = False
559+
556560
def throw(self, code):
557561
self._send_string(JERRY_DEBUGGER_EVAL_THROW + code, JERRY_DEBUGGER_EVAL)
558562
self.prompt = False
@@ -587,12 +591,18 @@ def exception(self, args):
587591

588592
return "Stop at exception disabled\n"
589593

590-
def _send_string(self, args, message_type):
591-
size = len(args)
594+
def _send_string(self, args, message_type, index=0):
592595

593596
# 1: length of type byte
594597
# 4: length of an uint32 value
595598
message_header = 1 + 4
599+
600+
# Add scope chain index
601+
if message_type == JERRY_DEBUGGER_EVAL:
602+
args = struct.pack(self.byte_order + "I", index) + args
603+
604+
size = len(args)
605+
596606
max_fragment = min(self.max_message_size - message_header, size)
597607

598608
message = struct.pack(self.byte_order + "BBIBI",
@@ -601,6 +611,7 @@ def _send_string(self, args, message_type):
601611
0,
602612
message_type,
603613
size)
614+
604615
if size == max_fragment:
605616
self.send_message(message + args)
606617
return

tests/debugger/do_eval_at.cmd

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
eval_at 0
2+
eval_at 0 b
3+
n
4+
eval_at 0 b
5+
b do_eval_at.js:20
6+
n
7+
scopes
8+
eval_at 0 b
9+
eval_at 1 b
10+
eval_at 0 b=20
11+
eval_at 1 b=100
12+
n
13+
eval_at 0 a
14+
scopes
15+
eval_at 0 b
16+
eval_at -1 b
17+
eval_at 65536 b
18+
eval_at b
19+
eval_at 200
20+
c

tests/debugger/do_eval_at.expected

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Connecting to: localhost:5001
2+
Stopped at tests/debugger/do_eval_at.js:15
3+
(jerry-debugger) eval_at 0
4+
undefined
5+
(jerry-debugger) eval_at 0 b
6+
undefined
7+
(jerry-debugger) n
8+
Stopped at tests/debugger/do_eval_at.js:23
9+
(jerry-debugger) eval_at 0 b
10+
2
11+
(jerry-debugger) b do_eval_at.js:20
12+
Breakpoint 1 at tests/debugger/do_eval_at.js:20 (in f() at line:17, col:1)
13+
(jerry-debugger) n
14+
Stopped at breakpoint:1 tests/debugger/do_eval_at.js:20 (in f() at line:17, col:1)
15+
(jerry-debugger) scopes
16+
level | type
17+
0 | local
18+
1 | global
19+
(jerry-debugger) eval_at 0 b
20+
6
21+
(jerry-debugger) eval_at 1 b
22+
2
23+
(jerry-debugger) eval_at 0 b=20
24+
20
25+
(jerry-debugger) eval_at 1 b=100
26+
100
27+
(jerry-debugger) n
28+
Stopped at tests/debugger/do_eval_at.js:25
29+
(jerry-debugger) eval_at 0 a
30+
23
31+
(jerry-debugger) scopes
32+
level | type
33+
0 | global
34+
(jerry-debugger) eval_at 0 b
35+
100
36+
(jerry-debugger) eval_at -1 b
37+
Error: Invalid scope chain index: -1 (must be between 0 and 65535)
38+
(jerry-debugger) eval_at 65536 b
39+
Error: Invalid scope chain index: 65536 (must be between 0 and 65535)
40+
(jerry-debugger) eval_at b
41+
Error: invalid literal for int() with base 10: 'b'
42+
(jerry-debugger) eval_at 200
43+
Uncaught exception: Error
44+
(jerry-debugger) c

tests/debugger/do_eval_at.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
var b = 2;
16+
17+
function f(a)
18+
{
19+
var b = 6;
20+
return a + b;
21+
}
22+
23+
var a = f(3);
24+
25+
null;

tests/debugger/do_help.expected

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ Stopped at tests/debugger/do_help.js:15
44

55
Documented commands (type help <topic>):
66
========================================
7-
abort bt display exception list next s src
8-
b c dump f memstats quit scopes step
9-
backtrace continue e finish ms res scroll throw
10-
break delete eval help n restart source variables
7+
abort c e finish n s step
8+
b continue eval help next scopes throw
9+
backtrace delete eval_at list quit scroll variables
10+
break display exception memstats res source
11+
bt dump f ms restart src
1112

1213
(jerry-debugger) quit

0 commit comments

Comments
 (0)