From b9f53f71fbd49e06a33c327ddc96655e35094655 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Tue, 1 Nov 2016 08:40:16 -0700 Subject: [PATCH] Reset API stack a fiber is aborted from wrenCall(). --- src/vm/wren_vm.c | 1 + test/api/main.c | 12 ++++++-- test/api/reset_stack_after_call_abort.c | 28 +++++++++++++++++++ test/api/reset_stack_after_call_abort.h | 3 ++ test/api/reset_stack_after_call_abort.wren | 14 ++++++++++ .../api/reset_stack_after_foreign_construct.c | 2 +- util/test.py | 9 +++--- util/xcode/wren.xcodeproj/project.pbxproj | 6 ++++ 8 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 test/api/reset_stack_after_call_abort.c create mode 100644 test/api/reset_stack_after_call_abort.h create mode 100644 test/api/reset_stack_after_call_abort.wren diff --git a/src/vm/wren_vm.c b/src/vm/wren_vm.c index bac89fe0..98cddbf4 100644 --- a/src/vm/wren_vm.c +++ b/src/vm/wren_vm.c @@ -400,6 +400,7 @@ static void runtimeError(WrenVM* vm) // If we got here, nothing caught the error, so show the stack trace. wrenDebugPrintStackTrace(vm); vm->fiber = NULL; + vm->apiStack = NULL; } // Aborts the current fiber with an appropriate method not found error for a diff --git a/test/api/main.c b/test/api/main.c index 6306418d..8647b8f4 100644 --- a/test/api/main.c +++ b/test/api/main.c @@ -12,6 +12,7 @@ #include "handle.h" #include "lists.h" #include "new_vm.h" +#include "reset_stack_after_call_abort.h" #include "reset_stack_after_foreign_construct.h" #include "slots.h" @@ -87,8 +88,15 @@ static WrenForeignClassMethods bindForeignClass( } static void afterLoad(WrenVM* vm) { - if (strstr(testName, "/call.wren") != NULL) callRunTests(vm); - if (strstr(testName, "/reset_stack_after_foreign_construct.wren") != NULL) + if (strstr(testName, "/call.wren") != NULL) + { + callRunTests(vm); + } + else if (strstr(testName, "/reset_stack_after_call_abort.wren") != NULL) + { + resetStackAfterCallAbortRunTests(vm); + } + else if (strstr(testName, "/reset_stack_after_foreign_construct.wren") != NULL) { resetStackAfterForeignConstructRunTests(vm); } diff --git a/test/api/reset_stack_after_call_abort.c b/test/api/reset_stack_after_call_abort.c new file mode 100644 index 00000000..8136796e --- /dev/null +++ b/test/api/reset_stack_after_call_abort.c @@ -0,0 +1,28 @@ +#include +#include + +#include "wren.h" + +void resetStackAfterCallAbortRunTests(WrenVM* vm) +{ + wrenEnsureSlots(vm, 1); + wrenGetVariable(vm, "main", "Test", 0); + WrenHandle* testClass = wrenGetSlotHandle(vm, 0); + + WrenHandle* abortFiber = wrenMakeCallHandle(vm, "abortFiber()"); + WrenHandle* afterConstruct = wrenMakeCallHandle(vm, "afterAbort(_,_)"); + + wrenEnsureSlots(vm, 1); + wrenSetSlotHandle(vm, 0, testClass); + wrenCall(vm, abortFiber); + + wrenEnsureSlots(vm, 3); + wrenSetSlotHandle(vm, 0, testClass); + wrenSetSlotDouble(vm, 1, 1.0); + wrenSetSlotDouble(vm, 2, 2.0); + wrenCall(vm, afterConstruct); + + wrenReleaseHandle(vm, testClass); + wrenReleaseHandle(vm, abortFiber); + wrenReleaseHandle(vm, afterConstruct); +} \ No newline at end of file diff --git a/test/api/reset_stack_after_call_abort.h b/test/api/reset_stack_after_call_abort.h new file mode 100644 index 00000000..bc4b5480 --- /dev/null +++ b/test/api/reset_stack_after_call_abort.h @@ -0,0 +1,3 @@ +#include "wren.h" + +void resetStackAfterCallAbortRunTests(WrenVM* vm); \ No newline at end of file diff --git a/test/api/reset_stack_after_call_abort.wren b/test/api/reset_stack_after_call_abort.wren new file mode 100644 index 00000000..fc91178b --- /dev/null +++ b/test/api/reset_stack_after_call_abort.wren @@ -0,0 +1,14 @@ +// Regression test. +// +// If you invoked some code with wrenCall() and that code aborted the current +// fiber, it did not reset the API stack. If you tried to immediately reuse the +// API stack by calling wrenCall(), it would be in a broken state. +class Test { + static abortFiber() { + Fiber.abort("Abort!") // expect handled runtime error: Abort! + } + + static afterAbort(a, b) { + System.print(a + b) // expect: 3 + } +} diff --git a/test/api/reset_stack_after_foreign_construct.c b/test/api/reset_stack_after_foreign_construct.c index 78075293..f24783d8 100644 --- a/test/api/reset_stack_after_foreign_construct.c +++ b/test/api/reset_stack_after_foreign_construct.c @@ -1,7 +1,7 @@ #include #include -#include "foreign_class.h" +#include "wren.h" static void counterAllocate(WrenVM* vm) { diff --git a/util/test.py b/util/test.py index 8f3fc1d3..cdd033ed 100755 --- a/util/test.py +++ b/util/test.py @@ -18,7 +18,7 @@ TEST_APP = join(WREN_DIR, 'build', 'debug', 'test', 'wrend') EXPECT_PATTERN = re.compile(r'// expect: ?(.*)') EXPECT_ERROR_PATTERN = re.compile(r'// expect error(?! line)') EXPECT_ERROR_LINE_PATTERN = re.compile(r'// expect error line (\d+)') -EXPECT_RUNTIME_ERROR_PATTERN = re.compile(r'// expect runtime error: (.+)') +EXPECT_RUNTIME_ERROR_PATTERN = re.compile(r'// expect (handled )?runtime error: (.+)') ERROR_PATTERN = re.compile(r'\[.* line (\d+)\] Error') STACK_TRACE_PATTERN = re.compile(r'\[main line (\d+)\] in') STDIN_PATTERN = re.compile(r'// stdin: (.*)') @@ -77,9 +77,10 @@ class Test: match = EXPECT_RUNTIME_ERROR_PATTERN.search(line) if match: self.runtime_error_line = line_num - self.runtime_error_message = match.group(1) - # If we expect a runtime error, it should exit with EX_SOFTWARE. - self.exit_code = 70 + self.runtime_error_message = match.group(2) + # If the runtime error isn't handled, it should exit with EX_SOFTWARE. + if match.group(1) != "handled ": + self.exit_code = 70 expectations += 1 match = STDIN_PATTERN.search(line) diff --git a/util/xcode/wren.xcodeproj/project.pbxproj b/util/xcode/wren.xcodeproj/project.pbxproj index 95dec647..d82494c8 100644 --- a/util/xcode/wren.xcodeproj/project.pbxproj +++ b/util/xcode/wren.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ 29D025E41C19CD1000A3BB28 /* os.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D025E01C19CD1000A3BB28 /* os.c */; }; 29D025E51C19CD1000A3BB28 /* os.wren.inc in Sources */ = {isa = PBXBuildFile; fileRef = 29D025E21C19CD1000A3BB28 /* os.wren.inc */; }; 29D025E61C19CD1000A3BB28 /* os.wren.inc in Sources */ = {isa = PBXBuildFile; fileRef = 29D025E21C19CD1000A3BB28 /* os.wren.inc */; }; + 29D880661DC8ECF600025364 /* reset_stack_after_call_abort.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D880641DC8ECF600025364 /* reset_stack_after_call_abort.c */; }; 29DC149F1BBA2FCC008A8274 /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29C8A9311AB71FFF00DEC81D /* vm.c */; }; 29DC14A01BBA2FD6008A8274 /* timer.c in Sources */ = {isa = PBXBuildFile; fileRef = 2901D7621B74F4050083A2C8 /* timer.c */; }; 29DC14A11BBA2FEC008A8274 /* scheduler.c in Sources */ = {isa = PBXBuildFile; fileRef = 291647C21BA5EA45006142EE /* scheduler.c */; }; @@ -151,6 +152,8 @@ 29D025E01C19CD1000A3BB28 /* os.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = os.c; path = ../../src/module/os.c; sourceTree = ""; }; 29D025E11C19CD1000A3BB28 /* os.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = os.h; path = ../../src/module/os.h; sourceTree = ""; }; 29D025E21C19CD1000A3BB28 /* os.wren.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = os.wren.inc; path = ../../src/module/os.wren.inc; sourceTree = ""; }; + 29D880641DC8ECF600025364 /* reset_stack_after_call_abort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = reset_stack_after_call_abort.c; path = ../../test/api/reset_stack_after_call_abort.c; sourceTree = ""; }; + 29D880651DC8ECF600025364 /* reset_stack_after_call_abort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reset_stack_after_call_abort.h; path = ../../test/api/reset_stack_after_call_abort.h; sourceTree = ""; }; 29F384111BD19706002F84E0 /* io.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = io.h; path = ../../src/module/io.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -294,6 +297,8 @@ 29932D531C210F8D00099DEE /* lists.h */, 29C946961C88F14F00B4A4F3 /* new_vm.c */, 29C946971C88F14F00B4A4F3 /* new_vm.h */, + 29D880641DC8ECF600025364 /* reset_stack_after_call_abort.c */, + 29D880651DC8ECF600025364 /* reset_stack_after_call_abort.h */, 29C80D581D73332A00493837 /* reset_stack_after_foreign_construct.c */, 29C80D591D73332A00493837 /* reset_stack_after_foreign_construct.h */, 29D009AA1B7E39A8000CE58C /* slots.c */, @@ -415,6 +420,7 @@ 29DC14A11BBA2FEC008A8274 /* scheduler.c in Sources */, 29A427391BDBE435001E6E22 /* wren_opt_random.c in Sources */, 293B255A1CEFD8C7005D9537 /* repl.wren.inc in Sources */, + 29D880661DC8ECF600025364 /* reset_stack_after_call_abort.c in Sources */, 29932D511C20D8C900099DEE /* benchmark.c in Sources */, 29DC14A01BBA2FD6008A8274 /* timer.c in Sources */, 29DC149F1BBA2FCC008A8274 /* vm.c in Sources */,