Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert nested interpreter calls into a single loop #20

Merged
merged 10 commits into from
Feb 2, 2019
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,4 @@ docs/
/*.out
/string
/.luaj*
*.log
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ dependencies {
testCompile 'org.luaj:luaj-jse:2.+'
testCompile 'junit:junit:4.+'
testCompile 'org.hamcrest:hamcrest-library:1.3'

testCompile 'org.openjdk.jmh:jmh-core:1.21'
testCompile 'org.openjdk.jmh:jmh-generator-annprocess:1.21'
}

task sourcesJar(type: Jar, dependsOn: classes) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/squiddev/cobalt/LuaDouble.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
* @see ValueFactory#valueOf(int)
* @see ValueFactory#valueOf(double)
*/
public class LuaDouble extends LuaNumber {
public final class LuaDouble extends LuaNumber {
/**
* Constant LuaDouble representing NaN (not a number)
*/
Expand Down Expand Up @@ -80,7 +80,7 @@ public class LuaDouble extends LuaNumber {
/**
* The value being held by this instance.
*/
private final double v;
public final double v;

public static LuaNumber valueOf(double d) {
int id = (int) d;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/squiddev/cobalt/LuaInteger.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
* @see ValueFactory#valueOf(int)
* @see ValueFactory#valueOf(double)
*/
public class LuaInteger extends LuaNumber {
public final class LuaInteger extends LuaNumber {

private static final LuaInteger[] intValues = new LuaInteger[512];

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/squiddev/cobalt/LuaString.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
* @see ValueFactory#valueOf(String)
* @see ValueFactory#valueOf(byte[])
*/
public class LuaString extends LuaValue {
public final 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.
Expand Down
152 changes: 81 additions & 71 deletions src/main/java/org/squiddev/cobalt/OperationHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
import org.squiddev.cobalt.function.LuaFunction;

import static org.squiddev.cobalt.Constants.*;
import static org.squiddev.cobalt.ValueFactory.valueOf;
import static org.squiddev.cobalt.LuaDouble.valueOf;
import static org.squiddev.cobalt.LuaInteger.valueOf;

/**
* Handles arithmetic operations
Expand All @@ -43,97 +44,93 @@ public static LuaValue add(LuaState state, LuaValue left, LuaValue right) throws
}

public static LuaValue add(LuaState state, LuaValue left, LuaValue right, int leftIdx, int rightIdx) throws LuaError {
int tLeft = left.type(), tRight = right.type();
if ((tLeft == TNUMBER || tLeft == TSTRING) && (tRight == TNUMBER || tRight == TSTRING)) {
double dLeft = left.toDouble();
if (tLeft == TNUMBER || !Double.isNaN(dLeft)) {
double dRight = right.toDouble();
if (tRight == TNUMBER || !Double.isNaN(dRight)) return valueOf(dLeft + dRight);
}
if (left instanceof LuaInteger && right instanceof LuaInteger) {
int x = ((LuaInteger) left).v, y = ((LuaInteger) right).v;
int r = x + y;
if (((x ^ r) & (y ^ r)) >= 0) return valueOf(r);
}

return arithMetatable(state, Constants.ADD, left, right, leftIdx, rightIdx);
double dLeft, dRight;
if (checkNumber(left, dLeft = left.toDouble()) && checkNumber(right, dRight = right.toDouble())) {
return valueOf(dLeft + dRight);
} else {
return arithMetatable(state, ADD, left, right, leftIdx, rightIdx);
}
}

public static LuaValue sub(LuaState state, LuaValue left, LuaValue right) throws LuaError {
return sub(state, left, right, -1, -1);
}

public static LuaValue sub(LuaState state, LuaValue left, LuaValue right, int leftIdx, int rightIdx) throws LuaError {
int tLeft = left.type(), tRight = right.type();
if ((tLeft == TNUMBER || tLeft == TSTRING) && (tRight == TNUMBER || tRight == TSTRING)) {
double dLeft = left.toDouble();
if (tLeft == TNUMBER || !Double.isNaN(dLeft)) {
double dRight = right.toDouble();
if (tRight == TNUMBER || !Double.isNaN(dRight)) return valueOf(dLeft - dRight);
}
if (left instanceof LuaInteger && right instanceof LuaInteger) {
int x = ((LuaInteger) left).v, y = ((LuaInteger) right).v;
int r = x - y;
if (((x ^ r) & (y ^ r)) >= 0) return valueOf(r);
}

return arithMetatable(state, Constants.SUB, left, right, leftIdx, rightIdx);
double dLeft, dRight;
if (checkNumber(left, dLeft = left.toDouble()) && checkNumber(right, dRight = right.toDouble())) {
return valueOf(dLeft - dRight);
} else {
return arithMetatable(state, SUB, left, right, leftIdx, rightIdx);
}
}

public static LuaValue mul(LuaState state, LuaValue left, LuaValue right) throws LuaError {
return mul(state, left, right, -1, -1);
}

public static LuaValue mul(LuaState state, LuaValue left, LuaValue right, int leftIdx, int rightIdx) throws LuaError {
int tLeft = left.type(), tRight = right.type();
if ((tLeft == TNUMBER || tLeft == TSTRING) && (tRight == TNUMBER || tRight == TSTRING)) {
double dLeft = left.toDouble();
if (tLeft == TNUMBER || !Double.isNaN(dLeft)) {
double dRight = right.toDouble();
if (tRight == TNUMBER || !Double.isNaN(dRight)) return valueOf(dLeft * dRight);
}
if (left instanceof LuaInteger && right instanceof LuaInteger) {
return valueOf((long) ((LuaInteger) left).v * (long) ((LuaInteger) right).v);
}

return arithMetatable(state, Constants.MUL, left, right, leftIdx, rightIdx);
double dLeft, dRight;
if (checkNumber(left, dLeft = left.toDouble()) && checkNumber(right, dRight = right.toDouble())) {
return valueOf(dLeft * dRight);
} else {
return arithMetatable(state, MUL, left, right, leftIdx, rightIdx);
}
}

public static LuaValue div(LuaState state, LuaValue left, LuaValue right) throws LuaError {
return div(state, left, right, -1, -1);
}

public static LuaValue div(LuaState state, LuaValue left, LuaValue right, int leftIdx, int rightIdx) throws LuaError {
int tLeft = left.type(), tRight = right.type();
if ((tLeft == TNUMBER || tLeft == TSTRING) && (tRight == TNUMBER || tRight == TSTRING)) {
double dLeft = left.toDouble();
if (tLeft == TNUMBER || !Double.isNaN(dLeft)) {
double dRight = right.toDouble();
if (tRight == TNUMBER || !Double.isNaN(dRight)) return valueOf(div(dLeft, dRight));
}
double dLeft, dRight;
if (checkNumber(left, dLeft = left.toDouble()) && checkNumber(right, dRight = right.toDouble())) {
return valueOf(div(dLeft, dRight));
} else {
return arithMetatable(state, DIV, left, right, leftIdx, rightIdx);
}

return arithMetatable(state, Constants.DIV, left, right, leftIdx, rightIdx);
}

public static LuaValue mod(LuaState state, LuaValue left, LuaValue right) throws LuaError {
return mod(state, left, right, -1, -1);
}

public static LuaValue mod(LuaState state, LuaValue left, LuaValue right, int leftIdx, int rightIdx) throws LuaError {
int tLeft = left.type(), tRight = right.type();
if ((tLeft == TNUMBER || tLeft == TSTRING) && (tRight == TNUMBER || tRight == TSTRING)) {
double dLeft = left.toDouble();
if (tLeft == TNUMBER || !Double.isNaN(dLeft)) {
double dRight = right.toDouble();
if (tRight == TNUMBER || !Double.isNaN(dRight)) return valueOf(mod(dLeft, dRight));
}
double dLeft, dRight;
if (checkNumber(left, dLeft = left.toDouble()) && checkNumber(right, dRight = right.toDouble())) {
return valueOf(mod(dLeft, dRight));
} else {
return arithMetatable(state, MOD, left, right, leftIdx, rightIdx);
}

return arithMetatable(state, Constants.MOD, left, right, leftIdx, rightIdx);
}

public static LuaValue pow(LuaState state, LuaValue left, LuaValue right) throws LuaError {
return pow(state, left, right, -1, -1);
}

public static LuaValue pow(LuaState state, LuaValue left, LuaValue right, int leftIdx, int rightIdx) throws LuaError {
int tLeft = left.type(), tRight = right.type();
if ((tLeft == TNUMBER || tLeft == TSTRING) && (tRight == TNUMBER || tRight == TSTRING)) {
return ValueFactory.valueOf(Math.pow(left.checkArith(), right.checkArith()));
double dLeft, dRight;
if (checkNumber(left, dLeft = left.toDouble()) && checkNumber(right, dRight = right.toDouble())) {
return valueOf(Math.pow(dLeft, dRight));
} else {
return arithMetatable(state, POW, left, right, leftIdx, rightIdx);
}

return arithMetatable(state, Constants.POW, left, right, leftIdx, rightIdx);
}

/**
Expand Down Expand Up @@ -174,7 +171,26 @@ public static double mod(double lhs, double rhs) {
* @return {@link LuaValue} resulting from metatag processing
* @throws LuaError if metatag was not defined for either operand
*/
private static LuaValue arithMetatable(LuaState state, LuaValue tag, LuaValue left, LuaValue right, int leftStack, int rightStack) throws LuaError {
public static LuaValue arithMetatable(LuaState state, LuaValue tag, LuaValue left, LuaValue right, int leftStack, int rightStack) throws LuaError {
return call(state, getMetatable(state, tag, left, right, leftStack, rightStack), left, right);
}

/**
* Perform metatag processing for arithmetic operations.
*
* Finds the supplied metatag value for {@code this} or {@code op2} and invokes it,
* or throws {@link LuaError} if neither is defined.
*
* @param state The current lua state
* @param tag The metatag to look up
* @param left The left operand value to perform the operation with
* @param right The other operand value to perform the operation with
* @param leftStack Stack index of the LHS
* @param rightStack Stack index of the RHS
* @return {@link LuaValue} resulting from metatag processing
* @throws LuaError if metatag was not defined for either operand
*/
public static LuaValue getMetatable(LuaState state, LuaValue tag, LuaValue left, LuaValue right, int leftStack, int rightStack) throws LuaError {
LuaValue h = left.metatag(state, tag);
if (h.isNil()) {
h = right.metatag(state, tag);
Expand All @@ -186,7 +202,7 @@ private static LuaValue arithMetatable(LuaState state, LuaValue tag, LuaValue le
throw ErrorFactory.operandError(state, left, "perform arithmetic on", leftStack);
}
}
return OperationHelper.call(state, h, left, right);
return h;
}

/**
Expand Down Expand Up @@ -222,11 +238,11 @@ public static LuaValue concat(LuaState state, LuaValue left, LuaValue right, int
}
}

public static LuaString concat(LuaString left, LuaString right) throws LuaError {
public static LuaString concat(LuaString left, LuaString right) {
byte[] b = new byte[left.length + right.length];
System.arraycopy(left.bytes, left.offset, b, 0, left.length);
System.arraycopy(right.bytes, right.offset, b, left.length, right.length);
return ValueFactory.valueOf(b);
return LuaString.valueOf(b);
}
//endregion

Expand Down Expand Up @@ -351,10 +367,15 @@ public static LuaValue neg(LuaState state, LuaValue value) throws LuaError {
}

public static LuaValue neg(LuaState state, LuaValue value, int stack) throws LuaError {
int tValue = value.type();
if (tValue == TNUMBER) {
return valueOf(-value.checkArith());
} else if (tValue == TSTRING) {
int type = value.type();
if (type == TNUMBER) {
if (value instanceof LuaInteger) {
int x = ((LuaInteger) value).v;
if (x != Integer.MIN_VALUE) return valueOf(-x);
}

return valueOf(-value.toDouble());
} else if (type == TSTRING) {
double res = value.toDouble();
if (!Double.isNaN(res)) return valueOf(-res);
}
Expand All @@ -366,6 +387,10 @@ public static LuaValue neg(LuaState state, LuaValue value, int stack) throws Lua

return OperationHelper.call(state, meta, value);
}

private static boolean checkNumber(LuaValue lua, double value) {
return lua.type() == TNUMBER || !Double.isNaN(value);
}
//endregion

//region Calling
Expand Down Expand Up @@ -444,21 +469,6 @@ public static Varargs invoke(LuaState state, LuaValue function, Varargs args, in
}
}

public static Varargs onInvoke(LuaState state, LuaValue function, Varargs args) throws LuaError {
return onInvoke(state, function, args, -1);
}

public static Varargs onInvoke(LuaState state, LuaValue function, Varargs args, int stack) throws LuaError {
if (function.isFunction()) {
return ((LuaFunction) function).onInvoke(state, args);
} else {
LuaValue meta = function.metatag(state, Constants.CALL);
if (!meta.isFunction()) throw ErrorFactory.operandError(state, function, "call", stack);

return ((LuaFunction) meta).onInvoke(state, ValueFactory.varargsOf(function, args));
}
}

//endregion

//region Tables
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/squiddev/cobalt/Prototype.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
package org.squiddev.cobalt;

import org.squiddev.cobalt.function.LocalVariable;
import org.squiddev.cobalt.function.LuaInterpreter;
import org.squiddev.cobalt.function.LuaInterpretedFunction;

import static org.squiddev.cobalt.compiler.LoadState.getShortName;

Expand All @@ -35,10 +35,10 @@
* This is both a straight translation of the corresponding C type,
* and the main data structure for execution of compiled lua bytecode.
*
* See documentatation on {@link LuaInterpreter} for information on how to load
* See documentatation on {@link LuaInterpretedFunction} for information on how to load
* and execute a {@link Prototype}.
*
* @see LuaInterpreter
* @see LuaInterpretedFunction
*/
public final class Prototype {
/* constants used by the function */
Expand Down
Loading