diff --git a/tests/api/test-dev-return-types.c b/tests/api/test-dev-return-types.c new file mode 100644 index 00000000..f5b389ad --- /dev/null +++ b/tests/api/test-dev-return-types.c @@ -0,0 +1,159 @@ +/* + * Supporting testcase for test-dev-return-types.js: cover return types + * which can't be exercised from Ecmascript code. + */ + +/*=== +*** test_basic_implicit (duk_safe_call) +inside func +result: undefined +final top: 0 +==> rc=0, result='undefined' +*** test_basic_explicit (duk_safe_call) +inside func +result: 123 +final top: 0 +==> rc=0, result='undefined' +*** test_endfin_return (duk_safe_call) +finally +result: 321 +final top: 0 +==> rc=0, result='undefined' +inside func +result: undefined +inside func +result: undefined +inside func +result: 123 +inside func +result: 123 +finally +result: 321 +finally +result: 321 +final top: 0 +===*/ + +/* Normal call from a duk_safe_call() wrapper, implicit return value. */ +static duk_ret_t test_basic_implicit(duk_context *ctx) { + duk_eval_string(ctx, + "(function () {\n" + " print('inside func');\n" + "})"); + duk_call(ctx, 0); + printf("result: %s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + + printf("final top: %ld\n", (long) duk_get_top(ctx)); + return 0; +} + +/* Normal call from a duk_safe_call() wrapper, explicit return value. */ +static duk_ret_t test_basic_explicit(duk_context *ctx) { + duk_eval_string(ctx, + "(function () {\n" + " print('inside func');\n" + " return 123;\n" + "})"); + duk_call(ctx, 0); + printf("result: %s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + + printf("final top: %ld\n", (long) duk_get_top(ctx)); + return 0; +} + +/* Ecmascript finally captures return and the return is propagated + * onwards after finally finishes. + */ +static duk_ret_t test_endfin_return(duk_context *ctx) { + duk_eval_string(ctx, + "(function () {\n" + " try {\n" + " return 321;\n" + " } finally {\n" + " print('finally');\n" + " }\n" + " print('never here');\n" + "})"); + duk_call(ctx, 0); + printf("result: %s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + + printf("final top: %ld\n", (long) duk_get_top(ctx)); + return 0; +} + +void test(duk_context *ctx) { + TEST_SAFE_CALL(test_basic_implicit); + TEST_SAFE_CALL(test_basic_explicit); + TEST_SAFE_CALL(test_endfin_return); + + /* Top level unprotected call + return with implicit value. */ + duk_eval_string(ctx, + "(function () {\n" + " print('inside func');\n" + "})"); + duk_call(ctx, 0); + printf("result: %s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + + /* Top level protected call + return with explicit value. */ + duk_eval_string(ctx, + "(function () {\n" + " print('inside func');\n" + "})"); + (void) duk_pcall(ctx, 0); + printf("result: %s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + + /* Top level unprotected call + return with explicit value. */ + duk_eval_string(ctx, + "(function () {\n" + " print('inside func');\n" + " return 123;\n" + "})"); + duk_call(ctx, 0); + printf("result: %s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + + /* Top level protected call + return with explicit value. */ + duk_eval_string(ctx, + "(function () {\n" + " print('inside func');\n" + " return 123;\n" + "})"); + duk_pcall(ctx, 0); + printf("result: %s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + + /* ENDFIN + RETURN case directly from top level, unprotected call. */ + duk_eval_string(ctx, + "(function () {\n" + " try {\n" + " return 321;\n" + " } finally {\n" + " print('finally');\n" + " }\n" + " print('never here');\n" + "})"); + duk_call(ctx, 0); + printf("result: %s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + + /* ENDFIN + RETURN case directly from top level, protected call. */ + duk_eval_string(ctx, + "(function () {\n" + " try {\n" + " return 321;\n" + " } finally {\n" + " print('finally');\n" + " }\n" + " print('never here');\n" + "})"); + duk_pcall(ctx, 0); + printf("result: %s\n", duk_safe_to_string(ctx, -1)); + duk_pop(ctx); + + printf("final top: %ld\n", (long) duk_get_top(ctx)); +} diff --git a/tests/api/test-dump-load-basic.c b/tests/api/test-dump-load-basic.c index 9f6f0fe6..d4021553 100644 --- a/tests/api/test-dump-load-basic.c +++ b/tests/api/test-dump-load-basic.c @@ -40,7 +40,7 @@ /*=== *** test_basic (duk_safe_call) dump result type: 7 -ff000000000e0000000300000001000900000000000100000001300004c0000000f300400052000040c200000114000101400001414c800041c3800082030101403000014100000081420180403000004000000000ef00000000057072696e74000000000568656c6c6f0140091eb851eb851f000000030000000000000000000300020000000100000001300604400080009a000080ef0000006f000000020000000561646465720000000f66616b6546696c656e616d652e6a730000000d03000000010000000c000000000000000178000000000000000179000000010000000000000001780000000179000000000000000000000006676c6f62616c0000000f66616b6546696c656e616d652e6a730000000e0e000000010000000c00000000000000000000000000 +ff000000000e0000000300000001000900000000000100000001300004c0000000f300400052000040c200000114000101400001414c800041c38000820301014030000141000000814201804030000040000000006f00000000057072696e74000000000568656c6c6f0140091eb851eb851f000000030000000000000000000300020000000100000001300604400080009a0000806f0000002f000000020000000561646465720000000f66616b6546696c656e616d652e6a730000000d03000000010000000c000000000000000178000000000000000179000000010000000000000001780000000179000000000000000000000006676c6f62616c0000000f66616b6546696c656e616d652e6a730000000e0e000000010000000c00000000000000000000000000 load result type: 6 hello 3 3.14 call result type: 1 @@ -91,7 +91,7 @@ static duk_ret_t test_basic(duk_context *ctx) { /*=== *** test_mandel (duk_safe_call) Mandelbrot source length: 884 -ff000000006c000000100000000000140000000000010000001e300604c0801300038007004380190083000008338000196e800001ae80000403000400c00080c3ab0003802d800000ee800017ae0000c3b67ffffeae0080c39d8003839c8083839b00038200000048338000136e8000022e80000403000401000004423300044340000103ab0003802d800000ee8000112e000103b67ffffeae0001039d8103839c8183839b000381c00000883380000d6e8000032e800004030004014080000443000442408000048300048280000104c20004c180010143ab0003802d800000ee80000a2e000143b67ffffeae0482439c000382c00502839c000383000602c39a828383ab0003806d8000022e04c0c39c0503839c0403839a000382800602c39b0383839a000382407ffffbae810143ab0003806d800000ee00018382000381808000042e838143ab0003806d800000ee0002038200038180800002ae848143ab0003806d800000ee00028382000381808000012e0002c382000381808000006e7ffff62e0000887300034380000303c20783839800018400008380307fffef2e00004873004343920003440000038442088404180003c48200840030008380307fffe8ae000008730000006f014004000000000000013ff400000000000001400800000000000001400000000000000000000000012301401000000000000000000000012e01401400000000000000000000012c01402400000000000000000000012d00000000013d00000000047075736800000000057072696e7400000000046a6f696e000000000000000000000000066d616e64656c000000096d616e64656c2e6a730000002a6c00000002000000140000000f0000002000000028801004002008000409100022420100822501080210000000017700000000000000016800000001000000046974657200000002000000016900000003000000016a00000004000000016b000000050000000163000000060000000278300000000700000002793000000008000000027878000000090000000279790000000a000000037878320000000b000000037979320000000c000000046c696e650000000d0000000000000000 +ff000000006c000000100000000000140000000000010000001e300604c0801300038007004380190083000008338000196e800001ae80000403000400c00080c3ab0003802d800000ee800017ae0000c3b67ffffeae0080c39d8003839c8083839b00038200000048338000136e8000022e80000403000401000004423300044340000103ab0003802d800000ee8000112e000103b67ffffeae0001039d8103839c8183839b000381c00000883380000d6e8000032e800004030004014080000443000442408000048300048280000104c20004c180010143ab0003802d800000ee80000a2e000143b67ffffeae0482439c000382c00502839c000383000602c39a828383ab0003806d8000022e04c0c39c0503839c0403839a000382800602c39b0383839a000382407ffffbae810143ab0003806d800000ee00018382000381808000042e838143ab0003806d800000ee0002038200038180800002ae848143ab0003806d800000ee00028382000381808000012e0002c382000381808000006e7ffff62e0000887300034380000303c20783839800018400008380307fffef2e00004873004343920003440000038442088404180003c48200840030008380307fffe8ae000008730000002f014004000000000000013ff400000000000001400800000000000001400000000000000000000000012301401000000000000000000000012e01401400000000000000000000012c01402400000000000000000000012d00000000013d00000000047075736800000000057072696e7400000000046a6f696e000000000000000000000000066d616e64656c000000096d616e64656c2e6a730000002a6c00000002000000140000000f0000002000000028801004002008000409100022420100822501080210000000017700000000000000016800000001000000046974657200000002000000016900000003000000016a00000004000000016b000000050000000163000000060000000278300000000700000002793000000008000000027878000000090000000279790000000a000000037878320000000b000000037979320000000c000000046c696e650000000d0000000000000000 ..........................,,,,,,,,,,,,,,,,,,,,,,,,,......................... ....................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,................... ................,,,,,,,,,,,,,,,,,,,,,,,,,,,---=----,,,,,,,,,,............... diff --git a/tests/ecmascript/test-dev-fast-return-cases.js b/tests/ecmascript/test-dev-return-cases.js similarity index 64% rename from tests/ecmascript/test-dev-fast-return-cases.js rename to tests/ecmascript/test-dev-return-cases.js index 3295cef9..f1ffcb55 100644 --- a/tests/ecmascript/test-dev-fast-return-cases.js +++ b/tests/ecmascript/test-dev-return-cases.js @@ -1,17 +1,5 @@ /* - * Exercise various code paths related to fast return handling. - * - * Duktape executor supports two kinds of return: - * - * - A slow return is implemented using longjmp() and handles all cases - * like label catchers, try-catch-finally blocks, etc. - * - * - A fast return avoids the longjmp() but is limited to common cases - * only. - * - * Longjmp has a moderate performance impact on normal platforms. However - * it has a much larger relative impact when Duktape is compiled with - * Emscripten. + * Exercise various code paths related to return handling. */ /*=== @@ -39,26 +27,27 @@ testTryFinally4 Error: canceled return still here returned 432 +testTryFinally5 +finally +returned 123 ===*/ -/* Basic case: fast return allowed. */ +/* Basic case. */ function testReturn1() { return 123; } -/* Basic case, implicit return value (undefined). Fast return allowed. */ +/* Basic case, implicit return value (undefined). */ function testReturn2() { return; } /* Basic case, implicit return value with no explicit return statement. - * Fast return allowed. */ function testReturn3() { } -/* Return from inside a label site (created by for-loop). Fast return - * is allowed for label catchers. +/* Return from inside a label site (created by for-loop). */ function testForLoop1() { for (;;) { @@ -66,9 +55,7 @@ function testForLoop1() { } } -/* Return from inside the try block of a try-catch is currently not a - * fast return. - * XXX: could allow if there's no finally clause? +/* Return from inside the try block of a try-catch. */ function testTryCatch1() { try { @@ -77,9 +64,7 @@ function testTryCatch1() { } } -/* Return from inside the catch block of a try-catch is currently not a - * fast return. - * XXX: could allow if there's no finally clause? +/* Return from inside the catch block of a try-catch. */ function testTryCatch2() { try { @@ -89,9 +74,7 @@ function testTryCatch2() { } } -/* Return from inside the try block of a try-finally is not a fast - * return because the finally block intercepts the return (and can - * even cancel it). +/* Return from inside the try block of a try-finally. */ function testTryFinally1() { try { @@ -110,10 +93,7 @@ function testTryFinally2() { } } -/* Return from inside the finally block of a try-finally is not a fast - * return. - * XXX: it could be, because there's no longer a chance of anyone - * catching the return. +/* Return from inside the finally block of a try-finally. */ function testTryFinally3() { try { @@ -141,6 +121,18 @@ function testTryFinally4() { return 432; } +function testTryFinally5() { + // Here 'finally' captures the return which then proceeds. + // This triggers the internal case where ENDFIN does RETURN handling + // which results in an executor restart. + try { + return 123; + } finally { + print('finally'); + } + print('never here'); +} + try { print('testReturn1'); print('returned', testReturn1()); @@ -171,6 +163,9 @@ try { print('testTryFinally4'); print('returned', testTryFinally4()); + + print('testTryFinally5'); + print('returned', testTryFinally5()); } catch (e) { print(e); } diff --git a/tests/perf/test-call-basic.js b/tests/perf/test-call-basic.js index ead4dc79..97c1a487 100644 --- a/tests/perf/test-call-basic.js +++ b/tests/perf/test-call-basic.js @@ -1,7 +1,5 @@ /* * Basic function call performance. - * - * Focuses on the cases where "fast returns" are possible. */ function test() { diff --git a/tests/perf/test-call-native.js b/tests/perf/test-call-native.js new file mode 100644 index 00000000..1a39b9b0 --- /dev/null +++ b/tests/perf/test-call-native.js @@ -0,0 +1,19 @@ +function test() { + var arr = []; + for (var i = 0; i < 1e3; i++) { + arr[i] = i; + } + for (var i = 0; i < 3e4; i++) { + // Each .forEach() call is a native call so that return 123 causes a + // return-to-native situation which was previously a longjmp. + + arr.forEach(function () { return 123; }); + } +} + +try { + test(); +} catch (e) { + print(e.stack || e); + throw e; +}