diff --git a/Changes.md b/Changes.md index 64b5fc29..d76013cc 100644 --- a/Changes.md +++ b/Changes.md @@ -2,6 +2,10 @@ libhxcpp 6.0.0 (unreleased) ------------------------------------------------------------ +* Fixed an exception from blit, setSize or resize under the cppia JIT ending the process instead of reaching the script's catch, on typed arrays and on Array: their native calls had no exception bridge. The script catches it, as it does interpreted and in compiled code (libhxcpp #404) +* Fixed resize() and cpp.NativeArray.setSize() on an Array under the cppia JIT evaluating the array expression twice, so a call in it ran twice and the array it returned the second time was the one resized. The JIT evaluates it once (libhxcpp #411) +* Fixed indexOf and lastIndexOf on an Array under the cppia JIT ignoring fromIndex: the JIT never generated it, so a call or exception in it was lost too. The search starts from it, as it does interpreted and in compiled code (libhxcpp #410) +* Fixed reverse() and resize() on an Array in interpreted cppia doing nothing: the interpreter had no case for them, and resize never evaluated its argument. They reverse and resize the array, as they do under the JIT and in compiled code (libhxcpp #409) * Added HXCPP_PROGRESS_PERCENT, which shows a group's compile progress as a percentage of its files, [42.5% ], instead of a count, [425/1000] * Fixed a program on Linux with glibc staying as large as its largest burst of large allocations, such as the files a game reads while it loads: glibc keeps a freed buffer's memory in its heap unless it had mapped the buffer on its own, and once a buffer mapped on its own has been freed it stops mapping those of that size or less, up to 32 MB. The memory of the large buffers a collection freed then stayed the process's. The collector now trims the C heap once 16 MB has been freed to it, on the thread that frees the buffers. A program that dropped 384 MB of 4 MB buffers stayed at 396 MB resident and now returns to 12 MB * Fixed a native extension that includes hx/CFFI.h before hx/CFFIPrime.h, as SteamWrap does, failing to compile with hxs_encoding, hxs_utf16 and alloc_hxs_utf8 not declared: CFFI.h included first declares the CFFI API without HXCPP_PRIME, so without the Prime string functions that the ordinary wrapper of a DEFINE_PRIME function now uses. CFFIPrime.h declares them then diff --git a/src/hx/cppia/ArrayBuiltin.cpp b/src/hx/cppia/ArrayBuiltin.cpp index 9e7ee958..6ecf7e99 100644 --- a/src/hx/cppia/ArrayBuiltin.cpp +++ b/src/hx/cppia/ArrayBuiltin.cpp @@ -99,6 +99,35 @@ static ArrayBase * SLJIT_CALL array_expand_size(ArrayBase *inArray, int inSize) return inArray; } +// blit, __SetSizeExact and resize throw for a range or size the array cannot +// take, and the exception becomes the script's pending one, which the code +// after the call checks. They are ArrayBase's whatever the element type, so +// each is one function here: a copy for every element type and builtin, each +// with its own exception handling, would take more sections than MSVC's +// object file format allows. +static void SLJIT_CALL array_set_size_exact(ArrayBase *inArray, int inSize) +{ + TRY_NATIVE + inArray->__SetSizeExact(inSize); + CATCH_NATIVE +} + +static void SLJIT_CALL array_resize(ArrayBase *inArray, int inSize) +{ + TRY_NATIVE + inArray->resize(inSize); + CATCH_NATIVE +} + +static void SLJIT_CALL array_blit(JitMultiArg *inArgs) +{ + // this, inDestElement, inSourceArray, inSourceElement, inElementCount + TRY_NATIVE + ArrayBase *dest = (ArrayBase *)inArgs[0].obj; + dest->Blit( inArgs[1].ival, (ArrayBase *)inArgs[2].obj, inArgs[3].ival, inArgs[4].ival ); + CATCH_NATIVE +} + #endif @@ -1245,16 +1274,6 @@ struct ArrayBuiltin : public ArrayBuiltinBase return inArray->keyValueIterator().mPtr; } - static void SLJIT_CALL runSetSizeExact( Array_obj *inArray, int size ) - { - inArray->__SetSizeExact(size); - } - - static void SLJIT_CALL runResize( Array_obj *inArray, int size ) - { - inArray->resize(size); - } - static void SLJIT_CALL runToString( Array_obj *inArray, String *outString ) { @@ -1268,14 +1287,6 @@ struct ArrayBuiltin : public ArrayBuiltinBase return inArray->copy().mPtr; } - static void SLJIT_CALL runBlit( JitMultiArg *inArgs) - { - // this, inDestElement, inSourceArray, inSourceElement, inElementCount - Array_obj *dest = (Array_obj *)inArgs[0].obj; - Array_obj *src = (Array_obj *)inArgs[2].obj; - dest->blit( inArgs[1].ival, src, inArgs[3].ival, inArgs[4].ival ); - } - static hx::Object * SLJIT_CALL runProcess( Array_obj *inArray, hx::Object *inFunction) { @@ -1891,7 +1902,8 @@ struct ArrayBuiltin : public ArrayBuiltinBase thisExpr->genCode(compiler, thisVal, etObject); genNullReferenceExceptionCheck(compiler, thisVal); args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt); - compiler->callNative( (void *)runSetSizeExact, thisVal, sJitArg1.as(jtInt)); + compiler->callNative( (void *)array_set_size_exact, thisVal, sJitArg1.as(jtInt)); + compiler->checkException(); break; } @@ -1901,7 +1913,8 @@ struct ArrayBuiltin : public ArrayBuiltinBase thisExpr->genCode(compiler, thisVal, etObject); genNullReferenceExceptionCheck(compiler, thisVal); args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt); - compiler->callNative( (void *)runResize, thisVal, sJitArg1.as(jtInt)); + compiler->callNative( (void *)array_resize, thisVal, sJitArg1.as(jtInt)); + compiler->checkException(); break; } @@ -1916,7 +1929,8 @@ struct ArrayBuiltin : public ArrayBuiltinBase args[1]->genCode(compiler, fargs.arg(2,jtPointer), etObject); args[2]->genCode(compiler, fargs.arg(3,jtInt), etInt); args[3]->genCode(compiler, fargs.arg(4,jtInt), etInt); - compiler->callNative( (void *)runBlit, fargs ); + compiler->callNative( (void *)array_blit, fargs ); + compiler->checkException(); break; } diff --git a/src/hx/cppia/ArrayVirtual.cpp b/src/hx/cppia/ArrayVirtual.cpp index 4370d6d6..04500f96 100644 --- a/src/hx/cppia/ArrayVirtual.cpp +++ b/src/hx/cppia/ArrayVirtual.cpp @@ -26,13 +26,19 @@ static hx::Object * SLJIT_CALL arrayConcat(ArrayAnyImpl *inObj, hx::Object *inVa { return inObj->concat(Dynamic(inValue)).mPtr; } +// These throw for a size or range the array cannot take: the exception becomes +// the script's pending one, which the code after the call checks static void SLJIT_CALL arraySetSizeExact(ArrayAnyImpl *inObj, int inSize) { + TRY_NATIVE inObj->__SetSizeExact(inSize); + CATCH_NATIVE } static void SLJIT_CALL arrayResize(ArrayAnyImpl *inObj, int inSize) { + TRY_NATIVE inObj->resize(inSize); + CATCH_NATIVE } @@ -142,9 +148,11 @@ static void SLJIT_CALL arrayUnshiftString( ArrayAnyImpl *inArray, String *inVal) static void SLJIT_CALL runBlit( JitMultiArg *inArgs) { // this, inDestElement, inSourceArray, inSourceElement, inElementCount + TRY_NATIVE ArrayAnyImpl *dest = (ArrayAnyImpl *)inArgs[0].obj; ArrayAnyImpl *src = (ArrayAnyImpl *)inArgs[2].obj; dest->blit( inArgs[1].ival, src, inArgs[3].ival, inArgs[4].ival ); + CATCH_NATIVE } @@ -261,7 +269,8 @@ struct ArrayBuiltinAny : public ArrayBuiltinBase if (FUNC==afJoin || FUNC==afToString) return Dynamic(runString(ctx)).mPtr; - if (FUNC==afSort || FUNC==afInsert || FUNC==afUnshift || FUNC==af__SetSizeExact || FUNC==afBlit) + if (FUNC==afSort || FUNC==afInsert || FUNC==afUnshift || FUNC==af__SetSizeExact || FUNC==afBlit || + FUNC==afReverse || FUNC==afResize) { runVoid(ctx); return 0; @@ -456,6 +465,24 @@ struct ArrayBuiltinAny : public ArrayBuiltinBase thisVal->__SetSizeExact(size); return; } + if (FUNC==afResize) + { + ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx); + BCR_VCHECK; + CPPIA_CHECK(thisVal); + int size = args[0]->runInt(ctx); + BCR_VCHECK; + thisVal->CALL(resize)(size); + return; + } + if (FUNC==afReverse) + { + ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx); + BCR_VCHECK; + CPPIA_CHECK(thisVal); + thisVal->CALL(reverse)(); + return; + } if (FUNC==afBlit) { ArrayAnyImpl *thisVal = (ArrayAnyImpl *)thisExpr->runObject(ctx); @@ -586,6 +613,8 @@ struct ArrayBuiltinAny : public ArrayBuiltinBase case afUnshift: case af__SetSizeExact: case afBlit: + case afReverse: + case afResize: return etVoid; case afPush: @@ -623,14 +652,14 @@ struct ArrayBuiltinAny : public ArrayBuiltinBase return 0; } - static int SLJIT_CALL runIndexOf( ArrayAnyImpl *inArray, hx::Object *inItem) + static int SLJIT_CALL runIndexOf( ArrayAnyImpl *inArray, hx::Object *inItem, hx::Object *inFrom) { - return inArray->indexOf(inItem); + return inArray->indexOf(inItem, inFrom); } - static int SLJIT_CALL runLastIndexOf( ArrayAnyImpl *inArray, hx::Object *inItem) + static int SLJIT_CALL runLastIndexOf( ArrayAnyImpl *inArray, hx::Object *inItem, hx::Object *inFrom) { - return inArray->lastIndexOf(inItem); + return inArray->lastIndexOf(inItem, inFrom); } @@ -727,8 +756,11 @@ struct ArrayBuiltinAny : public ArrayBuiltinBase case afIndexOf: case afLastIndexOf: { - args[0]->genCode(compiler, sJitArg1.as(jtPointer), etObject); - compiler->callNative( (void *)(FUNC==afIndexOf ? runIndexOf : runLastIndexOf), thisVal, sJitArg1.as(jtPointer)); + // The item, then fromIndex, which is null when the call leaves it out + JitTemp item(compiler,etObject); + args[0]->genCode(compiler, item, etObject); + args[1]->genCode(compiler, sJitArg2, etObject); + compiler->callNative( (void *)(FUNC==afIndexOf ? runIndexOf : runLastIndexOf), thisVal, item.as(jtPointer), sJitArg2.as(jtPointer)); compiler->convertReturnReg(etInt, inDest, destType ); } break; @@ -754,23 +786,19 @@ struct ArrayBuiltinAny : public ArrayBuiltinBase } break; + // The array is thisVal, evaluated and checked above: evaluating it + // again would run its side effects twice case af__SetSizeExact: - { - JitTemp thisVal(compiler,jtPointer); - thisExpr->genCode(compiler, thisVal, etObject); - args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt); - compiler->callNative( (void *)arraySetSizeExact, thisVal, sJitArg1.as(jtInt)); - break; - } + args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt); + compiler->callNative( (void *)arraySetSizeExact, thisVal, sJitArg1.as(jtInt)); + compiler->checkException(); + break; case afResize: - { - JitTemp thisVal(compiler,jtPointer); - thisExpr->genCode(compiler, thisVal, etObject); - args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt); - compiler->callNative( (void *)arrayResize, thisVal, sJitArg1.as(jtInt)); - break; - } + args[0]->genCode(compiler, sJitArg1.as(jtInt), etInt); + compiler->callNative( (void *)arrayResize, thisVal, sJitArg1.as(jtInt)); + compiler->checkException(); + break; case afBlit: { @@ -784,6 +812,7 @@ struct ArrayBuiltinAny : public ArrayBuiltinBase args[2]->genCode(compiler, fargs.arg(3,jtInt), etInt); args[3]->genCode(compiler, fargs.arg(4,jtInt), etInt); compiler->callNative( (void *)runBlit, fargs ); + compiler->checkException(); break; } diff --git a/test/regression/CppiaArrayHelperExceptions/Main.hx b/test/regression/CppiaArrayHelperExceptions/Main.hx new file mode 100644 index 00000000..e1b4cc7a --- /dev/null +++ b/test/regression/CppiaArrayHelperExceptions/Main.hx @@ -0,0 +1,13 @@ +// Runs the script interpreted and then under the JIT +function main() { + var script = haxe.io.Path.join([haxe.io.Path.directory(Sys.programPath()), "script.cppia"]); + for (jit in [false, true]) { + cpp.cppia.Host.enableJit(jit); + Sys.println(jit ? "jit" : "interpreted"); + try { + cpp.cppia.Host.runFile(script); + } catch (e:Dynamic) { + Sys.println("error: " + e); + } + } +} diff --git a/test/regression/CppiaArrayHelperExceptions/Script.hx b/test/regression/CppiaArrayHelperExceptions/Script.hx new file mode 100644 index 00000000..0c3bb4a9 --- /dev/null +++ b/test/regression/CppiaArrayHelperExceptions/Script.hx @@ -0,0 +1,57 @@ +// Under the JIT, an exception from blit, setSize or resize called directly in +// a try went past the script's catch and ended the host, on a typed array +// and on Array. Each one throws here, and the script catches it and +// finds the array as it was. A valid blit is the control. +class Script { + static function main() { + var dest = [7, 8]; + var source = [1, 2]; + var values = [7, 8]; + var anyDest:Array = [7, "eight"]; + var anySource:Array = [1, "two"]; + var any:Array = [7, "eight"]; + try { + cpp.NativeArray.blit(dest, 1, source, 0, 1); + Sys.println("valid blit: ran, " + dest); + } catch (e:Dynamic) { + Sys.println("valid blit: caught " + e + ", " + dest); + } + try { + cpp.NativeArray.blit(dest, -1, source, 0, 1); + Sys.println("blit: ran, " + dest); + } catch (e:Dynamic) { + Sys.println("blit: caught " + e + ", " + dest); + } + try { + cpp.NativeArray.setSize(values, -1); + Sys.println("setSize: ran, " + values); + } catch (e:Dynamic) { + Sys.println("setSize: caught " + e + ", " + values); + } + try { + values.resize(0x40000000); + Sys.println("resize: ran, " + values); + } catch (e:Dynamic) { + Sys.println("resize: caught " + e + ", " + values); + } + try { + cpp.NativeArray.blit(anyDest, -1, anySource, 0, 1); + Sys.println("dynamic blit: ran, " + anyDest); + } catch (e:Dynamic) { + Sys.println("dynamic blit: caught " + e + ", " + anyDest); + } + try { + cpp.NativeArray.setSize(any, -1); + Sys.println("dynamic setSize: ran, " + any); + } catch (e:Dynamic) { + Sys.println("dynamic setSize: caught " + e + ", " + any); + } + try { + any.resize(0x40000000); + Sys.println("dynamic resize: ran, " + any); + } catch (e:Dynamic) { + Sys.println("dynamic resize: caught " + e + ", " + any); + } + Sys.println("continued"); + } +} diff --git a/test/regression/CppiaArrayHelperExceptions/build.hxml b/test/regression/CppiaArrayHelperExceptions/build.hxml new file mode 100644 index 00000000..d20d36bd --- /dev/null +++ b/test/regression/CppiaArrayHelperExceptions/build.hxml @@ -0,0 +1,7 @@ +--main Script +-cppia bin/script.cppia +--next +--main Main +-cpp bin +-D scriptable +--dce no diff --git a/test/regression/CppiaArrayHelperExceptions/stdout.txt b/test/regression/CppiaArrayHelperExceptions/stdout.txt new file mode 100644 index 00000000..502ffa29 --- /dev/null +++ b/test/regression/CppiaArrayHelperExceptions/stdout.txt @@ -0,0 +1,18 @@ +interpreted +valid blit: ran, [7,1] +blit: caught blit out of bounds, [7,1] +setSize: caught Array allocation too large, [7,8] +resize: caught Array allocation too large, [7,8] +dynamic blit: caught blit out of bounds, [7,eight] +dynamic setSize: caught Array allocation too large, [7,eight] +dynamic resize: caught Array allocation too large, [7,eight] +continued +jit +valid blit: ran, [7,1] +blit: caught blit out of bounds, [7,1] +setSize: caught Array allocation too large, [7,8] +resize: caught Array allocation too large, [7,8] +dynamic blit: caught blit out of bounds, [7,eight] +dynamic setSize: caught Array allocation too large, [7,eight] +dynamic resize: caught Array allocation too large, [7,eight] +continued diff --git a/test/regression/CppiaDynamicArrayResizeReceiver/Main.hx b/test/regression/CppiaDynamicArrayResizeReceiver/Main.hx new file mode 100644 index 00000000..e1b4cc7a --- /dev/null +++ b/test/regression/CppiaDynamicArrayResizeReceiver/Main.hx @@ -0,0 +1,13 @@ +// Runs the script interpreted and then under the JIT +function main() { + var script = haxe.io.Path.join([haxe.io.Path.directory(Sys.programPath()), "script.cppia"]); + for (jit in [false, true]) { + cpp.cppia.Host.enableJit(jit); + Sys.println(jit ? "jit" : "interpreted"); + try { + cpp.cppia.Host.runFile(script); + } catch (e:Dynamic) { + Sys.println("error: " + e); + } + } +} diff --git a/test/regression/CppiaDynamicArrayResizeReceiver/Script.hx b/test/regression/CppiaDynamicArrayResizeReceiver/Script.hx new file mode 100644 index 00000000..a33f584a --- /dev/null +++ b/test/regression/CppiaDynamicArrayResizeReceiver/Script.hx @@ -0,0 +1,28 @@ +// The JIT evaluated the receiver of resize() and cpp.NativeArray.setSize() on +// an Array twice, so a receiver with side effects ran twice, and the +// array it returned the second time was the one resized. +class Script { + static var calls = 0; + static var first:Array; + static var second:Array; + + static function receiver():Array { + calls++; + return calls == 1 ? first : second; + } + + static function reset() { + calls = 0; + first = [1, "two", 3]; + second = [4, "five", 6]; + } + + static function main() { + reset(); + receiver().resize(1); + Sys.println('resize: calls=$calls first=$first second=$second'); + reset(); + cpp.NativeArray.setSize(receiver(), 1); + Sys.println('setSize: calls=$calls first=$first second=$second'); + } +} diff --git a/test/regression/CppiaDynamicArrayResizeReceiver/build.hxml b/test/regression/CppiaDynamicArrayResizeReceiver/build.hxml new file mode 100644 index 00000000..d20d36bd --- /dev/null +++ b/test/regression/CppiaDynamicArrayResizeReceiver/build.hxml @@ -0,0 +1,7 @@ +--main Script +-cppia bin/script.cppia +--next +--main Main +-cpp bin +-D scriptable +--dce no diff --git a/test/regression/CppiaDynamicArrayResizeReceiver/stdout.txt b/test/regression/CppiaDynamicArrayResizeReceiver/stdout.txt new file mode 100644 index 00000000..b8c5ced0 --- /dev/null +++ b/test/regression/CppiaDynamicArrayResizeReceiver/stdout.txt @@ -0,0 +1,6 @@ +interpreted +resize: calls=1 first=[1] second=[4,five,6] +setSize: calls=1 first=[1] second=[4,five,6] +jit +resize: calls=1 first=[1] second=[4,five,6] +setSize: calls=1 first=[1] second=[4,five,6] diff --git a/test/regression/CppiaDynamicArrayReverseResize/Main.hx b/test/regression/CppiaDynamicArrayReverseResize/Main.hx new file mode 100644 index 00000000..e1b4cc7a --- /dev/null +++ b/test/regression/CppiaDynamicArrayReverseResize/Main.hx @@ -0,0 +1,13 @@ +// Runs the script interpreted and then under the JIT +function main() { + var script = haxe.io.Path.join([haxe.io.Path.directory(Sys.programPath()), "script.cppia"]); + for (jit in [false, true]) { + cpp.cppia.Host.enableJit(jit); + Sys.println(jit ? "jit" : "interpreted"); + try { + cpp.cppia.Host.runFile(script); + } catch (e:Dynamic) { + Sys.println("error: " + e); + } + } +} diff --git a/test/regression/CppiaDynamicArrayReverseResize/Script.hx b/test/regression/CppiaDynamicArrayReverseResize/Script.hx new file mode 100644 index 00000000..fffd735d --- /dev/null +++ b/test/regression/CppiaDynamicArrayReverseResize/Script.hx @@ -0,0 +1,28 @@ +// The interpreter took reverse() and resize() on an Array but did +// neither, and never evaluated resize's argument. The JIT and compiled code +// do both. A typed array is the control. +class Script { + static var calls = 0; + + static function size(n:Int):Int { + calls++; + return n; + } + + static function main() { + var typed = [1, 2, 3]; + typed.reverse(); + typed.resize(2); + Sys.println("typed: " + typed.join(",")); + + var a:Array = [1, "two", 3]; + a.reverse(); + Sys.println("reversed: " + a.join(",")); + a.resize(size(1)); + Sys.println("shrunk: " + a.join(",") + " calls=" + calls); + a.resize(size(3)); + Sys.println("grown: " + a.length + " " + a.join(",") + " calls=" + calls); + a.resize(size(0)); + Sys.println("emptied: " + a.length + " calls=" + calls); + } +} diff --git a/test/regression/CppiaDynamicArrayReverseResize/build.hxml b/test/regression/CppiaDynamicArrayReverseResize/build.hxml new file mode 100644 index 00000000..d20d36bd --- /dev/null +++ b/test/regression/CppiaDynamicArrayReverseResize/build.hxml @@ -0,0 +1,7 @@ +--main Script +-cppia bin/script.cppia +--next +--main Main +-cpp bin +-D scriptable +--dce no diff --git a/test/regression/CppiaDynamicArrayReverseResize/stdout.txt b/test/regression/CppiaDynamicArrayReverseResize/stdout.txt new file mode 100644 index 00000000..c1dfa5bd --- /dev/null +++ b/test/regression/CppiaDynamicArrayReverseResize/stdout.txt @@ -0,0 +1,12 @@ +interpreted +typed: 3,2 +reversed: 3,two,1 +shrunk: 3 calls=1 +grown: 3 3,null,null calls=2 +emptied: 0 calls=3 +jit +typed: 3,2 +reversed: 3,two,1 +shrunk: 3 calls=1 +grown: 3 3,null,null calls=2 +emptied: 0 calls=3 diff --git a/test/regression/CppiaDynamicArraySearchFrom/Main.hx b/test/regression/CppiaDynamicArraySearchFrom/Main.hx new file mode 100644 index 00000000..e1b4cc7a --- /dev/null +++ b/test/regression/CppiaDynamicArraySearchFrom/Main.hx @@ -0,0 +1,13 @@ +// Runs the script interpreted and then under the JIT +function main() { + var script = haxe.io.Path.join([haxe.io.Path.directory(Sys.programPath()), "script.cppia"]); + for (jit in [false, true]) { + cpp.cppia.Host.enableJit(jit); + Sys.println(jit ? "jit" : "interpreted"); + try { + cpp.cppia.Host.runFile(script); + } catch (e:Dynamic) { + Sys.println("error: " + e); + } + } +} diff --git a/test/regression/CppiaDynamicArraySearchFrom/Script.hx b/test/regression/CppiaDynamicArraySearchFrom/Script.hx new file mode 100644 index 00000000..1db4bc82 --- /dev/null +++ b/test/regression/CppiaDynamicArraySearchFrom/Script.hx @@ -0,0 +1,33 @@ +// The JIT ignored fromIndex in indexOf and lastIndexOf on an Array, +// and never evaluated it, so calls and exceptions in it were lost. The +// interpreter and compiled code use it. A typed array is the control. +class Script { + static var calls = 0; + + static function from(n:Int):Int { + calls++; + return n; + } + + static function fail():Int { + throw "bad index"; + } + + static function main() { + var typed = ["a", "b", "a", "b", "a"]; + Sys.println("typed: " + typed.indexOf("a", 1) + " " + typed.lastIndexOf("a", 3)); + + var a:Array = ["a", "b", "a", "b", "a"]; + Sys.println("omitted: " + a.indexOf("a") + " " + a.lastIndexOf("a")); + Sys.println("from 2: " + a.indexOf("a", 2) + " " + a.lastIndexOf("a", 2)); + Sys.println("negative: " + a.indexOf("a", -2) + " " + a.lastIndexOf("a", -2)); + Sys.println("past the end: " + a.indexOf("a", 9) + " " + a.lastIndexOf("a", 9)); + Sys.println("evaluated: " + a.indexOf("a", from(3)) + " " + a.lastIndexOf("a", from(3)) + " calls=" + calls); + try { + a.indexOf("a", fail()); + Sys.println("throwing fromIndex: not thrown"); + } catch (e:Dynamic) { + Sys.println("throwing fromIndex: " + e); + } + } +} diff --git a/test/regression/CppiaDynamicArraySearchFrom/build.hxml b/test/regression/CppiaDynamicArraySearchFrom/build.hxml new file mode 100644 index 00000000..d20d36bd --- /dev/null +++ b/test/regression/CppiaDynamicArraySearchFrom/build.hxml @@ -0,0 +1,7 @@ +--main Script +-cppia bin/script.cppia +--next +--main Main +-cpp bin +-D scriptable +--dce no diff --git a/test/regression/CppiaDynamicArraySearchFrom/stdout.txt b/test/regression/CppiaDynamicArraySearchFrom/stdout.txt new file mode 100644 index 00000000..27c97a9f --- /dev/null +++ b/test/regression/CppiaDynamicArraySearchFrom/stdout.txt @@ -0,0 +1,16 @@ +interpreted +typed: 2 2 +omitted: 0 4 +from 2: 2 2 +negative: 4 2 +past the end: -1 4 +evaluated: 4 2 calls=2 +throwing fromIndex: bad index +jit +typed: 2 2 +omitted: 0 4 +from 2: 2 2 +negative: 4 2 +past the end: -1 4 +evaluated: 4 2 calls=2 +throwing fromIndex: bad index