diff --git a/src/core/org/luaj/compiler/DumpState.java b/src/core/org/luaj/compiler/DumpState.java index d85fdfc5..7ff5c970 100644 --- a/src/core/org/luaj/compiler/DumpState.java +++ b/src/core/org/luaj/compiler/DumpState.java @@ -25,13 +25,12 @@ import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; -import org.luaj.vm.LBoolean; -import org.luaj.vm.LNil; import org.luaj.vm.LNumber; +import org.luaj.vm.LPrototype; import org.luaj.vm.LString; import org.luaj.vm.LValue; +import org.luaj.vm.LocVars; import org.luaj.vm.Lua; -import org.luaj.vm.LPrototype; public class DumpState { @@ -54,9 +53,21 @@ public class DumpState { /** set true to allow integer compilation */ public static boolean ALLOW_INTEGER_CASTING = false; + /** format corresponding to non-number-patched lua, all numbers are floats or doubles */ + public static final int NUMBER_FORMAT_FLOATS_OR_DOUBLES = 0; + + /** format corresponding to non-number-patched lua, all numbers are ints */ + public static final int NUMBER_FORMAT_INTS_ONLY = 1; + + /** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */ + public static final int NUMBER_FORMAT_NUM_PATCH_INT32 = 4; + + /** default number format */ + public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES; + // header fields private boolean IS_LITTLE_ENDIAN = false; - private boolean IS_NUMBER_INTEGRAL = false; + private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT; private int SIZEOF_LUA_NUMBER = 8; private static final int SIZEOF_INT = 4; private static final int SIZEOF_SIZET = 4; @@ -98,49 +109,69 @@ public class DumpState { writer.write( 0 ); } - void dumpNumber(double d) throws IOException { - if ( IS_NUMBER_INTEGRAL ) { - int i = (int) d; - if ( (! ALLOW_INTEGER_CASTING) && (i != d) ) - throw new java.lang.IllegalArgumentException("not an integer: "+d); - dumpInt( i ); + void dumpDouble(double d) throws IOException { + long l = Double.doubleToLongBits(d); + if ( IS_LITTLE_ENDIAN ) { + dumpInt( (int) l ); + dumpInt( (int) (l>>32) ); } else { - long l = Double.doubleToLongBits(d); - if ( IS_LITTLE_ENDIAN ) { - dumpInt( (int) l ); - dumpInt( (int) (l>>32) ); - } else { - writer.writeLong(l); - } + writer.writeLong(l); } } void dumpCode( final LPrototype f ) throws IOException { - int n = f.code.length; + final int[] code = f.code; + int n = code.length; dumpInt( n ); for ( int i=0; i number format 'n', (n=0,1 or 4, default="+DumpState.NUMBER_FORMAT_DEFAULT+")\n" + " -v show version information\n" + " -- stop handling options\n"; @@ -65,7 +65,7 @@ public class luac { private boolean parseonly = false; private boolean stripdebug = false; private boolean littleendian = false; - private boolean intsonly = false; + private int numberformat = DumpState.NUMBER_FORMAT_DEFAULT; private boolean versioninfo = false; private boolean processing = true; @@ -107,7 +107,9 @@ public class luac { littleendian = true; break; case 'i': - intsonly = true; + if ( args[i].length() <= 2 ) + usageExit(); + numberformat = Integer.parseInt(args[i].substring(2)); break; case 'v': versioninfo = true; @@ -171,7 +173,7 @@ public class luac { // write out the chunk if (!parseonly) { - DumpState.dump(chunk, out, stripdebug, intsonly, littleendian); + DumpState.dump(chunk, out, stripdebug, numberformat, littleendian); } } catch ( Throwable t ) { diff --git a/src/test/java/org/luaj/compiler/DumpLoadEndianIntTest.java b/src/test/java/org/luaj/compiler/DumpLoadEndianIntTest.java index 8ef6b3cf..1cde9ab4 100644 --- a/src/test/java/org/luaj/compiler/DumpLoadEndianIntTest.java +++ b/src/test/java/org/luaj/compiler/DumpLoadEndianIntTest.java @@ -2,6 +2,7 @@ package org.luaj.compiler; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -15,38 +16,65 @@ import org.luaj.vm.LuaState; import org.luaj.vm.Platform; public class DumpLoadEndianIntTest extends TestCase { + private static final String SAVECHUNKS = "SAVECHUNKS"; - private static final String script = "return tostring(1234)..'-#!-'..tostring(23.75)"; + private static final boolean SHOULDPASS = true; + private static final boolean SHOULDFAIL = false; + private static final String mixedscript = "return tostring(1234)..'-#!-'..tostring(23.75)"; + private static final String intscript = "return tostring(1234)..'-#!-'..tostring(23)"; private static final String withdoubles = "1234-#!-23.75"; private static final String withints = "1234-#!-23"; protected void setUp() throws Exception { super.setUp(); Platform.setInstance(new J2sePlatform()); - DumpState.ALLOW_INTEGER_CASTING = true; + DumpState.ALLOW_INTEGER_CASTING = false; } - public void testBidDoubleCompile() { - doTest( false, false, false, withdoubles ); - doTest( false, false, true, withdoubles ); + public void testBigDoubleCompile() { + doTest( false, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, false, mixedscript, withdoubles, withdoubles, SHOULDPASS ); + doTest( false, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, true, mixedscript, withdoubles, withdoubles, SHOULDPASS ); } public void testLittleDoubleCompile() { - doTest( true, false, false, withdoubles ); - doTest( true, false, true, withdoubles ); + doTest( true, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, false, mixedscript, withdoubles, withdoubles, SHOULDPASS ); + doTest( true, DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES, true, mixedscript, withdoubles, withdoubles, SHOULDPASS ); } public void testBigIntCompile() { - doTest( false, true, false, withints ); - doTest( false, true, true, withints ); + DumpState.ALLOW_INTEGER_CASTING = true; + doTest( false, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDPASS ); + doTest( false, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDPASS ); + DumpState.ALLOW_INTEGER_CASTING = false; + doTest( false, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDFAIL ); + doTest( false, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDFAIL ); + doTest( false, DumpState.NUMBER_FORMAT_INTS_ONLY, false, intscript, withints, withints, SHOULDPASS ); + doTest( false, DumpState.NUMBER_FORMAT_INTS_ONLY, true, intscript, withints, withints, SHOULDPASS ); } public void testLittleIntCompile() { - doTest( true, true, false, withints ); - doTest( true, true, true, withints ); + DumpState.ALLOW_INTEGER_CASTING = true; + doTest( true, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDPASS ); + doTest( true, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDPASS ); + DumpState.ALLOW_INTEGER_CASTING = false; + doTest( true, DumpState.NUMBER_FORMAT_INTS_ONLY, false, mixedscript, withdoubles, withints, SHOULDFAIL ); + doTest( true, DumpState.NUMBER_FORMAT_INTS_ONLY, true, mixedscript, withdoubles, withints, SHOULDFAIL ); + doTest( true, DumpState.NUMBER_FORMAT_INTS_ONLY, false, intscript, withints, withints, SHOULDPASS ); + doTest( true, DumpState.NUMBER_FORMAT_INTS_ONLY, true, intscript, withints, withints, SHOULDPASS ); } - public void doTest( boolean littleEndian, boolean intNumbers, boolean stripDebug, String expected ) { + public void testBigNumpatchCompile() { + doTest( false, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, false, mixedscript, withdoubles, withdoubles, SHOULDPASS ); + doTest( false, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, true, mixedscript, withdoubles, withdoubles, SHOULDPASS ); + } + + public void testLittleNumpatchCompile() { + doTest( true, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, false, mixedscript, withdoubles, withdoubles, SHOULDPASS ); + doTest( true, DumpState.NUMBER_FORMAT_NUM_PATCH_INT32, true, mixedscript, withdoubles, withdoubles, SHOULDPASS ); + } + + public void doTest( boolean littleEndian, int numberFormat, boolean stripDebug, + String script, String expectedPriorDump, String expectedPostDump, boolean shouldPass ) { try { LuaState vm = Platform.newLuaState(); @@ -59,11 +87,20 @@ public class DumpLoadEndianIntTest extends TestCase { vm.pushfunction(f); vm.call(0,1); String actual = vm.poplvalue().toJavaString(); - assertEquals( withdoubles, actual ); + assertEquals( expectedPriorDump, actual ); // dump into bytes ByteArrayOutputStream baos = new ByteArrayOutputStream(); - DumpState.dump(p, baos, stripDebug, intNumbers, littleEndian); + try { + DumpState.dump(p, baos, stripDebug, numberFormat, littleEndian); + if ( ! shouldPass ) + fail( "dump should not have succeeded" ); + } catch ( Exception e ) { + if ( shouldPass ) + fail( "dump threw "+e ); + else + return; + } byte[] dumped = baos.toByteArray(); // load again using compiler @@ -71,13 +108,16 @@ public class DumpLoadEndianIntTest extends TestCase { vm.load(is, "dumped"); vm.call(0,1); actual = vm.poplvalue().toJavaString(); - assertEquals( expected, actual ); + assertEquals( expectedPostDump, actual ); // write test chunk - if ( System.getProperty("SAVECHUNKS") != null ) { - String filename = "test-" + if ( System.getProperty(SAVECHUNKS) != null && script.equals(mixedscript) ) { + new File("build").mkdirs(); + String filename = "build/test-" +(littleEndian? "little-": "big-") - +(intNumbers? "int-": "double-") + +(numberFormat==DumpState.NUMBER_FORMAT_FLOATS_OR_DOUBLES? "double-": + numberFormat==DumpState.NUMBER_FORMAT_INTS_ONLY? "int-": + numberFormat==DumpState.NUMBER_FORMAT_NUM_PATCH_INT32? "numpatch4-": "???-") +(stripDebug? "nodebug-": "debug-") +"bin.lua"; FileOutputStream fos = new FileOutputStream(filename); diff --git a/version.properties b/version.properties index 72c8861b..74dba767 100644 --- a/version.properties +++ b/version.properties @@ -1 +1 @@ -version: 0.46 +version: 0.50