Improve string byte backing ownership, add gradle file, up version, improve build packaging rules.

This commit is contained in:
James Roseborough
2015-03-09 06:32:54 +00:00
parent 71500e7d8d
commit c8e4bea43d
14 changed files with 465 additions and 321 deletions

View File

@@ -968,6 +968,9 @@ Files are no longer hosted at LuaForge.
<li>Add fallback to __lt when pocessing __le metatag.</li>
<li>Convert anonymous classes to inner classes (gradle build support).</li>
<li>Allow error() function to pass any lua object including non-strings.</li>
<li>Fix string backing ownership issue when compiling many scripts.</li>
<li>Make LuaC compile state explicit and improve factoring.</li>
<li>Add sample build.gradle file for Android example.</li>
</ul></td></tr>
</table></td></tr></table>

View File

@@ -13,6 +13,11 @@
<delete>
<fileset dir="." includes="luaj-*.jar"/>
</delete>
<delete dir="examples/android/bin"/>
<delete dir="examples/android/build"/>
<delete dir="examples/android/gen"/>
<delete dir="examples/android/libs"/>
<delete dir="examples/maven/target"/>
</target>
<import file="build-libs.xml"/>
@@ -150,7 +155,14 @@
<fileset dir="test"/>
</copy>
<copy todir="build/luaj-${version}/examples">
<fileset dir="examples"/>
<fileset dir="examples">
<include name="android/*.*"/>
<include name="android/assets/**"/>
<include name="android/res/**"/>
<include name="android/src/**"/>
<include name="maven/pom.xml"/>
<include name="maven/src/**"/>
</fileset>
</copy>
<copy todir="build/luaj-${version}/lib">
<fileset dir=".">

View File

@@ -0,0 +1,37 @@
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.1'
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 20
buildToolsVersion "20.0.0"
defaultConfig {
minSdkVersion 13
targetSdkVersion 20
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}
}
repositories {
mavenCentral()
}
dependencies {
compile 'org.luaj:luaj-jse:3.0.1'
}

View File

@@ -11,7 +11,7 @@
<dependency>
<groupId>org.luaj</groupId>
<artifactId>luaj-jse</artifactId>
<version>3.0</version>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>

View File

@@ -220,7 +220,7 @@ public class LoadState {
return null;
byte[] bytes = new byte[size];
is.readFully( bytes, 0, size );
return LuaString.valueOf( bytes, 0, bytes.length - 1 );
return LuaString.valueUsing( bytes, 0, bytes.length - 1 );
}
/**

View File

@@ -38,7 +38,7 @@ import org.luaj.vm2.lib.StringLib;
* sequences of characters or unicode code points, the {@link LuaString}
* implementation holds the string value in an internal byte array.
* <p>
* {@link LuaString} values are generally not mutable once constructed,
* {@link LuaString} values are not considered mutable once constructed,
* so multiple {@link LuaString} values can chare a single byte array.
* <p>
* Currently {@link LuaString}s are pooled via a centrally managed weak table.
@@ -46,6 +46,9 @@ import org.luaj.vm2.lib.StringLib;
* Constructors are not exposed directly. As with number, booleans, and nil,
* instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API.
* <p>
* Because of this pooling, users of LuaString <em>must not directly alter the
* bytes in a LuaString</em>, or undefined behavior will result.
* <p>
* When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed.
* The functions
* {@link LuaString#lengthAsUtf8(char[]),
@@ -59,46 +62,41 @@ import org.luaj.vm2.lib.StringLib;
*/
public class LuaString extends LuaValue {
/** Size of cache of recent short strings. This is the maximum number of LuaStrings that
* will be retained in the cache of recent short strings. */
public static final int RECENT_STRINGS_CACHE_SIZE = 128;
/** Maximum length of a string to be considered for recent short strings caching.
* This effectively limits the total memory that can be spent on the recent strings cache,
* ecause no LuaString whose backing exceeds this length will be put into the cache. */
public static final int RECENT_STRINGS_MAX_LENGTH = 32;
/** The singleton instance representing lua {@code true} */
public static LuaValue s_metatable;
/** The bytes for the string */
/** The bytes for the string. These <em><b>must not be mutated directly</b></em> because
* the backing may be shared by multiple LuaStrings, and the hash code is
* computed only at construction time.
* It is exposed only for performance and legacy reasons. */
public final byte[] m_bytes;
/** The offset into the byte array, 0 means start at the first byte */
public final int m_offset;
public final int m_offset;
/** The number of bytes that comprise this string */
public final int m_length;
public final int m_length;
private static class Cache {
/** Simple cache of recently created strings that are short.
* This is simply a list of strings, indexed by their hash codes modulo the cache size
* that have been recently constructed. If a string is being constructed frequently
* from different contexts, it will generally may show up as a cache hit and resolve
* to the same value. */
public final LuaString recent_short_strings[] = new LuaString[RECENT_STRINGS_CACHE_SIZE];
/** The hashcode for this string. Computed at construct time. */
private final int m_hashcode;
public LuaString get(LuaString s) {
final int index = s.hashCode() & (RECENT_STRINGS_CACHE_SIZE - 1);
final LuaString cached = (LuaString) recent_short_strings[index];
if (cached != null && s.raweq(cached))
return cached;
recent_short_strings[index] = s;
return s;
}
/** Size of cache of recent short strings. This is the maximum number of LuaStrings that
* will be retained in the cache of recent short strings. Exposed to package for testing. */
static final int RECENT_STRINGS_CACHE_SIZE = 128;
static final Cache instance = new Cache();
}
/** Maximum length of a string to be considered for recent short strings caching.
* This effectively limits the total memory that can be spent on the recent strings cache,
* because no LuaString whose backing exceeds this length will be put into the cache.
* Exposed to package for testing. */
static final int RECENT_STRINGS_MAX_LENGTH = 32;
/** Simple cache of recently created strings that are short.
* This is simply a list of strings, indexed by their hash codes modulo the cache size
* that have been recently constructed. If a string is being constructed frequently
* from different contexts, it will generally show up as a cache hit and resolve
* to the same value. */
private static final LuaString recent_short_strings[] =
new LuaString[RECENT_STRINGS_CACHE_SIZE];
/**
* Get a {@link LuaString} instance whose bytes match
@@ -110,13 +108,12 @@ public class LuaString extends LuaValue {
char[] c = string.toCharArray();
byte[] b = new byte[lengthAsUtf8(c)];
encodeToUtf8(c, c.length, b, 0);
return valueOf(b, 0, b.length);
return valueUsing(b, 0, b.length);
}
// TODO: should this be deprecated or made private?
/** Construct a {@link LuaString} around a byte array that may be used directly as the backing.
/** Construct a {@link LuaString} for a portion of a byte array.
* <p>
* The array may be used as the backing for this object, so clients must not change contents.
* The array is first be used as the backing for this object, so clients must not change contents.
* If the supplied value for 'len' is more than half the length of the container, the
* supplied byte array will be used as the backing, otherwise the bytes will be copied to a
* new byte array, and cache lookup may be performed.
@@ -127,19 +124,44 @@ public class LuaString extends LuaValue {
* @return {@link LuaString} wrapping the byte buffer
*/
public static LuaString valueOf(byte[] bytes, int off, int len) {
if (bytes.length < RECENT_STRINGS_MAX_LENGTH) {
// Short string. Reuse the backing and check the cache of recent strings before returning.
final LuaString s = new LuaString(bytes, off, len);
return Cache.instance.get( s );
} else if (len >= bytes.length / 2) {
// Reuse backing only when more than half the bytes are part of the result.
if (len > RECENT_STRINGS_MAX_LENGTH)
return valueFromCopy(bytes, off, len);
final int hash = hashCode(bytes, off, len);
final int bucket = hash & (RECENT_STRINGS_CACHE_SIZE - 1);
final LuaString t = recent_short_strings[bucket];
if (t != null && t.m_hashcode == hash && t.byteseq(bytes, off, len)) return t;
final LuaString s = valueFromCopy(bytes, off, len);
recent_short_strings[bucket] = s;
return s;
}
/** Construct a new LuaString using a copy of the bytes array supplied */
private static LuaString valueFromCopy(byte[] bytes, int off, int len) {
final byte[] copy = new byte[len];
for (int i=0; i<len; ++i) copy[i] = bytes[off+i];
return new LuaString(copy, 0, len);
}
/** Construct a {@link LuaString} around, possibly using the the supplied
* byte array as the backing store.
* <p>
* The caller must ensure that the array is not mutated after the call.
* However, if the string is short enough the short-string cache is checked
* for a match which may be used instead of the supplied byte array.
* <p>
* @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer, or an equivalent string.
*/
static public LuaString valueUsing(byte[] bytes, int off, int len) {
if (bytes.length > RECENT_STRINGS_MAX_LENGTH)
return new LuaString(bytes, off, len);
} else {
// Short result relative to the source. Copy only the bytes that are actually to be used.
final byte[] b = new byte[len];
System.arraycopy(bytes, off, b, 0, len);
return valueOf(b, 0, len); // To possibly use cached version.
}
final int hash = hashCode(bytes, off, len);
final int bucket = hash & (RECENT_STRINGS_CACHE_SIZE - 1);
final LuaString t = recent_short_strings[bucket];
if (t != null && t.m_hashcode == hash && t.byteseq(bytes, off, len)) return t;
final LuaString s = new LuaString(bytes, off, len);
recent_short_strings[bucket] = s;
return s;
}
/** Construct a {@link LuaString} using the supplied characters as byte values.
@@ -166,13 +188,13 @@ public class LuaString extends LuaValue {
byte[] b = new byte[len];
for ( int i=0; i<len; i++ )
b[i] = (byte) bytes[i + off];
return valueOf(b, 0, len);
return valueUsing(b, 0, len);
}
/** Construct a {@link LuaString} around a byte array without copying the contents.
/** Construct a {@link LuaString} for all the bytes in a byte array.
* <p>
* The array may be used directly as the backing, so clients must not change contents.
* The LuaString returned will either be a new LuaString containing a copy
* of the bytes array, or be an existing LuaString used already having the same value.
* <p>
* @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer
@@ -181,6 +203,21 @@ public class LuaString extends LuaValue {
return valueOf(bytes, 0, bytes.length);
}
/** Construct a {@link LuaString} for all the bytes in a byte array, possibly using
* the supplied array as the backing store.
* <p>
* The LuaString returned will either be a new LuaString containing the byte array,
* or be an existing LuaString used already having the same value.
* <p>
* The caller must not mutate the contents of the byte array after this call, as
* it may be used elsewhere due to recent short string caching.
* @param bytes byte buffer
* @return {@link LuaString} wrapping the byte buffer
*/
public static LuaString valueUsing(byte[] bytes) {
return valueUsing(bytes, 0, bytes.length);
}
/** Construct a {@link LuaString} around a byte array without copying the contents.
* <p>
* The array is used directly after this is called, so clients must not change contents.
@@ -194,6 +231,7 @@ public class LuaString extends LuaValue {
this.m_bytes = bytes;
this.m_offset = offset;
this.m_length = length;
this.m_hashcode = hashCode(bytes, offset, length);
}
public boolean isstring() {
@@ -275,7 +313,7 @@ public class LuaString extends LuaValue {
byte[] b = new byte[lhs.m_length+this.m_length];
System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length);
System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length);
return valueOf(b, 0, b.length);
return valueUsing(b, 0, b.length);
}
// string comparison
@@ -394,14 +432,29 @@ public class LuaString extends LuaValue {
* beginIndex and extending for (endIndex - beginIndex ) characters.
*/
public LuaString substring( int beginIndex, int endIndex ) {
return valueOf( m_bytes, m_offset + beginIndex, endIndex - beginIndex );
final int off = m_offset + beginIndex;
final int len = endIndex - beginIndex;
return len >= m_length / 2?
valueUsing(m_bytes, off, len):
valueOf(m_bytes, off, len);
}
public int hashCode() {
int h = m_length; /* seed */
int step = (m_length>>5)+1; /* if string is too long, don't hash all its chars */
for (int l1=m_length; l1>=step; l1-=step) /* compute hash */
h = h ^ ((h<<5)+(h>>2)+(((int) m_bytes[m_offset+l1-1] ) & 0x0FF ));
return m_hashcode;
}
/** Compute the hash code of a sequence of bytes within a byte array using
* lua's rules for string hashes. For long strings, not all bytes are hashed.
* @param bytes byte array containing the bytes.
* @param offset offset into the hash for the first byte.
* @param length number of bytes starting with offset that are part of the string.
* @return hash for the string defined by bytes, offset, and length.
*/
public static int hashCode(byte[] bytes, int offset, int length) {
int h = length; /* seed */
int step = (length>>5)+1; /* if string is too long, don't hash all its chars */
for (int l1=length; l1>=step; l1-=step) /* compute hash */
h = h ^ ((h<<5)+(h>>2)+(((int) bytes[offset+l1-1] ) & 0x0FF ));
return h;
}
@@ -441,6 +494,11 @@ public class LuaString extends LuaValue {
return equals( a.m_bytes, a.m_offset + i, b.m_bytes, b.m_offset + j, n );
}
/** Return true if the bytes in the supplied range match this LuaStrings bytes. */
private boolean byteseq(byte[] bytes, int off, int len) {
return (m_length == len && equals(m_bytes, m_offset, bytes, off, len));
}
public static boolean equals( byte[] a, int i, byte[] b, int j, int n ) {
if ( a.length < i + n || b.length < j + n )
return false;

View File

@@ -0,0 +1,185 @@
/*******************************************************************************
* Copyright (c) 2015 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.compiler;
import org.luaj.vm2.LocVars;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
/**
* Constants used by the LuaC compiler and related classes.
*
* @see LuaC
* @see FuncState
*/
public class Constants extends Lua {
/** Maximum stack size of a luaj vm interpreter instance. */
public static final int MAXSTACK = 250;
static final int LUAI_MAXUPVAL = 0xff;
static final int LUAI_MAXVARS = 200;
static final int NO_REG = MAXARG_A;
/* OpMode - basic instruction format */
static final int
iABC = 0,
iABx = 1,
iAsBx = 2;
/* OpArgMask */
static final int
OpArgN = 0, /* argument is not used */
OpArgU = 1, /* argument is used */
OpArgR = 2, /* argument is a register or a jump offset */
OpArgK = 3; /* argument is a constant or register/constant */
protected static void _assert(boolean b) {
if (!b)
throw new LuaError("compiler assert failed");
}
static void SET_OPCODE(InstructionPtr i,int o) {
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
}
static void SETARG_A(int[] code, int index, int u) {
code[index] = (code[index] & (MASK_NOT_A)) | ((u << POS_A) & MASK_A);
}
static void SETARG_A(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) );
}
static void SETARG_B(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_B)) | ((u << POS_B) & MASK_B) );
}
static void SETARG_C(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_C)) | ((u << POS_C) & MASK_C) );
}
static void SETARG_Bx(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_Bx)) | ((u << POS_Bx) & MASK_Bx) );
}
static void SETARG_sBx(InstructionPtr i,int u) {
SETARG_Bx( i, u + MAXARG_sBx );
}
static int CREATE_ABC(int o, int a, int b, int c) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_A) & MASK_A) |
((b << POS_B) & MASK_B) |
((c << POS_C) & MASK_C) ;
}
static int CREATE_ABx(int o, int a, int bc) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_A) & MASK_A) |
((bc << POS_Bx) & MASK_Bx) ;
}
// vector reallocation
static LuaValue[] realloc(LuaValue[] v, int n) {
LuaValue[] a = new LuaValue[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static Prototype[] realloc(Prototype[] v, int n) {
Prototype[] a = new Prototype[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LuaString[] realloc(LuaString[] v, int n) {
LuaString[] a = new LuaString[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LocVars[] realloc(LocVars[] v, int n) {
LocVars[] a = new LocVars[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static Upvaldesc[] realloc(Upvaldesc[] v, int n) {
Upvaldesc[] a = new Upvaldesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LexState.Vardesc[] realloc(LexState.Vardesc[] v, int n) {
LexState.Vardesc[] a = new LexState.Vardesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LexState.Labeldesc[] grow(LexState.Labeldesc[] v, int min_n) {
return v == null ? new LexState.Labeldesc[2] : v.length < min_n ? realloc(v, v.length*2) : v;
}
static LexState.Labeldesc[] realloc(LexState.Labeldesc[] v, int n) {
LexState.Labeldesc[] a = new LexState.Labeldesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static int[] realloc(int[] v, int n) {
int[] a = new int[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static byte[] realloc(byte[] v, int n) {
byte[] a = new byte[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static char[] realloc(char[] v, int n) {
char[] a = new char[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
protected Constants() {}
}

View File

@@ -28,8 +28,6 @@ import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaDouble;
import org.luaj.vm2.LuaInteger;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaUserdata;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
@@ -37,7 +35,7 @@ import org.luaj.vm2.compiler.LexState.ConsControl;
import org.luaj.vm2.compiler.LexState.expdesc;
public class FuncState extends LuaC {
public class FuncState extends Constants {
static class BlockCnt {
BlockCnt previous; /* chain */
@@ -52,7 +50,7 @@ public class FuncState extends LuaC {
Hashtable h; /* table to find (and reuse) elements in `k' */
FuncState prev; /* enclosing function */
LexState ls; /* lexical state */
LuaC L; /* compiler being invoked */
LuaC.CompileState L; /* compiler being invoked */
BlockCnt bl; /* chain of current blocks */
int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* `pc' of last `jump target' */

View File

@@ -23,7 +23,6 @@ package org.luaj.vm2.compiler;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.Hashtable;
import org.luaj.vm2.LocVars;
@@ -37,7 +36,7 @@ import org.luaj.vm2.compiler.FuncState.BlockCnt;
import org.luaj.vm2.lib.MathLib;
public class LexState {
public class LexState extends Constants {
protected static final String RESERVED_LOCAL_VAR_FOR_CONTROL = "(for control)";
protected static final String RESERVED_LOCAL_VAR_FOR_STATE = "(for state)";
@@ -135,7 +134,7 @@ public class LexState {
final Token t = new Token(); /* current token */
final Token lookahead = new Token(); /* look ahead token */
FuncState fs; /* `FuncState' is private to the parser */
LuaC L;
LuaC.CompileState L;
InputStream z; /* input stream */
char[] buff; /* buffer for tokens */
int nbuff; /* length of buffer */
@@ -203,7 +202,7 @@ public class LexState {
}
public LexState(LuaC state, InputStream stream) {
public LexState(LuaC.CompileState state, InputStream stream) {
this.z = stream;
this.buff = new char[32];
this.L = state;
@@ -229,7 +228,7 @@ public class LexState {
void save(int c) {
if ( buff == null || nbuff + 1 > buff.length )
buff = LuaC.realloc( buff, nbuff*2+1 );
buff = realloc( buff, nbuff*2+1 );
buff[nbuff++] = (char) c;
}
@@ -282,7 +281,7 @@ public class LexState {
void inclinenumber() {
int old = current;
LuaC._assert( currIsNewline() );
_assert( currIsNewline() );
nextChar(); /* skip '\n' or '\r' */
if ( currIsNewline() && current != old )
nextChar(); /* skip '\n\r' or '\r\n' */
@@ -290,7 +289,7 @@ public class LexState {
syntaxerror("chunk has too many lines");
}
void setinput( LuaC L, int firstByte, InputStream z, LuaString source ) {
void setinput(LuaC.CompileState L, int firstByte, InputStream z, LuaString source) {
this.decpoint = '.';
this.L = L;
this.lookahead.token = TK_EOS; /* no look-ahead token */
@@ -397,7 +396,7 @@ public class LexState {
void read_numeral(SemInfo seminfo) {
String expo = "Ee";
int first = current;
LuaC._assert (isdigit(current));
_assert (isdigit(current));
save_and_next();
if (first == '0' && check_next("Xx"))
expo = "Pp";
@@ -417,7 +416,7 @@ public class LexState {
int skip_sep() {
int count = 0;
int s = current;
LuaC._assert (s == '[' || s == ']');
_assert (s == '[' || s == ']');
save_and_next();
while (current == '=') {
save_and_next();
@@ -690,7 +689,7 @@ public class LexState {
}
default: {
if (isspace(current)) {
LuaC._assert (!currIsNewline());
_assert (!currIsNewline());
nextChar();
continue;
} else if (isdigit(current)) {
@@ -729,7 +728,7 @@ public class LexState {
}
void lookahead() {
LuaC._assert (lookahead.token == TK_EOS);
_assert (lookahead.token == TK_EOS);
lookahead.token = llex(lookahead.seminfo);
}
@@ -841,7 +840,7 @@ public class LexState {
void anchor_token () {
/* last token from outer function must be EOS */
LuaC._assert(fs != null || t.token == TK_EOS);
_assert(fs != null || t.token == TK_EOS);
if (t.token == TK_NAME || t.token == TK_STRING) {
LuaString ts = t.seminfo.ts;
// TODO: is this necessary?
@@ -916,7 +915,7 @@ public class LexState {
FuncState fs = this.fs;
Prototype f = fs.f;
if (f.locvars == null || fs.nlocvars + 1 > f.locvars.length)
f.locvars = LuaC.realloc( f.locvars, fs.nlocvars*2+1 );
f.locvars = realloc( f.locvars, fs.nlocvars*2+1 );
f.locvars[fs.nlocvars] = new LocVars(varname,0,0);
return fs.nlocvars++;
}
@@ -925,7 +924,7 @@ public class LexState {
int reg = registerlocalvar(name);
fs.checklimit(dyd.n_actvar + 1, FuncState.LUAI_MAXVARS, "local variables");
if (dyd.actvar == null || dyd.n_actvar + 1 > dyd.actvar.length)
dyd.actvar = LuaC.realloc(dyd.actvar, Math.max(1, dyd.n_actvar * 2));
dyd.actvar = realloc(dyd.actvar, Math.max(1, dyd.n_actvar * 2));
dyd.actvar[dyd.n_actvar++] = new Vardesc(reg);
}
@@ -954,7 +953,7 @@ public class LexState {
if (FuncState.singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
expdesc key = new expdesc();
FuncState.singlevaraux(fs, this.envn, var, 1); /* get environment variable */
LuaC._assert(var.k == VLOCAL || var.k == VUPVAL);
_assert(var.k == VLOCAL || var.k == VUPVAL);
this.codestring(key, varname); /* key is variable name */
fs.indexed(var, key); /* env[varname] */
}
@@ -997,7 +996,7 @@ public class LexState {
FuncState fs = this.fs;
Labeldesc[] gl = this.dyd.gt;
Labeldesc gt = gl[g];
LuaC._assert(gt.name.eq_b(label.name));
_assert(gt.name.eq_b(label.name));
if (gt.nactvar < label.nactvar) {
LuaString vname = fs.getlocvar(gt.nactvar).varname;
String msg = L.pushfstring("<goto " + gt.name + "> at line "
@@ -1033,7 +1032,7 @@ public class LexState {
return false; /* label not found; cannot close goto */
}
/* Caller must LuaC.grow() the vector before calling this. */
/* Caller must grow() the vector before calling this. */
int newlabelentry(Labeldesc[] l, int index, LuaString name, int line, int pc) {
l[index] = new Labeldesc(name, pc, line, fs.nactvar);
return index;
@@ -1060,7 +1059,7 @@ public class LexState {
*/
void breaklabel () {
LuaString n = LuaString.valueOf("break");
int l = newlabelentry(dyd.label=LuaC.grow(dyd.label, dyd.n_label+1), dyd.n_label++, n, 0, fs.pc);
int l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, n, 0, fs.pc);
findgotos(dyd.label[l]);
}
@@ -1079,7 +1078,7 @@ public class LexState {
Prototype clp;
Prototype f = fs.f; /* prototype of current function */
if (f.p == null || fs.np >= f.p.length) {
f.p = LuaC.realloc(f.p, Math.max(1, fs.np * 2));
f.p = realloc(f.p, Math.max(1, fs.np * 2));
}
f.p[fs.np++] = clp = new Prototype();
return clp;
@@ -1087,7 +1086,7 @@ public class LexState {
void codeclosure (expdesc v) {
FuncState fs = this.fs.prev;
v.init(VRELOCABLE, fs.codeABx(LuaC.OP_CLOSURE, 0, fs.np - 1));
v.init(VRELOCABLE, fs.codeABx(OP_CLOSURE, 0, fs.np - 1));
fs.exp2nextreg(v); /* fix it at stack top (for GC) */
}
@@ -1116,13 +1115,13 @@ public class LexState {
Prototype f = fs.f;
fs.ret(0, 0); /* final return */
fs.leaveblock();
f.code = LuaC.realloc(f.code, fs.pc);
f.lineinfo = LuaC.realloc(f.lineinfo, fs.pc);
f.k = LuaC.realloc(f.k, fs.nk);
f.p = LuaC.realloc(f.p, fs.np);
f.locvars = LuaC.realloc(f.locvars, fs.nlocvars);
f.upvalues = LuaC.realloc(f.upvalues, fs.nups);
LuaC._assert (fs.bl == null);
f.code = realloc(f.code, fs.pc);
f.lineinfo = realloc(f.lineinfo, fs.pc);
f.k = realloc(f.k, fs.nk);
f.p = realloc(f.p, fs.np);
f.locvars = realloc(f.locvars, fs.nlocvars);
f.upvalues = realloc(f.upvalues, fs.nups);
_assert (fs.bl == null);
this.fs = fs.prev;
// last token read was anchored in defunct function; must reanchor it
// ls.anchor_token();
@@ -1209,7 +1208,7 @@ public class LexState {
fs.exp2nextreg(t); /* fix it at stack top (for gc) */
this.checknext('{');
do {
LuaC._assert (cc.v.k == VVOID || cc.tostore > 0);
_assert (cc.v.k == VVOID || cc.tostore > 0);
if (this.t.token == '}')
break;
fs.closelistfield(cc);
@@ -1235,8 +1234,8 @@ public class LexState {
this.check_match('}', '{', line);
fs.lastlistfield(cc);
InstructionPtr i = new InstructionPtr(fs.f.code, pc);
LuaC.SETARG_B(i, luaO_int2fb(cc.na)); /* set initial array size */
LuaC.SETARG_C(i, luaO_int2fb(cc.nh)); /* set initial table size */
SETARG_B(i, luaO_int2fb(cc.na)); /* set initial array size */
SETARG_C(i, luaO_int2fb(cc.nh)); /* set initial table size */
}
/*
@@ -1350,7 +1349,7 @@ public class LexState {
return;
}
}
LuaC._assert (f.k == VNONRELOC);
_assert (f.k == VNONRELOC);
base = f.u.info; /* base register for call */
if (hasmultret(args.k))
nparams = Lua.LUA_MULTRET; /* open call */
@@ -1727,7 +1726,7 @@ public class LexState {
next(); /* skip break */
label = LuaString.valueOf("break");
}
g = newlabelentry(dyd.gt =LuaC.grow(dyd.gt, dyd.n_gt+1), dyd.n_gt++, label, line, pc);
g = newlabelentry(dyd.gt =grow(dyd.gt, dyd.n_gt+1), dyd.n_gt++, label, line, pc);
findlabel(g); /* close it if label already defined */
}
@@ -1745,7 +1744,7 @@ public class LexState {
fs.checkrepeated(dyd.label, dyd.n_label, label); /* check for repeated labels */
checknext(TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
l = newlabelentry(dyd.label=LuaC.grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.pc);
l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.pc);
skipnoopstat(); /* skip other no-op statements */
if (block_follow(false)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
@@ -2014,7 +2013,7 @@ public class LexState {
}
else { /* stat -> func */
check_condition(v.v.k == VCALL, "syntax error");
LuaC.SETARG_C(fs.getcodePtr(v.v), 1); /* call statement uses no results */
SETARG_C(fs.getcodePtr(v.v), 1); /* call statement uses no results */
}
}
@@ -2030,8 +2029,8 @@ public class LexState {
if (hasmultret(e.k)) {
fs.setmultret(e);
if (e.k == VCALL && nret == 1) { /* tail call? */
LuaC.SET_OPCODE(fs.getcodePtr(e), Lua.OP_TAILCALL);
LuaC._assert (Lua.GETARG_A(fs.getcode(e)) == fs.nactvar);
SET_OPCODE(fs.getcodePtr(e), Lua.OP_TAILCALL);
_assert (Lua.GETARG_A(fs.getcode(e)) == fs.nactvar);
}
first = fs.nactvar;
nret = Lua.LUA_MULTRET; /* return all values */
@@ -2041,7 +2040,7 @@ public class LexState {
else {
fs.exp2nextreg(e); /* values must go to the `stack' */
first = fs.nactvar; /* return all `active' values */
LuaC._assert (nret == fs.freereg - first);
_assert (nret == fs.freereg - first);
}
}
}
@@ -2111,7 +2110,7 @@ public class LexState {
break;
}
}
LuaC._assert(fs.f.maxstacksize >= fs.freereg
_assert(fs.f.maxstacksize >= fs.freereg
&& fs.freereg >= fs.nactvar);
fs.freereg = fs.nactvar; /* free registers */
leavelevel();

View File

@@ -26,15 +26,11 @@ import java.io.InputStream;
import java.util.Hashtable;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LocVars;
import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaClosure;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.Upvaldesc;
import org.luaj.vm2.lib.BaseLib;
/**
@@ -77,7 +73,7 @@ import org.luaj.vm2.lib.BaseLib;
* @see LuaCompiler
* @see Prototype
*/
public class LuaC extends Lua implements Globals.Compiler, Globals.Loader {
public class LuaC extends Constants implements Globals.Compiler, Globals.Loader {
/** A sharable instance of the LuaC compiler. */
public static final LuaC instance = new LuaC();
@@ -92,157 +88,8 @@ public class LuaC extends Lua implements Globals.Compiler, Globals.Loader {
globals.loader = instance;
}
protected static void _assert(boolean b) {
if (!b)
throw new LuaError("compiler assert failed");
}
public static final int MAXSTACK = 250;
static final int LUAI_MAXUPVAL = 0xff;
static final int LUAI_MAXVARS = 200;
static final int NO_REG = MAXARG_A;
/* OpMode - basic instruction format */
static final int
iABC = 0,
iABx = 1,
iAsBx = 2;
/* OpArgMask */
static final int
OpArgN = 0, /* argument is not used */
OpArgU = 1, /* argument is used */
OpArgR = 2, /* argument is a register or a jump offset */
OpArgK = 3; /* argument is a constant or register/constant */
static void SET_OPCODE(InstructionPtr i,int o) {
i.set( ( i.get() & (MASK_NOT_OP)) | ((o << POS_OP) & MASK_OP) );
}
static void SETARG_A(int[] code, int index, int u) {
code[index] = (code[index] & (MASK_NOT_A)) | ((u << POS_A) & MASK_A);
}
static void SETARG_A(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_A)) | ((u << POS_A) & MASK_A) );
}
static void SETARG_B(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_B)) | ((u << POS_B) & MASK_B) );
}
static void SETARG_C(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_C)) | ((u << POS_C) & MASK_C) );
}
static void SETARG_Bx(InstructionPtr i,int u) {
i.set( ( i.get() & (MASK_NOT_Bx)) | ((u << POS_Bx) & MASK_Bx) );
}
static void SETARG_sBx(InstructionPtr i,int u) {
SETARG_Bx( i, u + MAXARG_sBx );
}
static int CREATE_ABC(int o, int a, int b, int c) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_A) & MASK_A) |
((b << POS_B) & MASK_B) |
((c << POS_C) & MASK_C) ;
}
static int CREATE_ABx(int o, int a, int bc) {
return ((o << POS_OP) & MASK_OP) |
((a << POS_A) & MASK_A) |
((bc << POS_Bx) & MASK_Bx) ;
}
// vector reallocation
static LuaValue[] realloc(LuaValue[] v, int n) {
LuaValue[] a = new LuaValue[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static Prototype[] realloc(Prototype[] v, int n) {
Prototype[] a = new Prototype[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LuaString[] realloc(LuaString[] v, int n) {
LuaString[] a = new LuaString[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LocVars[] realloc(LocVars[] v, int n) {
LocVars[] a = new LocVars[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static Upvaldesc[] realloc(Upvaldesc[] v, int n) {
Upvaldesc[] a = new Upvaldesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LexState.Vardesc[] realloc(LexState.Vardesc[] v, int n) {
LexState.Vardesc[] a = new LexState.Vardesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static LexState.Labeldesc[] grow(LexState.Labeldesc[] v, int min_n) {
return v == null ? new LexState.Labeldesc[2] : v.length < min_n ? realloc(v, v.length*2) : v;
}
static LexState.Labeldesc[] realloc(LexState.Labeldesc[] v, int n) {
LexState.Labeldesc[] a = new LexState.Labeldesc[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static int[] realloc(int[] v, int n) {
int[] a = new int[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static byte[] realloc(byte[] v, int n) {
byte[] a = new byte[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
static char[] realloc(char[] v, int n) {
char[] a = new char[n];
if ( v != null )
System.arraycopy(v, 0, a, 0, Math.min(v.length,n));
return a;
}
public int nCcalls;
Hashtable strings;
protected LuaC() {}
private LuaC(Hashtable strings) {
this.strings = strings;
}
/** Compile lua source into a Prototype.
* @param stream InputStream representing the text source conforming to lua source syntax.
* @param chunkname String name of the chunk to use.
@@ -250,59 +97,64 @@ public class LuaC extends Lua implements Globals.Compiler, Globals.Loader {
* @throws IOException
*/
public Prototype compile(InputStream stream, String chunkname) throws IOException {
return (new LuaC(new Hashtable())).luaY_parser(stream, chunkname);
}
/** @deprecated
* Use Globals.load(InputString, String, String) instead,
* or LuaC.compil(InputStream, String) and construct LuaClosure directly.
*/
public LuaValue load(InputStream stream, String chunkname, Globals globals) throws IOException {
return new LuaClosure(compile(stream, chunkname), globals);
}
/** Parse the input */
private Prototype luaY_parser(InputStream z, String name) throws IOException{
LexState lexstate = new LexState(this, z);
FuncState funcstate = new FuncState();
// lexstate.buff = buff;
lexstate.fs = funcstate;
lexstate.setinput( this, z.read(), z, (LuaString) LuaValue.valueOf(name) );
/* main func. is always vararg */
funcstate.f = new Prototype();
funcstate.f.source = (LuaString) LuaValue.valueOf(name);
lexstate.mainfunc(funcstate);
LuaC._assert (funcstate.prev == null);
/* all scopes should be correctly finished */
LuaC._assert (lexstate.dyd == null
|| (lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0));
return funcstate.f;
}
// look up and keep at most one copy of each string
public LuaString newTString(String s) {
return cachedLuaString(LuaString.valueOf(s));
}
// look up and keep at most one copy of each string
public LuaString newTString(LuaString s) {
return cachedLuaString(s);
}
public LuaString cachedLuaString(LuaString s) {
LuaString c = (LuaString) strings.get(s);
if (c != null)
return c;
strings.put(s, s);
return s;
}
public String pushfstring(String string) {
return string;
return (new CompileState()).luaY_parser(stream, chunkname);
}
public LuaFunction load(Prototype prototype, String chunkname, LuaValue env) throws IOException {
return new LuaClosure(prototype, env);
}
/** @deprecated
* Use Globals.load(InputString, String, String) instead,
* or LuaC.compile(InputStream, String) and construct LuaClosure directly.
*/
public LuaValue load(InputStream stream, String chunkname, Globals globals) throws IOException {
return new LuaClosure(compile(stream, chunkname), globals);
}
static class CompileState {
int nCcalls = 0;
private Hashtable strings = new Hashtable();
protected CompileState() {}
/** Parse the input */
private Prototype luaY_parser(InputStream z, String name) throws IOException{
LexState lexstate = new LexState(this, z);
FuncState funcstate = new FuncState();
// lexstate.buff = buff;
lexstate.fs = funcstate;
lexstate.setinput(this, z.read(), z, (LuaString) LuaValue.valueOf(name) );
/* main func. is always vararg */
funcstate.f = new Prototype();
funcstate.f.source = (LuaString) LuaValue.valueOf(name);
lexstate.mainfunc(funcstate);
LuaC._assert (funcstate.prev == null);
/* all scopes should be correctly finished */
LuaC._assert (lexstate.dyd == null
|| (lexstate.dyd.n_actvar == 0 && lexstate.dyd.n_gt == 0 && lexstate.dyd.n_label == 0));
return funcstate.f;
}
// look up and keep at most one copy of each string
public LuaString newTString(String s) {
return cachedLuaString(LuaString.valueOf(s));
}
// look up and keep at most one copy of each string
public LuaString newTString(LuaString s) {
return cachedLuaString(s);
}
public LuaString cachedLuaString(LuaString s) {
LuaString c = (LuaString) strings.get(s);
if (c != null)
return c;
strings.put(s, s);
return s;
}
public String pushfstring(String string) {
return string;
}
}
}

View File

@@ -557,7 +557,7 @@ public class IoLib extends TwoArgFunction {
int r;
if ( ( r = f.read(b,0,b.length) ) < 0 )
return NIL;
return LuaString.valueOf(b, 0, r);
return LuaString.valueUsing(b, 0, r);
}
public static LuaValue freaduntil(File f,boolean lineonly) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -580,7 +580,7 @@ public class IoLib extends TwoArgFunction {
}
return ( c < 0 && baos.size() == 0 )?
(LuaValue) NIL:
(LuaValue) LuaString.valueOf(baos.toByteArray());
(LuaValue) LuaString.valueUsing(baos.toByteArray());
}
public static LuaValue freadline(File f) throws IOException {
return freaduntil(f,true);

View File

@@ -160,7 +160,7 @@ public class StringLib extends TwoArgFunction {
if (c<0 || c>=256) argerror(a, "invalid value");
bytes[i] = (byte) c;
}
return LuaString.valueOf( bytes );
return LuaString.valueUsing( bytes );
}
/**
@@ -177,7 +177,7 @@ public class StringLib extends TwoArgFunction {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
DumpState.dump( ((LuaClosure)f).p, baos, true );
return LuaString.valueOf(baos.toByteArray());
return LuaString.valueUsing(baos.toByteArray());
} catch (IOException e) {
return error( e.getMessage() );
}
@@ -658,7 +658,7 @@ public class StringLib extends TwoArgFunction {
for ( int offset = 0; offset < bytes.length; offset += len ) {
s.copyInto( 0, bytes, offset, len );
}
return LuaString.valueOf( bytes );
return LuaString.valueUsing( bytes );
}
/**
@@ -672,7 +672,7 @@ public class StringLib extends TwoArgFunction {
byte[] b = new byte[n];
for ( int i=0, j=n-1; i<n; i++, j-- )
b[j] = (byte) s.luaByte(i);
return LuaString.valueOf( b );
return LuaString.valueUsing( b );
}
/**

View File

@@ -33,20 +33,20 @@ public class Str {
public static LuaString quoteString(String image) {
String s = image.substring(1, image.length()-1);
byte[] bytes = unquote(s);
return LuaString.valueOf(bytes);
return LuaString.valueUsing(bytes);
}
public static LuaString charString(String image) {
String s = image.substring(1, image.length()-1);
byte[] bytes = unquote(s);
return LuaString.valueOf(bytes);
return LuaString.valueUsing(bytes);
}
public static LuaString longString(String image) {
int i = image.indexOf('[', image.indexOf('[')+1)+1;
String s = image.substring(i,image.length()-i);
byte[] b = iso88591bytes(s);
return LuaString.valueOf(b);
return LuaString.valueUsing(b);
}
public static byte[] iso88591bytes( String s ) {

View File

@@ -1 +1 @@
version: 3.0
version: 3.0.1