diff --git a/examples/builtins/pdb_set_break.py b/examples/builtins/pdb_set_break.py new file mode 100644 index 000000000..21bc5d8ee --- /dev/null +++ b/examples/builtins/pdb_set_break.py @@ -0,0 +1,8 @@ +import PikaDebug as pdb +pdb.set_trace() +pdb.set_break('pdb_set_break', 48) +print('line 1') +print('line 2') +print('line 3') +print('line 4') +print('line 5') diff --git a/package/PikaStdLib/PikaDebug.pyi b/package/PikaStdLib/PikaDebug.pyi index eceee7747..762a8f1b0 100644 --- a/package/PikaStdLib/PikaDebug.pyi +++ b/package/PikaStdLib/PikaDebug.pyi @@ -4,3 +4,12 @@ class Debuger: def set_trace(self): pass + +def set_trace(): + pass + +def set_break(module: str, pc_break: int): + pass + +def reset_break(module: str, pc_break: int): + pass diff --git a/package/PikaStdLib/PikaDebuger_Debuger.c b/package/PikaStdLib/PikaDebuger_Debuger.c index 4e9ba606e..600bca6d7 100644 --- a/package/PikaStdLib/PikaDebuger_Debuger.c +++ b/package/PikaStdLib/PikaDebuger_Debuger.c @@ -1,56 +1,23 @@ #include "PikaVM.h" #include "dataStrs.h" -extern volatile PikaObj* __pikaMain; -static enum shellCTRL __obj_shellLineHandler_debug(PikaObj* self, - char* input_line, - struct ShellConfig* config) { - /* continue */ - if (strEqu("c", input_line)) { - return SHELL_CTRL_EXIT; - } - /* next */ - if (strEqu("n", input_line)) { - return SHELL_CTRL_EXIT; - } - /* launch shell */ - if (strEqu("sh", input_line)) { - /* exit pika shell */ - pikaScriptShell((PikaObj*)__pikaMain); - return SHELL_CTRL_CONTINUE; - } - /* quit */ - if (strEqu("q", input_line)) { - obj_setInt(self, "enable", 0); - return SHELL_CTRL_EXIT; - } - /* print */ - if (strIsStartWith(input_line, "p ")) { - char* path = input_line + 2; - Arg* asm_buff = arg_newStr("B0\n1 REF "); - asm_buff = arg_strAppend(asm_buff, path); - asm_buff = arg_strAppend(asm_buff, "\n0 RUN print\n"); - pikaVM_runAsm((PikaObj*)__pikaMain, arg_getStr(asm_buff)); - arg_deinit(asm_buff); - return SHELL_CTRL_CONTINUE; - } - obj_run((PikaObj*)__pikaMain, input_line); - return SHELL_CTRL_CONTINUE; -} - void PikaDebug_Debuger___init__(PikaObj* self) { /* global enable contral */ obj_setInt(self, "enable", 1); } void PikaDebug_Debuger_set_trace(PikaObj* self) { - if (!obj_getInt(self, "enable")) { - return; - } - struct ShellConfig cfg = { - .prefix = "(pika-debug) ", - .handler = __obj_shellLineHandler_debug, - .fn_getchar = __platform_getchar, - }; - _do_pikaScriptShell(self, &cfg); + pika_debug_set_trace(self); +} + +void PikaDebug_set_trace(PikaObj* self) { + PikaDebug_Debuger_set_trace(self); +} + +void PikaDebug_set_break(PikaObj* self, char* module, int pc_break) { + pika_debug_set_break(module, pc_break); +} + +void PikaDebug_reset_break(PikaObj* self, char* module, int pc_break) { + pika_debug_reset_break(module, pc_break); } diff --git a/port/linux/.vscode/launch.json b/port/linux/.vscode/launch.json index 226e1c5e8..1834301b4 100644 --- a/port/linux/.vscode/launch.json +++ b/port/linux/.vscode/launch.json @@ -12,7 +12,8 @@ // "program": "${workspaceFolder}/build/boot/demo06-pikamain/pikascript_demo06-pikamain", "args": [ // "--gtest_filter=vm.keyword_2" - "--gtest_filter=vm.exit_vm" + // "--gtest_filter=compiler.find_break_point" + "--gtest_filter=pikaMain.REPL_pdb_set_break" ], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/port/linux/.vscode/settings.json b/port/linux/.vscode/settings.json index a69f7adcd..5bb650b42 100644 --- a/port/linux/.vscode/settings.json +++ b/port/linux/.vscode/settings.json @@ -129,7 +129,7 @@ "editor.defaultFormatter": "tamasfe.even-better-toml" }, "[python]": { - "editor.defaultFormatter": "ms-python.autopep8" + "editor.defaultFormatter": "ms-python.python" }, "[c]": { "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd" diff --git a/port/linux/package/pikascript/PikaDebug.pyi b/port/linux/package/pikascript/PikaDebug.pyi index eceee7747..762a8f1b0 100644 --- a/port/linux/package/pikascript/PikaDebug.pyi +++ b/port/linux/package/pikascript/PikaDebug.pyi @@ -4,3 +4,12 @@ class Debuger: def set_trace(self): pass + +def set_trace(): + pass + +def set_break(module: str, pc_break: int): + pass + +def reset_break(module: str, pc_break: int): + pass diff --git a/port/linux/package/pikascript/main.py b/port/linux/package/pikascript/main.py index 77b29cb0a..aca47dc84 100644 --- a/port/linux/package/pikascript/main.py +++ b/port/linux/package/pikascript/main.py @@ -1,4 +1,5 @@ -import PikaStdLib, PikaStdDevice, PikaMath, PikaDebug, PikaCV, PikaNN +import PikaDebug as pdb +import PikaStdLib, PikaStdDevice, PikaMath, PikaCV, PikaNN import random, re, modbus, socket, unittest, binascii, ctypes, requests, mqtt import pika_lua, pika_cjson, cjson_test, json import GTestTask, TempDevTest diff --git a/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaDebuger_Debuger.c b/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaDebuger_Debuger.c index 4e9ba606e..600bca6d7 100644 --- a/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaDebuger_Debuger.c +++ b/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaDebuger_Debuger.c @@ -1,56 +1,23 @@ #include "PikaVM.h" #include "dataStrs.h" -extern volatile PikaObj* __pikaMain; -static enum shellCTRL __obj_shellLineHandler_debug(PikaObj* self, - char* input_line, - struct ShellConfig* config) { - /* continue */ - if (strEqu("c", input_line)) { - return SHELL_CTRL_EXIT; - } - /* next */ - if (strEqu("n", input_line)) { - return SHELL_CTRL_EXIT; - } - /* launch shell */ - if (strEqu("sh", input_line)) { - /* exit pika shell */ - pikaScriptShell((PikaObj*)__pikaMain); - return SHELL_CTRL_CONTINUE; - } - /* quit */ - if (strEqu("q", input_line)) { - obj_setInt(self, "enable", 0); - return SHELL_CTRL_EXIT; - } - /* print */ - if (strIsStartWith(input_line, "p ")) { - char* path = input_line + 2; - Arg* asm_buff = arg_newStr("B0\n1 REF "); - asm_buff = arg_strAppend(asm_buff, path); - asm_buff = arg_strAppend(asm_buff, "\n0 RUN print\n"); - pikaVM_runAsm((PikaObj*)__pikaMain, arg_getStr(asm_buff)); - arg_deinit(asm_buff); - return SHELL_CTRL_CONTINUE; - } - obj_run((PikaObj*)__pikaMain, input_line); - return SHELL_CTRL_CONTINUE; -} - void PikaDebug_Debuger___init__(PikaObj* self) { /* global enable contral */ obj_setInt(self, "enable", 1); } void PikaDebug_Debuger_set_trace(PikaObj* self) { - if (!obj_getInt(self, "enable")) { - return; - } - struct ShellConfig cfg = { - .prefix = "(pika-debug) ", - .handler = __obj_shellLineHandler_debug, - .fn_getchar = __platform_getchar, - }; - _do_pikaScriptShell(self, &cfg); + pika_debug_set_trace(self); +} + +void PikaDebug_set_trace(PikaObj* self) { + PikaDebug_Debuger_set_trace(self); +} + +void PikaDebug_set_break(PikaObj* self, char* module, int pc_break) { + pika_debug_set_break(module, pc_break); +} + +void PikaDebug_reset_break(PikaObj* self, char* module, int pc_break) { + pika_debug_reset_break(module, pc_break); } diff --git a/port/linux/package/pikascript/pikascript-lib/time/_time.c b/port/linux/package/pikascript/pikascript-lib/time/_time.c index d9b88fb1b..9ccc70719 100644 --- a/port/linux/package/pikascript/pikascript-lib/time/_time.c +++ b/port/linux/package/pikascript/pikascript-lib/time/_time.c @@ -8,7 +8,7 @@ #endif void (*global_do_sleep_ms)(uint32_t); -extern volatile VMSignal g_PikaVMSignal; +extern volatile VMState g_PikaVMState; volatile int g_pika_local_timezone = 8; static void _do_sleep_ms_tick(uint32_t ms) { diff --git a/port/linux/test/compile-test.cpp b/port/linux/test/compile-test.cpp deleted file mode 100644 index 2a2055970..000000000 --- a/port/linux/test/compile-test.cpp +++ /dev/null @@ -1,806 +0,0 @@ -#include "test_common.h" -TEST_START - -TEST(compiler, file) { - char* lines = - "len = calls.len()\n" - "mode = 'none'\n" - "info_index = 0\n" - "for i in range(0, len):\n" - " if len == 0:\n" - " break\n" - " if info_index == 0:\n" - " mode = calls[i]\n" - " info_index = 1\n" - " elif info_index == 1:\n" - " if mode == 'always':\n" - " todo = calls[i]\n" - " todo()\n" - " info_index = 0\n" - " elif mode == 'when':\n" - " when = calls[i]\n" - " info_index = 2\n" - " elif mode == 'period_ms':\n" - " period_ms = calls[i]\n" - " info_index = 2\n" - " elif info_index == 2:\n" - " if mode == 'when':\n" - " if when():\n" - " todo = calls[i]\n" - " todo()\n" - " info_index = 0\n" - " elif mode == 'period_ms':\n" - " todo = calls[i]\n" - " info_index = 3\n" - " elif info_index == 3:\n" - " if mode == 'period_ms':\n" - " if tick > calls[i]:\n" - " todo()\n" - " calls[i] = tick + period_ms\n" - " info_index = 0\n" - "\n"; - pikaCompile("task.bin", lines); - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, task) { - char* lines = - "len = calls.len()\n" - "mode = 'none'\n" - "info_index = 0\n" - "for i in range(0, len):\n" - " if len == 0:\n" - " break\n" - " if info_index == 0:\n" - " mode = calls[i]\n" - " info_index = 1\n" - " elif info_index == 1:\n" - " if mode == 'always':\n" - " todo = calls[i]\n" - " todo()\n" - " info_index = 0\n" - " elif mode == 'when':\n" - " when = calls[i]\n" - " info_index = 2\n" - " elif mode == 'period_ms':\n" - " period_ms = calls[i]\n" - " info_index = 2\n" - " elif info_index == 2:\n" - " if mode == 'when':\n" - " if when():\n" - " todo = calls[i]\n" - " todo()\n" - " info_index = 0\n" - " elif mode == 'period_ms':\n" - " todo = calls[i]\n" - " info_index = 3\n" - " elif info_index == 3:\n" - " if mode == 'period_ms':\n" - " if tick > calls[i]:\n" - " todo()\n" - " calls[i] = tick + period_ms\n" - " info_index = 0\n" - "\n"; - - Args buffs = {0}; - char* pikaAsm = pika_lines2Asm(&buffs, lines); - - ByteCodeFrame bytecode_frame; - byteCodeFrame_init(&bytecode_frame); - byteCodeFrame_appendFromAsm(&bytecode_frame, pikaAsm); - /* do something */ - byteCodeFrame_print(&bytecode_frame); - printf("Asm size: %d\r\n", (int)strGetSize(pikaAsm)); - - byteCodeFrame_printAsArray(&bytecode_frame); - - /* deinit */ - byteCodeFrame_deinit(&bytecode_frame); - strsDeinit(&buffs); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, demo1) { - char* lines = "append(__val)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, snake_file) { - char* lines = - "from PikaObj import *\n" - "import PikaStdLib\n" - "import machine \n" - "\n" - "# hardware init\n" - "lcd = machine.LCD()\n" - "lcd.init()\n" - "lcd.clear('white')\n" - "key = machine.KEY()\n" - "key.init()\n" - "time = machine.Time()\n" - "x_max = 120\n" - "y_max = 150\n" - "\n" - "# snake init\n" - "s = machine.Point()\n" - "w = 9\n" - "h = 9\n" - "s.x = 50\n" - "s.y = 10\n" - "len = 0\n" - "while len < 3:\n" - " b = s\n" - " i = 0\n" - " while i < len:\n" - " b = b.next\n" - " i = i + 1\n" - " b.next = machine.Point()\n" - " b.next.x = b.x - 10\n" - " b.next.y = b.y\n" - " b.next.prev = b\n" - " len = len + 1\n" - "# ring link\n" - "b.next = s\n" - "s.prev = b\n" - "\n" - "i = 0\n" - "b = s\n" - "while i < len:\n" - " lcd.fill(b.x, b.y, w, h, 'blue')\n" - " b = b.next\n" - " i = i + 1\n" - "\n" - "print('snake lengh')\n" - "print(len)\n" - "\n" - "# fruit init\n" - "f = machine.Point()\n" - "f.x = 30\n" - "f.y = 20\n" - "lcd.fill(f.x, f.y, w, h, 'green')\n" - "\n" - "# memory check\n" - "mem = PikaStdLib.MemChecker()\n" - "print('mem used max:')\n" - "mem.max()\n" - "\n" - "# main loop\n" - "d = 0\n" - "isUpdate = 1\n" - "isEat = 0\n" - "while True:\n" - " if isUpdate:\n" - " # isUpdate = 0\n" - " # check eat fruit\n" - " if f.x == s.x and f.y == s.y:\n" - " # have eat fruit\n" - " isEat = 1\n" - " f.x = f.x + 30\n" - " if f.x > x_max:\n" - " f.x = f.x - x_max\n" - " f.y = f.y + 30\n" - " if f.y > y_max:\n" - " f.y = f.y - y_max\n" - " lcd.fill(f.x, f.y, w, h, 'green')\n" - " # move snake by the direction\n" - " if d == 0:\n" - " x_new = s.x + 10\n" - " y_new = s.y\n" - " if x_new > x_max:\n" - " x_new = 0\n" - " elif d == 1:\n" - " x_new = s.x\n" - " y_new = s.y - 10\n" - " if y_new < 0:\n" - " y_new = y_max\n" - " elif d == 2:\n" - " x_new = s.x\n" - " y_new = s.y + 10\n" - " if y_new > y_max:\n" - " y_new = 0\n" - " elif d == 3:\n" - " x_new = s.x - 10\n" - " y_new = s.y\n" - " if x_new < 0:\n" - " x_new = x_max\n" - " if isEat:\n" - " isEat = 0\n" - " b_new = machine.Point()\n" - " b_new.x = x_new\n" - " b_new.y = y_new\n" - " b_new.prev = s.prev\n" - " b_new.next = s\n" - " s.prev.next = b_new\n" - " s.prev = b_new\n" - " s = b_new\n" - " len = len + 1\n" - " print('snake lengh')\n" - " print(len)\n" - " print('mem used max:')\n" - " mem.max()\n" - " # drow the snake and fruit\n" - " # clear last body\n" - " lcd.fill(s.prev.x, s.prev.y, w, h, 'white')\n" - " # new body\n" - " s.prev.x = x_new\n" - " s.prev.y = y_new\n" - " # head is last body\n" - " s = s.prev\n" - " lcd.fill(s.x, s.y, w, h, 'blue')\n" - " b = s\n" - " i = 0\n" - " # scan key\n" - " key_val = key.get()\n" - " if key_val == 0:\n" - " d = 0\n" - " isUpdate = 1\n" - " elif key_val == 1:\n" - " d = 1\n" - " isUpdate = 1\n" - " elif key_val == 2:\n" - " d = 2\n" - " isUpdate = 1\n" - " elif key_val == 3:\n" - " d = 3\n" - " isUpdate = 1\n"; - pikaCompile("snake.bin", lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, import_bf_mem) { - PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); - char* lines = - "def mytest():\n" - " print('test')\n" - "\n"; - ByteCodeFrame bf; - byteCodeFrame_init(&bf); - pika_lines2Bytes(&bf, lines); - obj_importModuleWithByteCodeFrame(pikaMain, "mtest", &bf); - byteCodeFrame_deinit(&bf); - obj_deinit(pikaMain); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, import_bf1) { - PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); - char* lines = - "def mytest():\n" - " print('test_import_bf1')\n" - "\n"; - ByteCodeFrame bf; - byteCodeFrame_init(&bf); - pika_lines2Bytes(&bf, lines); - obj_importModuleWithByteCodeFrame(pikaMain, "mtest", &bf); - obj_run(pikaMain, - "mtest.mytest()\n" - "\n"); - EXPECT_STREQ(log_buff[0], "test_import_bf1\r\n"); - byteCodeFrame_deinit(&bf); - obj_deinit(pikaMain); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, import_bf2) { - PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); - char* lines = - "class Test:\n" - " def mytest(self):\n" - " print('test_import_bf2')\n" - "\n"; - ByteCodeFrame bf; - byteCodeFrame_init(&bf); - pika_lines2Bytes(&bf, lines); - obj_importModuleWithByteCodeFrame(pikaMain, "mtest", &bf); - obj_run(pikaMain, - "m = mtest.Test()\n" - "m.mytest()\n" - "\n"); - byteCodeFrame_deinit(&bf); - obj_deinit(pikaMain); - EXPECT_STREQ(log_buff[0], "test_import_bf2\r\n"); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, file1) { - pikaCompileFile("test/python/main.py"); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, file2) { - pikaCompileFile("test/python/main_snake_LCD.py"); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, init) { - LibObj* lib = New_LibObj(NULL); - LibObj_deinit(lib); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, lib_link_bytecode) { - LibObj* lib = New_LibObj(NULL); - LibObj_dynamicLink(lib, "module1", (uint8_t*)0x3344); - LibObj_dynamicLink(lib, "module2", (uint8_t*)0x33433); - LibObj_dynamicLink(lib, "module3", (uint8_t*)0x33433); - LibObj_dynamicLink(lib, "module4", (uint8_t*)0x33433); - LibObj_dynamicLink(lib, "module5", (uint8_t*)0x33433); - EXPECT_STREQ(obj_getStr(lib, "module1.name"), "module1"); - EXPECT_EQ((uintptr_t)obj_getPtr(lib, "module1.bytecode"), 0x3344); - /* deinit */ - LibObj_deinit(lib); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, lib_push_file) { - LibObj* lib = New_LibObj(NULL); - LibObj_staticLinkFile(lib, "test/python/main.py.o"); - /* deinit */ - LibObj_deinit(lib); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, lib_push_files) { - LibObj* lib = New_LibObj(NULL); - LibObj_staticLinkFile(lib, "test/python/main.py.o"); - LibObj_staticLinkFile(lib, "test/python/main_snake_LCD.py.o"); - LibObj_listModules(lib); - /* asset */ - EXPECT_STREQ(log_buff[0], "main\r\n"); - EXPECT_STREQ(log_buff[1], "main_snake_LCD\r\n"); - /* deinit */ - LibObj_deinit(lib); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, lib_compile_link) { - LibObj* lib = New_LibObj(NULL); - - pikaCompileFile("test/python/UnitTest.py"); - pikaCompileFile("test/python/main.py"); - pikaCompileFile("test/python/main_snake_LCD.py"); - - LibObj_staticLinkFile(lib, "test/python/UnitTest.py.o"); - LibObj_staticLinkFile(lib, "test/python/main.py.o"); - LibObj_staticLinkFile(lib, "test/python/main_snake_LCD.py.o"); - - LibObj_listModules(lib); - /* asset */ - EXPECT_STREQ(log_buff[0], "UnitTest\r\n"); - EXPECT_STREQ(log_buff[1], "main\r\n"); - EXPECT_STREQ(log_buff[2], "main_snake_LCD\r\n"); - /* deinit */ - LibObj_deinit(lib); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, compile_link_import) { - LibObj* lib = New_LibObj(NULL); - - pikaCompileFile("test/python/test_module1.py"); - LibObj_staticLinkFile(lib, "test/python/test_module1.py.o"); - LibObj_listModules(lib); - - PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); - obj_linkLibObj(pikaMain, lib); - obj_run(pikaMain, - "import test_module1\n" - "test_module1.mytest()\n"); - /* asset */ - EXPECT_STREQ(log_buff[0], "test_module_1_hello\r\n"); - /* deinit */ - obj_deinit(pikaMain); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, lib_to_file) { - LibObj* lib = New_LibObj(NULL); - - pikaCompileFile("test/python/UnitTest.py"); - pikaCompileFile("test/python/main.py"); - pikaCompileFile("test/python/main_snake_LCD.py"); - - LibObj_staticLinkFile(lib, "test/python/UnitTest.py.o"); - LibObj_staticLinkFile(lib, "test/python/main.py.o"); - LibObj_staticLinkFile(lib, "test/python/main_snake_LCD.py.o"); - - LibObj_listModules(lib); - LibObj_linkFile(lib, "test/python/lib_to_file.py.a"); - /* asset */ - EXPECT_STREQ(log_buff[0], "UnitTest\r\n"); - EXPECT_STREQ(log_buff[1], "main\r\n"); - EXPECT_STREQ(log_buff[2], "main_snake_LCD\r\n"); - /* deinit */ - LibObj_deinit(lib); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, save2) { - LibObj* lib = New_LibObj(NULL); - - pikaCompileFile("test/python/test_module1.py"); - pikaCompileFile("test/python/test_module2.py"); - pikaCompileFile("test/python/test_module3.py"); - - LibObj_staticLinkFile(lib, "test/python/test_module1.py.o"); - LibObj_staticLinkFile(lib, "test/python/test_module2.py.o"); - LibObj_staticLinkFile(lib, "test/python/test_module3.py.o"); - - LibObj_listModules(lib); - LibObj_linkFile(lib, "test/python/test_module.py.a"); - /* asset */ - EXPECT_STREQ(log_buff[0], "test_module1\r\n"); - EXPECT_STREQ(log_buff[1], "test_module2\r\n"); - EXPECT_STREQ(log_buff[2], "test_module3\r\n"); - /* deinit */ - LibObj_deinit(lib); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, load_file) { - /* compile */ - LibObj* lib = New_LibObj(NULL); - LibObj_loadLibraryFile(lib, "test/python/test_module.py.a"); - - PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); - obj_linkLibObj(pikaMain, lib); - obj_run(pikaMain, - "import test_module1\n" - "import test_module2\n" - "import test_module3\n" - "test_module1.mytest()\n" - "test_module2.mytest()\n" - "test_module3.mytest()\n"); - /* asset */ - EXPECT_STREQ(log_buff[2], "test_module_1_hello\r\n"); - EXPECT_STREQ(log_buff[1], "test_module_2_hello\r\n"); - EXPECT_STREQ(log_buff[0], "test_module_3_hello\r\n"); - /* deinit */ - obj_deinit(pikaMain); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, load_no_file) { - /* compile */ - LibObj* lib = New_LibObj(NULL); - int res = LibObj_loadLibraryFile(lib, "test/python/mian.py.o"); - EXPECT_EQ(res, PIKA_RES_ERR_IO_ERROR); - /* deinit */ - LibObj_deinit(lib); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, load_err_file_type) { - /* compile */ - LibObj* lib = New_LibObj(NULL); - int res = LibObj_loadLibraryFile(lib, "test/python/main.py.o"); - EXPECT_EQ(res, PIKA_RES_ERR_OPERATION_FAILED); - /* deinit */ - LibObj_deinit(lib); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(lib, lib_file_to_array) { - Lib_loadLibraryFileToArray("test/python/lib_to_file.py.a", "test/python"); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(make, maker) { - PikaMaker* maker = New_PikaMaker(); - pikaMaker_deinit(maker); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(make, compile) { - PikaMaker* maker = New_PikaMaker(); - pikaMaker_setPWD(maker, "package/pikascript/"); - pikaMaker_compileModule(maker, "main"); - pikaMaker_deinit(maker); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(make, depend) { - PikaMaker* maker = New_PikaMaker(); - pikaMaker_setPWD(maker, "package/pikascript/"); - pikaMaker_getDependencies(maker, "main"); - pikaMaker_printStates(maker); - // char* uncompiled = pikaMaker_getFirstNocompiled(maker); - // EXPECT_STREQ(uncompiled, "test_module1"); - pikaMaker_deinit(maker); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(make, compile_depend) { - PikaMaker* maker = New_PikaMaker(); - pikaMaker_setPWD(maker, "package/pikascript/"); - pikaMaker_getDependencies(maker, "main"); - char* uncompiled = pikaMaker_getFirstNocompiled(maker); - pika_assert(NULL != uncompiled); - pikaMaker_compileModule(maker, uncompiled); - pikaMaker_getDependencies(maker, uncompiled); - uncompiled = pikaMaker_getFirstNocompiled(maker); - // EXPECT_STREQ(uncompiled, "test_module3"); - pikaMaker_printStates(maker); - pikaMaker_deinit(maker); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(make, compile_depend_all) { - PikaMaker* maker = New_PikaMaker(); - pikaMaker_setPWD(maker, "package/pikascript/"); - pikaMaker_compileModuleWithDepends(maker, "main"); - pikaMaker_printStates(maker); - pikaMaker_deinit(maker); - EXPECT_EQ(pikaMemNow(), 0); -} - -// TEST(make, compile_link_all) { -// PikaMaker* maker = New_PikaMaker(); -// pikaMaker_setPWD(maker, "package/pikascript/"); -// pikaMaker_compileModuleWithDepends(maker, "main"); -// pikaMaker_printStates(maker); -// pikaMaker_linkCompiledModules(maker, "pikaModules.py.a"); -// pikaMaker_deinit(maker); -// EXPECT_EQ(pikaMemNow(), 0); -// } - -TEST(compiler, __str__) { - char* lines = "@res_str = __str__()"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __len__) { - char* lines = "@res_len = __len__()"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __del__) { - char* lines = "__del__()"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, event_cb) { - char* lines = "_eventCallBack(_eventSignal)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, event_cb_lvgl) { - char* lines = "_res = eventCallBack(eventData)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __setitem__) { - char* lines = "__setitem__(__key, __val)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __getitem__) { - char* lines = "@res_item = __getitem__(__key)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __add__) { - char* lines = "@res_add = __add__(__others)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __eq__) { - char* lines = "@res_eq = __eq__(__others)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __iter__) { - char* lines = "@res_iter = __iter__()"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __sub__) { - char* lines = "@res_sub = __sub__(__others)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __contains__) { - char* lines = "@res_contains = __contains__(__others)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __callback) { - char* lines = "__callback(__frameBuffer, __isNewFrame)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, __list) { - char* lines = - "@res_list = []\n" - "for __item in __list:\n" - " @res_list.append(__item)\n" - "del __item\n" - "del __list\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, getattr) { - char* lines = "@res = __getattribute__(@name)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, getattr2) { - char* lines = "@res = __getattr__(@name)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, setattr) { - char* lines = "__setattr__(@name, @value)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, dict_update) { - char* lines = - "for @item in @other:\n" - " @self[@item] = @other[@item]\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, i_pp) { - char* lines = - "i = 0\n" - "while i < 10000:\n" - " i += 1\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, benchmark) { - char* lines = - "num = 0\n" - "i = 2\n" - "while i < 1000:\n" - " is_prime = 1\n" - " j = 2\n" - " while j < i:\n" - " if i%j==0 :\n" - " is_prime = 0\n" - " break\n" - " j += 1 \n" - " if is_prime:\n" - " num = num + i\n" - " i += 1\n" - "\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, for_print_1k) { - char* lines = - "for i in range(1000):\n" - " print(i)\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, bc_fn) { - char* lines = - "def test():\n" - " print('test')\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, starrd) { - char* lines = "@l = __len__()"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, starrd_get) { - char* lines = "@a = __getitem__(@d)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, thread_arg) { - char* lines = "thread(*args)"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, prime_100) { - char* lines = - "num = 0\n" - "i = 2\n" - "for i in range(2,100):\n" - " j=2\n" - " is_prime = 1\n" - " for j in range(2,i):\n" - " if i%j==0 :\n" - " is_prime = 0\n" - " break\n" - " if is_prime:\n" - " num = num + i\n" - "\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, getattr_fn) { - char* lines = "@res = @obj.@name\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, str_join) { - char* lines = - "@res_join = \"\"\n" - "@num = len(@val)\n" - "for i in range(@num):\n" - " @res_join += @val[i]\n" - " if i != @num - 1:\n" - " @res_join += @str\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, thread_void_arg) { - char* lines = "thread()"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, max) { - char* lines = - "@res_max = @list[0]\n" - "for @item in @list:\n" - " if @item > @res_max:\n" - " @res_max = @item\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, min) { - char* lines = - "@res_max = @list[0]\n" - "for @item in @list:\n" - " if @item < @res_max:\n" - " @res_max = @item\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, contains) { - char* lines = - "@res_contains = 0\n" - "for @item in @list:\n" - " if @item == @val:\n" - " @res_contains = 1\n" - " break\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST(compiler, fn1) { - char* lines = "@r = @f(@d)\n"; - pika_lines2Array(lines); - EXPECT_EQ(pikaMemNow(), 0); -} - -TEST_END diff --git a/port/linux/test/module-test.cpp b/port/linux/test/module-test.cpp index fdcace9fa..b03c473b1 100644 --- a/port/linux/test/module-test.cpp +++ b/port/linux/test/module-test.cpp @@ -559,7 +559,7 @@ TEST(module, REPL_script) { fclose((FILE*)f_getchar_fp); /* collect */ /* assert */ - EXPECT_STREQ(log_buff[4], "mem used max:\r\n"); + EXPECT_STREQ(log_buff[3], "mem used max:\r\n"); /* deinit */ obj_deinit(pikaMain); EXPECT_EQ(pikaMemNow(), 0); diff --git a/port/linux/test/pikaMain-test.cpp b/port/linux/test/pikaMain-test.cpp index 28e6dbbb5..f545e1fca 100644 --- a/port/linux/test/pikaMain-test.cpp +++ b/port/linux/test/pikaMain-test.cpp @@ -2927,6 +2927,25 @@ TEST(pikaMain, REPL_key_down_over) { EXPECT_EQ(pikaMemNow(), 0); } +TEST(pikaMain, REPL_pdb_set_break) { + char lines[] = "pdb.set_break('pdb_set_break', 36)\nn\nn\nn\n"; + write_to_getchar_buffer(lines, strGetSize(lines)); + /* init */ + g_PikaMemInfo.heapUsedMax = 0; + PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); + extern unsigned char pikaModules_py_a[]; + obj_linkLibrary(pikaMain, pikaModules_py_a); + pikaVM_runSingleFile(pikaMain, "test/python/builtins/pdb_set_break.py"); + /* run */ + __platform_printf("BEGIN\r\n"); + /* collect */ + /* assert */ + // EXPECT_STREQ(log_buff[1], "2\r\n"); + /* deinit */ + obj_deinit(pikaMain); + EXPECT_EQ(pikaMemNow(), 0); +} + #endif #if PIKA_SHELL_FILTER_ENABLE diff --git a/port/linux/test/pika_config_gtest.c b/port/linux/test/pika_config_gtest.c index c3b538515..cfef373a2 100644 --- a/port/linux/test/pika_config_gtest.c +++ b/port/linux/test/pika_config_gtest.c @@ -51,3 +51,26 @@ PIKA_WEAK void pika_hook_unused_stack_arg(PikaVMFrame* vm, Arg* arg) { arg_print(arg, pika_true, "\r\n"); } } + +#define GETCHAR_BUFFER_SIZE 1024 +uint8_t getchar_buffer[GETCHAR_BUFFER_SIZE] = {0}; +size_t getchar_buffer_index = 0; + +int write_to_getchar_buffer(const char* str, size_t size) { + if (size > GETCHAR_BUFFER_SIZE - getchar_buffer_index) { + return -1; + } + memcpy(getchar_buffer + getchar_buffer_index, str, size); + getchar_buffer_index += size; + return 0; +} + +char pika_platform_getchar(void) { + if (getchar_buffer_index > 0) { + char c = getchar_buffer[0]; + memmove(getchar_buffer, getchar_buffer + 1, getchar_buffer_index - 1); + getchar_buffer_index--; + return c; + } + return getchar(); +} diff --git a/port/linux/test/pika_config_gtest.h b/port/linux/test/pika_config_gtest.h index d416a2f04..2e4ad6e2a 100644 --- a/port/linux/test/pika_config_gtest.h +++ b/port/linux/test/pika_config_gtest.h @@ -1,4 +1,6 @@ +#include #define LOG_BUFF_MAX 100 #define LOG_SIZE 512 void mem_pool_deinit(void); void mem_pool_init(void); +int write_to_getchar_buffer(const char* str, size_t size); diff --git a/port/linux/test/python/PikaUI/test_page.py b/port/linux/test/python/PikaUI/test_page.py index c750644a6..ce697b4c4 100644 --- a/port/linux/test/python/PikaUI/test_page.py +++ b/port/linux/test/python/PikaUI/test_page.py @@ -1,7 +1,5 @@ import PikaUI as ui from PikaStdLib import MemChecker as mem - - class MainContainer(ui.Container): def onclick_next(self, event): print('Page1: onclick_next') diff --git a/port/linux/test/python/builtins/pdb_set_break.py b/port/linux/test/python/builtins/pdb_set_break.py new file mode 100644 index 000000000..21bc5d8ee --- /dev/null +++ b/port/linux/test/python/builtins/pdb_set_break.py @@ -0,0 +1,8 @@ +import PikaDebug as pdb +pdb.set_trace() +pdb.set_break('pdb_set_break', 48) +print('line 1') +print('line 2') +print('line 3') +print('line 4') +print('line 5') diff --git a/src/PikaObj.c b/src/PikaObj.c index 7ede6169f..f1a89f21d 100644 --- a/src/PikaObj.c +++ b/src/PikaObj.c @@ -37,13 +37,14 @@ #include "dataQueue.h" #include "dataString.h" #include "dataStrs.h" +#include "PikaParser.h" #if __linux #include "signal.h" #include "termios.h" #include "unistd.h" #endif -extern volatile VMSignal g_PikaVMSignal; +extern volatile VMState g_PikaVMState; volatile PikaObjState g_PikaObjState = { .helpModulesCmodule = NULL, .inRootObj = pika_false, @@ -1790,7 +1791,9 @@ enum shellCTRL _inner_do_obj_runChar(PikaObj* self, } shell->lineBuff[shell->line_position] = '\0'; ctrl = shell->handler(self, shell->lineBuff, shell); - pika_platform_printf("%s", shell->prefix); + if (SHELL_CTRL_EXIT != ctrl) { + pika_platform_printf("%s", shell->prefix); + } __clearBuff(shell); goto __exit; } @@ -2032,7 +2035,9 @@ static enum shellCTRL __obj_shellLineHandler_REPL(PikaObj* self, return SHELL_CTRL_EXIT; } /* run single line */ - _pikaVM_runPyLines(self, input_line, pika_true); + pikaVM_run_ex_cfg cfg = {0}; + cfg.in_repl = pika_true; + pikaVM_run_ex(self, input_line, &cfg); return SHELL_CTRL_CONTINUE; } @@ -2542,6 +2547,17 @@ PikaObj* obj_importModuleWithByteCode(PikaObj* self, pikaVM_runByteCode(obj_getObj((PikaObj*)__pikaMain, name), (uint8_t*)byteCode); + PikaObj* module_obj = obj_getObj((PikaObj*)__pikaMain, name); + + PikaVMThread vm_thread = {.try_state = TRY_STATE_NONE, + .try_result = TRY_RESULT_NONE}; + pikaVM_runBytecode_ex_cfg cfg = {0}; + cfg.globals = module_obj; + cfg.locals = module_obj; + cfg.name = name; + cfg.vm_thread = &vm_thread; + cfg.is_const_bytecode = pika_true; + pikaVM_runByteCode_ex(module_obj, byteCode, &cfg); } if (self != (PikaObj*)__pikaMain) { /* import to other module context */ @@ -2617,7 +2633,16 @@ int obj_runModule(PikaObj* self, char* module_name) { if (NULL == bytecode) { return 1; } - pikaVM_runByteCode(self, bytecode); + + PikaVMThread vm_thread = {.try_state = TRY_STATE_NONE, + .try_result = TRY_RESULT_NONE}; + pikaVM_runBytecode_ex_cfg cfg = {0}; + cfg.globals = self; + cfg.locals = self; + cfg.name = module_name; + cfg.vm_thread = &vm_thread; + cfg.is_const_bytecode = pika_true; + pikaVM_runByteCode_ex(self, bytecode, &cfg); return 0; } @@ -2791,8 +2816,8 @@ static void _thread_event(void* arg) { while (1) { pika_GIL_ENTER(); #if PIKA_EVENT_ENABLE - if (g_PikaVMSignal.event_thread_exit) { - g_PikaVMSignal.event_thread_exit_done = 1; + if (g_PikaVMState.event_thread_exit) { + g_PikaVMState.event_thread_exit_done = 1; break; } #endif @@ -2814,11 +2839,11 @@ PIKA_RES _do_pika_eventListener_send(PikaEventListener* self, #else _RETURN_WHEN_NOT_ZERO(pika_GIL_ENTER(), -1); #if PIKA_EVENT_THREAD_ENABLE - if (!g_PikaVMSignal.event_thread) { + if (!g_PikaVMState.event_thread) { /* using multi thread */ if (_VM_is_first_lock()) { // avoid _VMEvent_pickupEvent() in _time.c as soon as possible - g_PikaVMSignal.event_thread = pika_platform_thread_init( + g_PikaVMState.event_thread = pika_platform_thread_init( "pika_event", _thread_event, NULL, PIKA_EVENT_THREAD_STACK_SIZE, PIKA_THREAD_PRIO, PIKA_THREAD_TICK); pika_debug("event thread init"); @@ -2870,11 +2895,11 @@ Arg* pika_eventListener_sendSignalAwaitResult(PikaEventListener* self, while (1) { }; #else - extern volatile VMSignal g_PikaVMSignal; - int tail = g_PikaVMSignal.cq.tail; + extern volatile VMState g_PikaVMState; + int tail = g_PikaVMState.cq.tail; pika_eventListener_sendSignal(self, eventId, eventSignal); while (1) { - Arg* res = g_PikaVMSignal.cq.res[tail]; + Arg* res = g_PikaVMState.cq.res[tail]; pika_platform_thread_yield(); if (NULL != res) { return res; @@ -4443,3 +4468,73 @@ size_t pikaDict_getBytesSize(PikaDict* self, char* name) { void pikaDict_deinit(PikaDict* self) { obj_deinit(self); } + +PIKA_RES insert_label_at_line(const char* filename, + int N, + char* buff, + int buff_size) { + FILE* file = pika_platform_fopen(filename, "r"); + if (!file) { + return PIKA_RES_ERR_IO_ERROR; + } + + int line_count = 1; + int buff_index = 0; + char ch; + + while ((pika_platform_fread(&ch, 1, 1, file)) != 0) { + if (line_count == N) { + char* label = "#!label\n"; + int label_length = strGetSize(label); + + if (buff_index + label_length >= buff_size) { + pika_platform_fclose(file); + return PIKA_RES_ERR_IO_ERROR; // Insufficient buffer size + } + + strCopy(buff + buff_index, label); + buff_index += label_length; + line_count++; // Skip this line since we're adding a label + } + + if (ch == '\n') { + line_count++; + } + + if (buff_index >= + buff_size - 1) { // -1 to leave space for null terminator + pika_platform_fclose(file); + return PIKA_RES_ERR_IO_ERROR; // Insufficient buffer size + } + + buff[buff_index] = ch; + buff_index++; + } + + buff[buff_index] = '\0'; // Null terminate the buffer + + pika_platform_fclose(file); + return PIKA_RES_OK; +} + +int32_t pika_debug_find_break_point_pc(char* pyFile, uint32_t pyLine) { + ByteCodeFrame bytecode_frame; + byteCodeFrame_init(&bytecode_frame); + char* file_buff = pikaMalloc(PIKA_READ_FILE_BUFF_SIZE); + FILE* file = pika_platform_fopen(pyFile, "r"); + if (!file) { + goto __exit; + } + if (PIKA_RES_OK != insert_label_at_line(pyFile, pyLine, file_buff, + PIKA_READ_FILE_BUFF_SIZE)) { + goto __exit; + } + pika_lines2Bytes(&bytecode_frame, file_buff); +__exit: + if (NULL != file) { + pika_platform_fclose(file); + } + byteCodeFrame_deinit(&bytecode_frame); + pikaFree(file_buff, PIKA_READ_FILE_BUFF_SIZE); + return bytecode_frame.label_pc; +} diff --git a/src/PikaObj.h b/src/PikaObj.h index 8465440e5..081bbbfc9 100644 --- a/src/PikaObj.h +++ b/src/PikaObj.h @@ -69,8 +69,11 @@ struct InstructArray { typedef struct ByteCodeFrame ByteCodeFrame; struct ByteCodeFrame { + char* name; + Hash name_hash; ConstPool const_pool; InstructArray instruct_array; + int32_t label_pc; }; typedef struct NativeProperty NativeProperty; @@ -459,6 +462,8 @@ struct ShellConfig { ShellHistory* history; #endif pika_bool no_echo; + PikaObj* locals; + PikaObj* globals; }; #if PIKA_SHELL_HISTORY_ENABLE @@ -808,6 +813,8 @@ uint32_t pikaGC_printFreeList(void); int pika_GIL_EXIT(void); int pika_GIL_ENTER(void); +int32_t pika_debug_find_break_point_pc(char* pyFile, uint32_t pyLine); + typedef PikaObj PikaList; typedef PikaObj PikaTuple; typedef PikaObj PikaDict; diff --git a/src/PikaParser.c b/src/PikaParser.c index 2ae1ea29d..ae09eb79b 100644 --- a/src/PikaParser.c +++ b/src/PikaParser.c @@ -2954,6 +2954,11 @@ char* parser_lines2Target(Parser* self, char* sPyLines) { __parse_line: /* parse single Line to Asm */ + if (strEqu(sLine, "#!label")) { + self->bytecode_frame->label_pc = + self->bytecode_frame->instruct_array.size; + goto __next_line; + } sBackendCode = parser_line2Target(self, sLine); __parse_after: if (NULL == sBackendCode) { diff --git a/src/PikaParser.h b/src/PikaParser.h index a0c866f8b..01b7cbf00 100644 --- a/src/PikaParser.h +++ b/src/PikaParser.h @@ -103,6 +103,7 @@ struct Parser { pika_bool isGenBytecode; ByteCodeFrame* bytecode_frame; uint8_t thisBlockDeepth; + uint32_t label_pc; }; typedef struct LexToken LexToken; diff --git a/src/PikaVM.c b/src/PikaVM.c index 7193e7cc6..ac6360fa6 100644 --- a/src/PikaVM.c +++ b/src/PikaVM.c @@ -38,20 +38,24 @@ #endif static pika_platform_thread_mutex_t g_pikaGIL = {0}; -volatile VMSignal g_PikaVMSignal = {.signal_ctrl = VM_SIGNAL_CTRL_NONE, - - .vm_cnt = 0, +volatile VMState g_PikaVMState = { + .signal_ctrl = VM_SIGNAL_CTRL_NONE, + .vm_cnt = 0, #if PIKA_EVENT_ENABLE - .cq = - { - .head = 0, - .tail = 0, - .res = {0}, - }, - .event_pickup_cnt = 0, - .event_thread = NULL, - .event_thread_exit = pika_false - + .cq = + { + .head = 0, + .tail = 0, + .res = {0}, + }, + .event_pickup_cnt = 0, + .event_thread = NULL, + .event_thread_exit = pika_false, +#endif +#if PIKA_DEBUG_BREAK_POINT_MAX > 0 + .break_module_hash = {0}, + .break_point_pc = {0}, + .break_point_cnt = 0, #endif }; extern volatile PikaObjState g_PikaObjState; @@ -127,14 +131,14 @@ int _VM_is_first_lock(void) { } int _VMEvent_getVMCnt(void) { - return g_PikaVMSignal.vm_cnt; + return g_PikaVMState.vm_cnt; } int _VMEvent_getEventPickupCnt(void) { #if !PIKA_EVENT_ENABLE return -1; #else - return g_PikaVMSignal.event_pickup_cnt; + return g_PikaVMState.event_pickup_cnt; #endif } @@ -209,21 +213,21 @@ void _VMEvent_deinit(void) { pika_platform_panic_handle(); #else for (int i = 0; i < PIKA_EVENT_LIST_SIZE; i++) { - if (NULL != g_PikaVMSignal.cq.res[i]) { - arg_deinit(g_PikaVMSignal.cq.res[i]); - g_PikaVMSignal.cq.res[i] = NULL; + if (NULL != g_PikaVMState.cq.res[i]) { + arg_deinit(g_PikaVMState.cq.res[i]); + g_PikaVMState.cq.res[i] = NULL; } - if (NULL != g_PikaVMSignal.cq.data[i]) { - arg_deinit(g_PikaVMSignal.cq.data[i]); - g_PikaVMSignal.cq.data[i] = NULL; + if (NULL != g_PikaVMState.cq.data[i]) { + arg_deinit(g_PikaVMState.cq.data[i]); + g_PikaVMState.cq.data[i] = NULL; } } - if (NULL != g_PikaVMSignal.event_thread) { - g_PikaVMSignal.event_thread_exit = 1; - pika_platform_thread_destroy(g_PikaVMSignal.event_thread); - g_PikaVMSignal.event_thread = NULL; + if (NULL != g_PikaVMState.event_thread) { + g_PikaVMState.event_thread_exit = 1; + pika_platform_thread_destroy(g_PikaVMState.event_thread); + g_PikaVMState.event_thread = NULL; pika_GIL_EXIT(); - while (!g_PikaVMSignal.event_thread_exit_done) { + while (!g_PikaVMState.event_thread_exit_done) { pika_platform_thread_yield(); } pika_GIL_ENTER(); @@ -243,24 +247,23 @@ PIKA_RES __eventListener_pushEvent(PikaEventListener* lisener, arg_setType(eventData, ARG_TYPE_OBJECT); } /* push to event_cq_buff */ - if (_ecq_isFull(&g_PikaVMSignal.cq)) { + if (_ecq_isFull(&g_PikaVMState.cq)) { // pika_debug("event_cq_buff is full"); arg_deinit(eventData); return PIKA_RES_ERR_SIGNAL_EVENT_FULL; } - if (g_PikaVMSignal.cq.res[g_PikaVMSignal.cq.tail] != NULL) { - arg_deinit(g_PikaVMSignal.cq.res[g_PikaVMSignal.cq.tail]); - g_PikaVMSignal.cq.res[g_PikaVMSignal.cq.tail] = NULL; + if (g_PikaVMState.cq.res[g_PikaVMState.cq.tail] != NULL) { + arg_deinit(g_PikaVMState.cq.res[g_PikaVMState.cq.tail]); + g_PikaVMState.cq.res[g_PikaVMState.cq.tail] = NULL; } - if (g_PikaVMSignal.cq.data[g_PikaVMSignal.cq.tail] != NULL) { - arg_deinit(g_PikaVMSignal.cq.data[g_PikaVMSignal.cq.tail]); - g_PikaVMSignal.cq.data[g_PikaVMSignal.cq.tail] = NULL; + if (g_PikaVMState.cq.data[g_PikaVMState.cq.tail] != NULL) { + arg_deinit(g_PikaVMState.cq.data[g_PikaVMState.cq.tail]); + g_PikaVMState.cq.data[g_PikaVMState.cq.tail] = NULL; } - g_PikaVMSignal.cq.id[g_PikaVMSignal.cq.tail] = eventId; - g_PikaVMSignal.cq.data[g_PikaVMSignal.cq.tail] = eventData; - g_PikaVMSignal.cq.listener[g_PikaVMSignal.cq.tail] = lisener; - g_PikaVMSignal.cq.tail = - (g_PikaVMSignal.cq.tail + 1) % PIKA_EVENT_LIST_SIZE; + g_PikaVMState.cq.id[g_PikaVMState.cq.tail] = eventId; + g_PikaVMState.cq.data[g_PikaVMState.cq.tail] = eventData; + g_PikaVMState.cq.listener[g_PikaVMState.cq.tail] = lisener; + g_PikaVMState.cq.tail = (g_PikaVMState.cq.tail + 1) % PIKA_EVENT_LIST_SIZE; return PIKA_RES_OK; #endif } @@ -275,15 +278,14 @@ PIKA_RES __eventListener_popEvent(PikaEventListener** lisener_p, return PIKA_RES_ERR_OPERATION_FAILED; #else /* pop from event_cq_buff */ - if (_ecq_isEmpty(&g_PikaVMSignal.cq)) { + if (_ecq_isEmpty(&g_PikaVMState.cq)) { return PIKA_RES_ERR_SIGNAL_EVENT_EMPTY; } - *id = g_PikaVMSignal.cq.id[g_PikaVMSignal.cq.head]; - *data = g_PikaVMSignal.cq.data[g_PikaVMSignal.cq.head]; - *lisener_p = g_PikaVMSignal.cq.listener[g_PikaVMSignal.cq.head]; - *head = g_PikaVMSignal.cq.head; - g_PikaVMSignal.cq.head = - (g_PikaVMSignal.cq.head + 1) % PIKA_EVENT_LIST_SIZE; + *id = g_PikaVMState.cq.id[g_PikaVMState.cq.head]; + *data = g_PikaVMState.cq.data[g_PikaVMState.cq.head]; + *lisener_p = g_PikaVMState.cq.listener[g_PikaVMState.cq.head]; + *head = g_PikaVMState.cq.head; + g_PikaVMState.cq.head = (g_PikaVMState.cq.head + 1) % PIKA_EVENT_LIST_SIZE; return PIKA_RES_OK; #endif } @@ -303,23 +305,23 @@ void __VMEvent_pickupEvent(char* info) { int head; if (PIKA_RES_OK == __eventListener_popEvent(&event_lisener, &event_id, &event_data, &head)) { - g_PikaVMSignal.event_pickup_cnt++; + g_PikaVMState.event_pickup_cnt++; pika_debug("pickup_info: %s", info); pika_debug("pickup_cnt: %d", g_PikaVMSignal.event_pickup_cnt); Arg* res = __eventListener_runEvent(event_lisener, event_id, event_data); - g_PikaVMSignal.cq.res[head] = res; - g_PikaVMSignal.event_pickup_cnt--; + g_PikaVMState.cq.res[head] = res; + g_PikaVMState.event_pickup_cnt--; } #endif } VM_SIGNAL_CTRL VMSignal_getCtrl(void) { - return g_PikaVMSignal.signal_ctrl; + return g_PikaVMState.signal_ctrl; } void pika_vm_exit(void) { - g_PikaVMSignal.signal_ctrl = VM_SIGNAL_CTRL_EXIT; + g_PikaVMState.signal_ctrl = VM_SIGNAL_CTRL_EXIT; } void pika_vm_exit_await(void) { @@ -333,7 +335,7 @@ void pika_vm_exit_await(void) { } void pika_vmSignal_setCtrlClear(void) { - g_PikaVMSignal.signal_ctrl = VM_SIGNAL_CTRL_NONE; + g_PikaVMState.signal_ctrl = VM_SIGNAL_CTRL_NONE; } /* head declare start */ @@ -401,6 +403,21 @@ static int PikaVMFrame_getInvokeDeepthNow(PikaVMFrame* vm) { return instructUnit_getInvokeDeepth(ins_unit); } +pika_bool PikaVMFrame_checkBreakPoint(PikaVMFrame* vm) { +#if !PIKA_DEBUG_BREAK_POINT_MAX + return pika_false; +#else + if (g_PikaVMState.break_point_cnt == 0) { + return pika_false; + } + if (NULL == vm->bytecode_frame->name) { + return pika_false; + } + Hash module_hash = byteCodeFrame_getNameHash(vm->bytecode_frame); + return pika_debug_check_break_hash(module_hash, vm->pc); +#endif +} + static int32_t PikaVMFrame_getAddrOffsetOfJmpBack(PikaVMFrame* vm) { int offset = 0; int blockDeepthGot = -1; @@ -731,9 +748,9 @@ Arg* _vm_get(PikaVMFrame* vm, PikaObj* self, Arg* aKey, Arg* aObj) { 0x73, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x00, /* const pool */ }; if (NULL != vm) { - aRes = _do_pikaVM_runByteCodeReturn(oArg, oArg, oArg, - (uint8_t*)bytes, vm->vm_thread, - pika_true, "@res_item"); + aRes = pikaVM_runByteCode_exReturn(oArg, oArg, oArg, + (uint8_t*)bytes, vm->vm_thread, + pika_true, "@res_item"); } else { aRes = pikaVM_runByteCodeReturn(oArg, (uint8_t*)bytes, "@res_item"); } @@ -1811,6 +1828,13 @@ InstructUnit* byteCodeFrame_findInsForward(ByteCodeFrame* bcframe, pika_true); } +Hash byteCodeFrame_getNameHash(ByteCodeFrame* bcframe) { + if (0 == bcframe->name_hash) { + bcframe->name_hash = hash_time33(bcframe->name); + } + return bcframe->name_hash; +} + InstructUnit* byteCodeFrame_findInsUnitBackward(ByteCodeFrame* bcframe, int32_t pc_start, enum InstructIndex index, @@ -3565,6 +3589,70 @@ const VM_instruct_handler VM_instruct_handler_table[__INSTRUCTION_CNT] = { }; #endif +extern volatile PikaObj* __pikaMain; +static enum shellCTRL __obj_shellLineHandler_debug(PikaObj* self, + char* input_line, + struct ShellConfig* config) { + /* continue */ + if (strEqu("c", input_line)) { + return SHELL_CTRL_EXIT; + } + /* next */ + if (strEqu("n", input_line)) { + return SHELL_CTRL_EXIT; + } + /* launch shell */ + if (strEqu("sh", input_line)) { + /* exit pika shell */ + pikaScriptShell((PikaObj*)__pikaMain); + return SHELL_CTRL_CONTINUE; + } + /* quit */ + if (strEqu("q", input_line)) { + obj_setInt(self, "enable", 0); + return SHELL_CTRL_EXIT; + } + /* print */ + if (strIsStartWith(input_line, "p ")) { + char* path = input_line + 2; + Arg* asm_buff = arg_newStr("print("); + asm_buff = arg_strAppend(asm_buff, path); + asm_buff = arg_strAppend(asm_buff, ")\n"); + pikaVM_run_ex_cfg cfg = {0}; + cfg.globals = config->globals; + cfg.in_repl = pika_true; + pikaVM_run_ex(config->locals, arg_getStr(asm_buff), &cfg); + arg_deinit(asm_buff); + return SHELL_CTRL_CONTINUE; + } + pikaVM_run_ex_cfg cfg = {0}; + cfg.globals = config->globals; + cfg.in_repl = pika_true; + pikaVM_run_ex(config->locals, input_line, &cfg); + return SHELL_CTRL_CONTINUE; +} + +void pika_debug_set_trace(PikaObj* self) { + if (!obj_getInt(self, "enable")) { + return; + } + char* name = "stdin"; + pika_assert(NULL != self->vmFrame); + if (NULL != self->vmFrame->bytecode_frame->name) { + name = self->vmFrame->bytecode_frame->name; + } + pika_platform_printf("%s:%d\n", name, self->vmFrame->pc); + struct ShellConfig cfg = { + .prefix = "(Pdb-pika) ", + .handler = __obj_shellLineHandler_debug, + .fn_getchar = __platform_getchar, + .locals = self->vmFrame->locals, + .globals = self->vmFrame->globals, + }; + _do_pikaScriptShell(self, &cfg); + shConfig_deinit(&cfg); +} + static int pikaVM_runInstructUnit(PikaObj* self, PikaVMFrame* vm, InstructUnit* ins_unit) { @@ -3576,6 +3664,9 @@ static int pikaVM_runInstructUnit(PikaObj* self, char* data = PikaVMFrame_getConstWithInstructUnit(vm, ins_unit); /* run instruct */ pika_assert(NULL != vm->vm_thread); + if (PikaVMFrame_checkBreakPoint(vm)) { + pika_debug_set_trace(self); + } #if PIKA_INSTRUCT_EXTENSION_ENABLE const VMInstruction* ins = instructUnit_getInstruct(instruct); @@ -3751,14 +3842,16 @@ static ByteCodeFrame* _cache_bcf_fn_bc(PikaObj* self, uint8_t* bytecode) { return _cache_bytecodeframe(self); } -VMParameters* _pikaVM_runPyLines(PikaObj* self, - char* py_lines, - pika_bool in_repl) { - VMParameters* globals = NULL; +VMParameters* pikaVM_run_ex(PikaObj* self, + char* py_lines, + pikaVM_run_ex_cfg* cfg) { ByteCodeFrame bytecode_frame_stack = {0}; ByteCodeFrame* bytecode_frame_p = NULL; uint8_t is_use_heap_bytecode = 0; - + PikaObj* globals = self; + if (NULL != cfg->globals) { + globals = cfg->globals; + } /* * the first obj_run, cache bytecode to heap, to support 'def' and * 'class' @@ -3779,7 +3872,11 @@ VMParameters* _pikaVM_runPyLines(PikaObj* self, goto __exit; } /* run byteCode */ - globals = _pikaVM_runByteCodeFrame(self, bytecode_frame_p, in_repl); + if (NULL != cfg->module_name) { + byteCodeFrame_setName(bytecode_frame_p, cfg->module_name); + } + globals = _pikaVM_runByteCodeFrameGlobals(self, globals, bytecode_frame_p, + cfg->in_repl); goto __exit; __exit: if (!is_use_heap_bytecode) { @@ -3788,12 +3885,9 @@ __exit: return globals; } -VMParameters* _do_pikaVM_runByteCode(PikaObj* self, - VMParameters* locals, - VMParameters* globals, - uint8_t* bytecode, - PikaVMThread* vm_thread, - pika_bool is_const_bytecode) { +VMParameters* pikaVM_runByteCode_ex(PikaObj* self, + uint8_t* bytecode, + pikaVM_runBytecode_ex_cfg* cfg) { ByteCodeFrame bytecode_frame_stack = {0}; ByteCodeFrame* bytecode_frame_p = NULL; uint8_t is_use_heap_bytecode = 1; @@ -3807,24 +3901,24 @@ VMParameters* _do_pikaVM_runByteCode(PikaObj* self, /* get bytecode_ptr from stack */ bytecode_frame_p = &bytecode_frame_stack; /* no def/class ins, no need cache bytecode */ - is_const_bytecode = pika_true; + cfg->is_const_bytecode = pika_true; } /* load or generate byte code frame */ /* load bytecode */ - _do_byteCodeFrame_loadByteCode(bytecode_frame_p, bytecode, - is_const_bytecode); + _do_byteCodeFrame_loadByteCode(bytecode_frame_p, bytecode, cfg->name, + cfg->is_const_bytecode); /* run byteCode */ - globals = _pikaVM_runByteCodeFrameWithState(self, locals, globals, - bytecode_frame_p, 0, vm_thread); + cfg->globals = _pikaVM_runByteCodeFrameWithState( + self, cfg->locals, cfg->globals, bytecode_frame_p, 0, cfg->vm_thread); goto __exit; __exit: if (!is_use_heap_bytecode) { byteCodeFrame_deinit(&bytecode_frame_stack); } - return globals; + return cfg->globals; } VMParameters* pikaVM_runByteCodeFile(PikaObj* self, char* filename) { @@ -3852,21 +3946,33 @@ VMParameters* pikaVM_runSingleFile(PikaObj* self, char* filename) { char* lines = (char*)arg_getBytes(file_arg); lines = strsFilePreProcess(&buffs, lines); /* clear the void line */ - VMParameters* res = pikaVM_run(self, lines); + pikaVM_run_ex_cfg cfg = {0}; + cfg.in_repl = pika_false; + char* module_name = strsPathGetFileName(&buffs, filename); + module_name = strsPopToken(&buffs, &module_name, '.'); + cfg.module_name = module_name; + VMParameters* res = pikaVM_run_ex(self, lines, &cfg); arg_deinit(file_arg); strsDeinit(&buffs); return res; } VMParameters* pikaVM_run(PikaObj* self, char* py_lines) { - return _pikaVM_runPyLines(self, py_lines, pika_false); + pikaVM_run_ex_cfg cfg = {0}; + cfg.in_repl = pika_false; + return pikaVM_run_ex(self, py_lines, &cfg); } VMParameters* pikaVM_runByteCode(PikaObj* self, const uint8_t* bytecode) { PikaVMThread vm_thread = {.try_state = TRY_STATE_NONE, .try_result = TRY_RESULT_NONE}; - return _do_pikaVM_runByteCode(self, self, self, (uint8_t*)bytecode, - &vm_thread, pika_true); + pikaVM_runBytecode_ex_cfg cfg = {0}; + cfg.locals = self; + cfg.globals = self; + cfg.name = NULL; + cfg.vm_thread = &vm_thread; + cfg.is_const_bytecode = pika_true; + return pikaVM_runByteCode_ex(self, (uint8_t*)bytecode, &cfg); } Arg* pikaVM_runByteCodeReturn(PikaObj* self, @@ -3884,15 +3990,19 @@ Arg* pikaVM_runByteCodeReturn(PikaObj* self, return ret; } -Arg* _do_pikaVM_runByteCodeReturn(PikaObj* self, - VMParameters* locals, - VMParameters* globals, - uint8_t* bytecode, - PikaVMThread* vm_thread, - pika_bool is_const_bytecode, - char* return_name) { - _do_pikaVM_runByteCode(self, locals, globals, bytecode, vm_thread, - is_const_bytecode); +Arg* pikaVM_runByteCode_exReturn(PikaObj* self, + VMParameters* locals, + VMParameters* globals, + uint8_t* bytecode, + PikaVMThread* vm_thread, + pika_bool is_const_bytecode, + char* return_name) { + pikaVM_runBytecode_ex_cfg cfg = {0}; + cfg.locals = locals; + cfg.globals = globals; + cfg.vm_thread = vm_thread; + cfg.is_const_bytecode = is_const_bytecode; + pikaVM_runByteCode_ex(self, bytecode, &cfg); Arg* ret = args_getArg(self->list, return_name); if (NULL == ret) { return NULL; @@ -3907,8 +4017,12 @@ Arg* _do_pikaVM_runByteCodeReturn(PikaObj* self, VMParameters* pikaVM_runByteCodeInconstant(PikaObj* self, uint8_t* bytecode) { PikaVMThread vm_thread = {.try_state = TRY_STATE_NONE, .try_result = TRY_RESULT_NONE}; - return _do_pikaVM_runByteCode(self, self, self, (uint8_t*)bytecode, - &vm_thread, pika_false); + pikaVM_runBytecode_ex_cfg cfg = {0}; + cfg.locals = self; + cfg.globals = self; + cfg.vm_thread = &vm_thread; + cfg.is_const_bytecode = pika_false; + return pikaVM_runByteCode_ex(self, (uint8_t*)bytecode, &cfg); } void constPool_update(ConstPool* self) { @@ -4017,11 +4131,14 @@ void byteCodeFrame_init(ByteCodeFrame* self) { can not init */ constPool_init(&(self->const_pool)); instructArray_init(&(self->instruct_array)); + self->name = NULL; + self->label_pc = -1; } extern const char magic_code_pyo[4]; void _do_byteCodeFrame_loadByteCode(ByteCodeFrame* self, uint8_t* bytes, + char* name, pika_bool is_const) { if (bytes[0] == magic_code_pyo[0] && bytes[1] == magic_code_pyo[1] && bytes[2] == magic_code_pyo[2] && bytes[3] == magic_code_pyo[3]) { @@ -4037,6 +4154,7 @@ void _do_byteCodeFrame_loadByteCode(ByteCodeFrame* self, self->const_pool.size = *const_size_p; self->const_pool.content_start = (char*)((uintptr_t)const_size_p + sizeof(*const_size_p)); + byteCodeFrame_setName(self, name); if (!is_const) { pika_assert(NULL == self->instruct_array.arg_buff); pika_assert(NULL == self->instruct_array.arg_buff); @@ -4051,13 +4169,23 @@ void _do_byteCodeFrame_loadByteCode(ByteCodeFrame* self, pika_assert(NULL != self->const_pool.content_start); } +void byteCodeFrame_setName(ByteCodeFrame* self, char* name) { + if (name != NULL && self->name == NULL) { + self->name = pika_platform_malloc(strGetSize(name) + 1); + pika_platform_memcpy(self->name, name, strGetSize(name) + 1); + } +} + void byteCodeFrame_loadByteCode(ByteCodeFrame* self, uint8_t* bytes) { - _do_byteCodeFrame_loadByteCode(self, bytes, pika_true); + _do_byteCodeFrame_loadByteCode(self, bytes, NULL, pika_true); } void byteCodeFrame_deinit(ByteCodeFrame* self) { constPool_deinit(&(self->const_pool)); instructArray_deinit(&(self->instruct_array)); + if (NULL != self->name) { + pika_platform_free(self->name); + } } void instructArray_init(InstructArray* self) { @@ -4313,13 +4441,13 @@ static VMParameters* __pikaVM_runByteCodeFrameWithState( int size = bytecode_frame->instruct_array.size; /* locals is the local scope */ - if (g_PikaVMSignal.vm_cnt == 0) { + if (g_PikaVMState.vm_cnt == 0) { pika_vmSignal_setCtrlClear(); } PikaVMFrame* vm = PikaVMFrame_create(locals, globals, bytecode_frame, pc, vm_thread); vm->in_repl = in_repl; - g_PikaVMSignal.vm_cnt++; + g_PikaVMState.vm_cnt++; while (vm->pc < size) { if (vm->pc == VM_PC_EXIT) { break; @@ -4332,6 +4460,7 @@ static VMParameters* __pikaVM_runByteCodeFrameWithState( vm->vm_thread->error_code = 0; vm->vm_thread->line_error_code = 0; } + self->vmFrame = vm; vm->pc = pikaVM_runInstructUnit(self, vm, this_ins_unit); vm->ins_cnt++; #if PIKA_INSTRUCT_HOOK_ENABLE @@ -4376,12 +4505,71 @@ static VMParameters* __pikaVM_runByteCodeFrameWithState( } PikaVMFrame_solveUnusedStack(vm); stack_deinit(&(vm->stack)); - g_PikaVMSignal.vm_cnt--; + g_PikaVMState.vm_cnt--; VMParameters* result = locals; pikaFree(vm, sizeof(PikaVMFrame)); + self->vmFrame = NULL; return result; } +pika_bool pika_debug_check_break(char* module_name, int pc_break) { + Hash h = hash_time33(module_name); + for (int i = 0; i < g_PikaVMState.break_point_cnt; i++) { + if (g_PikaVMState.break_module_hash[i] == h && + g_PikaVMState.break_point_pc[i] == pc_break) { + return pika_true; + } + } + return pika_false; +} + +pika_bool pika_debug_check_break_hash(Hash module_hash, int pc_break) { + for (int i = 0; i < g_PikaVMState.break_point_cnt; i++) { + if (g_PikaVMState.break_module_hash[i] == module_hash && + g_PikaVMState.break_point_pc[i] == pc_break) { + return pika_true; + } + } + return pika_false; +} + +PIKA_RES pika_debug_set_break(char* module_name, int pc_break) { + if (pika_debug_check_break(module_name, pc_break)) { + return PIKA_RES_OK; + } + if (g_PikaVMState.break_point_cnt >= PIKA_DEBUG_BREAK_POINT_MAX) { + return PIKA_RES_ERR_RUNTIME_ERROR; + } + Hash h = hash_time33(module_name); + g_PikaVMState.break_module_hash[g_PikaVMState.break_point_cnt] = h; + g_PikaVMState.break_point_pc[g_PikaVMState.break_point_cnt] = pc_break; + g_PikaVMState.break_point_cnt++; + return PIKA_RES_OK; +} + +PIKA_RES pika_debug_reset_break(char* module_name, int pc_break) { + if (!pika_debug_check_break(module_name, pc_break)) { + return PIKA_RES_OK; + } + Hash h = hash_time33(module_name); + for (int i = 0; i < g_PikaVMState.break_point_cnt; i++) { + if (g_PikaVMState.break_module_hash[i] == h && + g_PikaVMState.break_point_pc[i] == pc_break) { + // Move subsequent break points one position forward + for (int j = i; j < g_PikaVMState.break_point_cnt - 1; j++) { + g_PikaVMState.break_module_hash[j] = + g_PikaVMState.break_module_hash[j + 1]; + g_PikaVMState.break_point_pc[j] = + g_PikaVMState.break_point_pc[j + 1]; + } + // Decrease the count of break points + g_PikaVMState.break_point_cnt--; + return PIKA_RES_OK; + } + } + return PIKA_RES_ERR_RUNTIME_ERROR; +} + static VMParameters* _pikaVM_runByteCodeFrameWithState( PikaObj* self, VMParameters* locals, @@ -4402,6 +4590,16 @@ VMParameters* _pikaVM_runByteCodeFrame(PikaObj* self, 0, &vm_thread, in_repl); } +VMParameters* _pikaVM_runByteCodeFrameGlobals(PikaObj* self, + PikaObj* globals, + ByteCodeFrame* byteCode_frame, + pika_bool in_repl) { + PikaVMThread vm_thread = {.try_state = TRY_STATE_NONE, + .try_result = TRY_RESULT_NONE}; + return __pikaVM_runByteCodeFrameWithState( + self, self, globals, byteCode_frame, 0, &vm_thread, in_repl); +} + VMParameters* pikaVM_runByteCodeFrame(PikaObj* self, ByteCodeFrame* byteCode_frame) { return _pikaVM_runByteCodeFrame(self, byteCode_frame, pika_false); diff --git a/src/PikaVM.h b/src/PikaVM.h index 439bddf54..c08923d17 100644 --- a/src/PikaVM.h +++ b/src/PikaVM.h @@ -95,8 +95,8 @@ typedef struct JmpBufCQ { } JmpBufCQ; #endif -typedef struct VMSignal VMSignal; -struct VMSignal { +typedef struct VMState VMState; +struct VMState { VM_SIGNAL_CTRL signal_ctrl; int vm_cnt; #if PIKA_EVENT_ENABLE @@ -106,6 +106,11 @@ struct VMSignal { pika_bool event_thread_exit; pika_bool event_thread_exit_done; #endif +#if PIKA_DEBUG_BREAK_POINT_MAX > 0 + Hash break_module_hash[PIKA_DEBUG_BREAK_POINT_MAX]; + uint32_t break_point_pc[PIKA_DEBUG_BREAK_POINT_MAX]; + int break_point_cnt; +#endif }; typedef Arg* (*VM_instruct_handler)(PikaObj* self, @@ -136,6 +141,10 @@ VMParameters* pikaVM_runAsm(PikaObj* self, char* pikaAsm); VMParameters* _pikaVM_runByteCodeFrame(PikaObj* self, ByteCodeFrame* byteCode_frame, pika_bool in_repl); +VMParameters* _pikaVM_runByteCodeFrameGlobals(PikaObj* self, + PikaObj* globals, + ByteCodeFrame* byteCode_frame, + pika_bool in_repl); VMParameters* pikaVM_runByteCodeFrame(PikaObj* self, ByteCodeFrame* byteCode_frame); @@ -208,6 +217,14 @@ static inline char* PikaVMFrame_getConstWithInstructUnit( instructUnit_getConstPoolIndex(ins_unit)); } +pika_bool PikaVMFrame_checkBreakPoint(PikaVMFrame* vm); + +typedef struct { + PikaObj* globals; + pika_bool in_repl; + char* module_name; +} pikaVM_run_ex_cfg; + char* constPool_getNow(ConstPool* self); char* constPool_getNext(ConstPool* self); char* constPool_getByIndex(ConstPool* self, uint16_t index); @@ -215,6 +232,7 @@ void constPool_print(ConstPool* self); void byteCodeFrame_init(ByteCodeFrame* bf); void byteCodeFrame_deinit(ByteCodeFrame* bf); +void byteCodeFrame_setName(ByteCodeFrame* self, char* name); size_t byteCodeFrame_getSize(ByteCodeFrame* bf); InstructUnit* byteCodeFrame_findInstructUnit(ByteCodeFrame* bcframe, int32_t iPcStart, @@ -229,6 +247,7 @@ InstructUnit* byteCodeFrame_findInsForward(ByteCodeFrame* bcframe, int32_t pc_start, enum InstructIndex index, int32_t* p_offset); +Hash byteCodeFrame_getNameHash(ByteCodeFrame* bcframe); void instructArray_init(InstructArray* ins_array); void instructArray_deinit(InstructArray* ins_array); void instructArray_append(InstructArray* ins_array, InstructUnit* ins_unit); @@ -287,13 +306,13 @@ VMParameters* pikaVM_runByteCodeInconstant(PikaObj* self, uint8_t* bytecode); Arg* pikaVM_runByteCodeReturn(PikaObj* self, const uint8_t* bytecode, char* returnName); -Arg* _do_pikaVM_runByteCodeReturn(PikaObj* self, - VMParameters* locals, - VMParameters* globals, - uint8_t* bytecode, - PikaVMThread* vm_thread, - pika_bool is_const_bytecode, - char* return_name); +Arg* pikaVM_runByteCode_exReturn(PikaObj* self, + VMParameters* locals, + VMParameters* globals, + uint8_t* bytecode, + PikaVMThread* vm_thread, + pika_bool is_const_bytecode, + char* return_name); InstructUnit* instructArray_getNow(InstructArray* self); InstructUnit* instructArray_getNext(InstructArray* self); VMParameters* pikaVM_runSingleFile(PikaObj* self, char* filename); @@ -306,14 +325,22 @@ Arg* _vm_slice(PikaVMFrame* vm, Arg* obj, Arg* start, int step); -VMParameters* _do_pikaVM_runByteCode(PikaObj* self, - VMParameters* locals, - VMParameters* globals, - uint8_t* bytecode, - PikaVMThread* vm_thread, - pika_bool is_const_bytecode); + +typedef struct { + VMParameters* locals; + VMParameters* globals; + char* name; + PikaVMThread* vm_thread; + pika_bool is_const_bytecode; +} pikaVM_runBytecode_ex_cfg; + +VMParameters* pikaVM_runByteCode_ex(PikaObj* self, + uint8_t* bytecode, + pikaVM_runBytecode_ex_cfg* cfg); + void _do_byteCodeFrame_loadByteCode(ByteCodeFrame* self, uint8_t* bytes, + char* name, pika_bool is_const); Arg* _vm_get(PikaVMFrame* vm, PikaObj* self, Arg* key, Arg* obj); VM_SIGNAL_CTRL VMSignal_getCtrl(void); @@ -332,6 +359,11 @@ void __VMEvent_pickupEvent(char* info); void _pikaVM_yield(void); int _VM_lock_init(void); int _VM_is_first_lock(void); +PIKA_RES pika_debug_set_break(char* module_name, int pc_break); +void pika_debug_set_trace(PikaObj* self); +PIKA_RES pika_debug_reset_break(char* module_name, int pc_break); +pika_bool pika_debug_check_break_hash(Hash module_hash, int pc_break); +pika_bool pika_debug_check_break(char* module_name, int pc_break); #define _VMEvent_pickupEvent() __VMEvent_pickupEvent(__FILE__) @@ -339,9 +371,9 @@ typedef struct { PikaObj* lreg[PIKA_REGIST_SIZE]; } VMLocals; -VMParameters* _pikaVM_runPyLines(PikaObj* self, - char* py_lines, - pika_bool in_repl); +VMParameters* pikaVM_run_ex(PikaObj* self, + char* py_lines, + pikaVM_run_ex_cfg* cfg); #endif diff --git a/src/PikaVersion.h b/src/PikaVersion.h index 41b933a11..4a0741f56 100644 --- a/src/PikaVersion.h +++ b/src/PikaVersion.h @@ -2,4 +2,4 @@ #define PIKA_VERSION_MINOR 12 #define PIKA_VERSION_MICRO 6 -#define PIKA_EDIT_TIME "2023/09/27 22:21:23" +#define PIKA_EDIT_TIME "2023/09/30 00:30:20" diff --git a/src/pika_config_valid.h b/src/pika_config_valid.h index b8ce24412..e6435845a 100644 --- a/src/pika_config_valid.h +++ b/src/pika_config_valid.h @@ -290,6 +290,10 @@ extern "C" { #define PIKA_DEBUG_ENABLE 0 #endif + #ifndef PIKA_DEBUG_BREAK_POINT_MAX + #define PIKA_DEBUG_BREAK_POINT_MAX 8 + #endif + #ifndef PIKA_FILEIO_ENABLE #define PIKA_FILEIO_ENABLE 1 #endif diff --git a/tools/pikaByteCodeGen/main.c b/tools/pikaByteCodeGen/main.c index cc0c61934..6eaa38902 100644 --- a/tools/pikaByteCodeGen/main.c +++ b/tools/pikaByteCodeGen/main.c @@ -40,7 +40,7 @@ void PikaStdData_List___init__(PikaObj *self) {} void PikaStdData_List_append(PikaObj *self, Arg *arg) {} void PikaStdData_Dict___init__(PikaObj *self) {} void PikaStdData_Dict_set(PikaObj *self, char *key, Arg *val) {} -PikaObj *New_builtins_object(Args *args){return NULL;}; +PikaObj *New_builtins_object(Args *args) { return NULL; }; PikaObj *New_PikaStdLib_SysObj(Args *args) { return NULL; }; PikaObj *New_builtins(Args *args) { return NULL; }; PikaObj *New_builtins_RangeObj(Args *args) { return NULL; } @@ -50,6 +50,23 @@ char *string_slice(Args *outBuffs, char *str, int start, int end) { } int PikaStdData_FILEIO_init(PikaObj *self, char *path, char *mode) { return 0; } +static int handle_breakpoint_option(int argc, char **argv, int i) { + if (0 == strcmp(argv[i], "--break-point")) { + if (i + 2 < argc) { + uint32_t pc = + pika_debug_find_break_point_pc(argv[i + 1], atoi(argv[i + 2])); + // printf("break point pc: %d\r\n", pc); + /* json output */ + printf("{\"pc\":%d}\r\n", pc); + return 0; + } else { + printf("Invalid --break-point option usage.\n"); + return -1; + } + } + return -1; +} + static int _do_main(int argc, char **argv) { int parc = argc - 1; PikaMaker *maker = New_PikaMaker(); @@ -68,6 +85,11 @@ static int _do_main(int argc, char **argv) { /* delete --xxx yyy */ for (int i = 1; i < argc; i++) { + int res = handle_breakpoint_option(argc, argv, i); + if (0 == res) { + return 0; + } + if (0 == strcmp(argv[i], "--add-file")) { // printf("before delete: %d\r\n", parc); // for (int j = 0; j < parc; j++) { diff --git a/tools/pikaCompiler/rust-msc-latest-win10.exe b/tools/pikaCompiler/rust-msc-latest-win10.exe index a568d88b8..1fdc0b1b3 100644 Binary files a/tools/pikaCompiler/rust-msc-latest-win10.exe and b/tools/pikaCompiler/rust-msc-latest-win10.exe differ