Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.ssssssss.script.compile.MagicScriptCompiler Maven / Gradle / Ivy
package org.ssssssss.script.compile;
import org.ssssssss.script.MagicScriptContext;
import org.ssssssss.script.asm.ClassWriter;
import org.ssssssss.script.asm.Handle;
import org.ssssssss.script.asm.Label;
import org.ssssssss.script.asm.MethodVisitor;
import org.ssssssss.script.asm.Opcodes;
import org.ssssssss.script.asm.Type;
import org.ssssssss.script.parsing.Span;
import org.ssssssss.script.parsing.VarIndex;
import org.ssssssss.script.parsing.ast.Expression;
import org.ssssssss.script.parsing.ast.Node;
import org.ssssssss.script.parsing.ast.VariableSetter;
import org.ssssssss.script.parsing.ast.binary.AssigmentOperation;
import org.ssssssss.script.parsing.ast.statement.VariableAccess;
import org.ssssssss.script.runtime.MagicScriptRuntime;
import org.ssssssss.script.runtime.RuntimeContext;
import org.ssssssss.script.runtime.Variables;
import org.ssssssss.script.runtime.function.MagicScriptLambdaFunction;
import org.ssssssss.script.runtime.handle.ArithmeticHandle;
import org.ssssssss.script.runtime.handle.BitHandle;
import org.ssssssss.script.runtime.handle.FunctionCallHandle;
import org.ssssssss.script.runtime.handle.OperatorHandle;
import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicLong;
import static org.ssssssss.script.asm.ClassWriter.COMPUTE_FRAMES;
import static org.ssssssss.script.asm.ClassWriter.COMPUTE_MAXS;
import static org.ssssssss.script.compile.Descriptor.make_descriptor;
/**
* 脚本编译器
*/
public class MagicScriptCompiler implements Opcodes {
private static final AtomicLong COUNTER = new AtomicLong(1);
private final ClassWriter classWriter;
private final Long id = COUNTER.getAndIncrement();
/**
* < <= == === != !=== >= > 等操作符处理器
*/
private static final Handle OPERATOR_HANDLE = makeHandle(OperatorHandle.class);
/**
* << >> >>> & ^ | 运算
*/
private static final Handle BIT_HANDLE = makeHandle(BitHandle.class);
/**
* 方法调用、lambda调用、函数调用处理器
*/
private static final Handle FUNCTION_HANDLE = makeHandle(FunctionCallHandle.class);
/**
* + - * / % 处理器
*/
private static final Handle ARITHMETIC_HANDLE = makeHandle(ArithmeticHandle.class);
private final Stack methodVisitors = new Stack<>();
private final Stack> vars = new Stack<>();
private final Stack labelStack = new Stack<>();
/*
* 替换为双端队列实现栈,因为Stack在for遍历时先从栈尾开始
*/
private final Deque> finallyStack = new LinkedList<>();
private final Set varIndices;
/**
* -1 ~ 5的int值
*/
private static final int[] ICONST = {ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5};
private final List spans = new ArrayList<>();
private int functionIndex = 0;
private int tempIndex = 4;
private final boolean debug;
private int lastLineNumber = -1;
private boolean contextInited = false;
public MagicScriptCompiler(Set varIndices, boolean debug) {
this.varIndices = varIndices;
this.debug = debug;
// 创建类并继承 MagicScriptRuntime
classWriter = new ClassWriter(COMPUTE_FRAMES | COMPUTE_MAXS);
classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, getClassName(), null, getJvmType(MagicScriptRuntime.class), null);
classWriter.visitSource(getClassName() + ".ms", null);
createMethod(ACC_PUBLIC, "", make_descriptor(void.class));
this.load0()
.invoke(INVOKESPECIAL, MagicScriptRuntime.class, "", void.class)
.insn(RETURN)
.pop();
// 创建execute方法
createMethod(ACC_PUBLIC, "execute", make_descriptor(Object.class, MagicScriptContext.class));
initContext();
}
public List getSpans() {
return spans;
}
/**
* 创建方法
*
* @param access 访问属性
* @param methodName 方法名
* @param descriptor 方法描述
*/
public MagicScriptCompiler createMethod(int access, String methodName, String descriptor) {
MethodVisitor visitor = classWriter.visitMethod(access, methodName, descriptor, null, null);
visitor.visitCode();
methodVisitors.push(visitor);
vars.push(new ArrayList<>());
labelStack.push(new Label[2]);
return this;
}
public int getTempIndex() {
return tempIndex++;
}
/**
* 获取lambda函数下标
*/
public int getFunctionIndex() {
return ++functionIndex;
}
/**
* 标识continue和break位置
*/
public MagicScriptCompiler markLabel(Label start, Label end) {
labelStack.push(new Label[]{start, end});
return this;
}
/**
* 消除标记
*/
public MagicScriptCompiler exitLabel() {
labelStack.pop();
return this;
}
/**
* 跳转到continue位置
*/
public MagicScriptCompiler start() {
return jump(GOTO, labelStack.peek()[0]);
}
/**
* 跳转到break位置
*/
public MagicScriptCompiler end() {
return jump(GOTO, labelStack.peek()[1]);
}
/**
* 访问AST节点
*/
public MagicScriptCompiler visit(Node node) {
// 对于赋值语句的特殊处理
if (node instanceof AssigmentOperation) {
AssigmentOperation operation = (AssigmentOperation) node;
// 如果是a = b = 1这种情况,则需要读取a的值
if (operation.getLeftOperand() instanceof VariableAccess) {
return compile(node, true).compile(operation.getLeftOperand());
}
}
return compile(node, false);
}
/**
* 编译AST节点
*/
public MagicScriptCompiler compile(Node node) {
return compile(node, false);
}
public MagicScriptCompiler lineNumber(Span span) {
spans.add(span);
MethodVisitor mv = self();
Label label = new Label();
// 设置行号(节点序号)
mv.visitLabel(label);
mv.visitLineNumber(spans.size() - 1, label);
return this;
}
public MagicScriptCompiler loadContext() {
if (contextInited || methodVisitors.size() > 1) {
load0().self().visitFieldInsn(GETFIELD, getClassName(), "context", Type.getDescriptor(MagicScriptContext.class));
return this;
}
return load1();
}
public MagicScriptCompiler newRuntimeContext() {
return this.typeInsn(NEW, RuntimeContext.class)
.insn(DUP)
.loadContext()
.load2()
.invoke(INVOKESPECIAL, RuntimeContext.class, "", void.class, MagicScriptContext.class, Variables.class);
}
/**
* 编译AST节点
*
* @param node AST节点
* @param pop 是否需要弹出栈顶
*/
public MagicScriptCompiler compile(Node node, boolean pop) {
if (node == null) {
return insn(ACONST_NULL);
} else {
lineNumber(node.getSpan());
if (debug) {
Span.Line currentLine = node.getSpan().getLine();
int line = currentLine.getLineNumber();
if (lastLineNumber != line) {
this.loadContext()
.visitInt(line)
.visitInt(currentLine.getStartCol())
.visitInt(currentLine.getEndLineNumber())
.visitInt(currentLine.getEndCol())
.load2()
.invoke(INVOKEVIRTUAL, MagicScriptContext.class, "pause", void.class, int.class, int.class, int.class, int.class, Variables.class);
lastLineNumber = line;
}
}
// 编译该节点
node.compile(this);
}
// 对于赋值语句的特殊处理,因为赋值语句有两种
// 不带返回值的: a+=1
// 带返回值的 xxx.xx = 1
if (node instanceof AssigmentOperation) {
AssigmentOperation operation = (AssigmentOperation) node;
if (operation.getLeftOperand() instanceof VariableSetter && operation.getLeftOperand() instanceof VariableAccess) {
return this;
}
}
// 对于带有返回值的表达式,且需要弹出栈顶时,追加指令POP
return pop && node instanceof Expression ? insn(POP) : this;
}
/**
* 设定tryCatch跳转
* 如果在Label start到Label end代码范围内捕获到type异常,则跳转到Label handler
* type为null则表示finally,只要抛异常就跳转到handler
*/
public MagicScriptCompiler tryCatch(Label start, Label end, Label handle, Class> target) {
self().visitTryCatchBlock(start, end, handle, getJvmType(target));
return this;
}
/**
* 访问
*/
public MagicScriptCompiler visit(List extends Node> nodes) {
nodes.forEach(this::visit);
return this;
}
/**
* 编译
*/
public MagicScriptCompiler compile(List extends Node> nodes) {
nodes.forEach(it -> compile(it, true));
return this;
}
/**
* 加载this
*/
public MagicScriptCompiler load0() {
self().visitVarInsn(ALOAD, 0);
return this;
}
/**
* 加载context
*/
public MagicScriptCompiler load1() {
self().visitVarInsn(ALOAD, 1);
return this;
}
/**
* 加载context
*/
public void newArrayList() {
this.typeInsn(NEW, ArrayList.class)
.insn(DUP)
.invoke(INVOKESPECIAL, ArrayList.class, "", void.class);
}
/**
* 加载Variables
*/
public MagicScriptCompiler load2() {
self().visitVarInsn(ALOAD, 2);
return this;
}
/**
* 加载3号变量,一般指异常(临时变量)
*/
public MagicScriptCompiler load3() {
self().visitVarInsn(ALOAD, 3);
return this;
}
public MagicScriptCompiler load4() {
self().visitVarInsn(ALOAD, 4);
return this;
}
/**
* 加载变量
*/
public MagicScriptCompiler load(int index) {
return load2().visitInt(index).invoke(INVOKEVIRTUAL, Variables.class, "getValue", Object.class, int.class);
}
/**
* 加载变量
*/
public MagicScriptCompiler load(VarIndex varIndex) {
return load(varIndex.getIndex());
}
/**
* 加载变量
*
* @param name 变量名
*/
public MagicScriptCompiler load(String name) {
int index = vars.peek().indexOf(name) + 1;
if (index > 0) { // 如果当前栈中有,则直接使用
return load(index);
} else {
// 从环境中获取
this.load1()
.ldc(name)
.invoke(INVOKEVIRTUAL, MagicScriptContext.class, "getEnvironmentValue", Object.class, String.class);
}
return this;
}
public MagicScriptCompiler label(Label label) {
self().visitLabel(label);
return this;
}
/**
* 跳转
*/
public MagicScriptCompiler jump(int opcode, Label label) {
self().visitJumpInsn(opcode, label);
return this;
}
/**
* 移除变量
*/
public MagicScriptCompiler remove(VarIndex varIndex) {
if (varIndex == null) {
return this;
}
return remove(varIndex.getName());
}
/**
* 移除变量
*/
public MagicScriptCompiler remove(String name) {
List varList = vars.peek();
int index = varList.indexOf(name);
if (index > -1) {
varList.set(index, null);
}
return this;
}
/**
* 配合pre_store使用,保存至数组中
*/
public MagicScriptCompiler store() {
return invoke(INVOKEVIRTUAL, Variables.class, "setValue", void.class, int.class, Object.class);
}
/**
* 配合pre_store使用,保存至数组中
*/
public MagicScriptCompiler store(VarIndex varIndex) {
return varIndex.isScoped() ? scopeStore() : store();
}
/**
* 配合pre_store使用,保存至数组中
*/
public MagicScriptCompiler scopeStore() {
return invoke(INVOKEVIRTUAL, Variables.class, "setScopeValue", void.class, int.class, Object.class);
}
/**
* 保存变量
*/
public MagicScriptCompiler store(int index) {
self().visitVarInsn(ASTORE, index);
return this;
}
/**
* 保存变量
*/
public MagicScriptCompiler frame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
self().visitFrame(type, numLocal, local, numStack, stack);
return this;
}
/**
* 写变量前的准备
*/
public MagicScriptCompiler pre_store(int index) {
return load2().visitInt(index);
}
/**
* 写变量前的准备
*/
public MagicScriptCompiler pre_store(VarIndex varIndex) {
return pre_store(varIndex.getIndex());
}
public MagicScriptCompiler bipush(int value) {
self().visitIntInsn(BIPUSH, value);
return this;
}
public MagicScriptCompiler typeInsn(int opcode, Class> target) {
self().visitTypeInsn(opcode, getJvmType(target));
return this;
}
/**
* 二元运算
*
* @param methodName 运算方法
*/
public MagicScriptCompiler operator(String methodName) {
self().visitInvokeDynamicInsn(methodName, MethodType.genericMethodType(2).toMethodDescriptorString(), OPERATOR_HANDLE, 2);
return this;
}
/**
* 位运算
*
* @param methodName 运算方法
*/
public MagicScriptCompiler bit(String methodName) {
self().visitInvokeDynamicInsn(methodName, MethodType.genericMethodType(2).toMethodDescriptorString(), BIT_HANDLE, 2);
return this;
}
/**
* 将方法转为lambda
*
* @param methodName 方法名
*/
public MagicScriptCompiler lambda(String methodName) {
load0();
Handle metaFactory = new Handle(H_INVOKESTATIC, getJvmType(LambdaMetafactory.class), "metafactory", make_descriptor(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class), false);
String descriptor = make_descriptor(Object.class, Variables.class, Object[].class);
Handle impl = new Handle(H_INVOKEVIRTUAL, getClassName(), methodName, descriptor, false);
self().visitInvokeDynamicInsn("apply", "(L" + getClassName() + ";)" + Type.getType(MagicScriptLambdaFunction.class).getDescriptor(), metaFactory, Type.getType(descriptor), impl, Type.getType(descriptor));
load2().self().visitMethodInsn(INVOKEVIRTUAL, getClassName(), "createLambda", make_descriptor(MagicScriptLambdaFunction.class, MagicScriptLambdaFunction.class, Variables.class), false);
return this;
}
/**
* invokedynamic调用
*
* @param methodName 方法名
* @param arguments 参数个数
*/
public MagicScriptCompiler call(String methodName, int arguments) {
self().visitInvokeDynamicInsn(methodName, MethodType.genericMethodType(arguments).toMethodDescriptorString(), FUNCTION_HANDLE, arguments);
return this;
}
/**
* 执行算术运算
*
* @param methodName 方法名
*/
public MagicScriptCompiler arithmetic(String methodName) {
self().visitInvokeDynamicInsn(methodName, MethodType.genericMethodType(2).toMethodDescriptorString(), ARITHMETIC_HANDLE, 2);
return this;
}
/**
* 将int值装箱
*/
public MagicScriptCompiler asInteger() {
return invoke(INVOKESTATIC, Integer.class, "valueOf", Integer.class, int.class);
}
/**
* 将boolean值装箱
*/
public MagicScriptCompiler asBoolean() {
return invoke(INVOKESTATIC, Boolean.class, "valueOf", Boolean.class, boolean.class);
}
/**
* 调用方法
*
* @param opcode 调用类型
* @param target 目标类
* @param method 方法名
* @param returnType 返回值类型
* @param argumentTypes 参数类型
*/
public MagicScriptCompiler invoke(int opcode, Class> target, String method, Class> returnType, Class>... argumentTypes) {
return invoke(opcode, target, method, false, returnType, argumentTypes);
}
/**
* 调用方法
*
* @param opcode 调用类型
* @param target 目标类
* @param method 方法名
* @param isInterface 是否是接口
* @param returnType 返回值类型
* @param argumentTypes 参数类型
*/
public MagicScriptCompiler invoke(int opcode, Class> target, String method, boolean isInterface, Class> returnType, Class>... argumentTypes) {
self().visitMethodInsn(opcode, getJvmType(target), method, make_descriptor(returnType, argumentTypes), isInterface);
return this;
}
public MagicScriptCompiler ldc(Object value) {
self().visitLdcInsn(value);
return this;
}
public MagicScriptCompiler insn(int opcode) {
self().visitInsn(opcode);
return this;
}
public void intInsn(int opcode, int operand) {
self().visitIntInsn(opcode, operand);
}
/**
* 编译数组
*/
public MagicScriptCompiler newArray(List values) {
int size = values.size();
visitInt(size).typeInsn(ANEWARRAY, Object.class);
for (int i = 0; i < size; i++) {
insn(DUP).visitInt(i).visit(values.get(i)).insn(AASTORE);
}
return this;
}
/**
* 编译int值
*/
public MagicScriptCompiler visitInt(int value) {
if (value >= -1 && value <= 5) {
insn(ICONST[value + 1]);
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
intInsn(BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
intInsn(SIPUSH, value);
} else {
ldc(value);
}
return this;
}
private void initContext() {
if (!this.contextInited) {
this.load0().load1();
self().visitFieldInsn(PUTFIELD, getClassName(), "context", Type.getDescriptor(MagicScriptContext.class));
this.contextInited = true;
// var2 = context.createVariables(this, varIndices.size())
this.load1()
.load0()
.visitInt(varIndices.size())
.invoke(INVOKEVIRTUAL, MagicScriptContext.class, "createVariables", Variables.class, MagicScriptRuntime.class, int.class)
.store(2);
}
}
public void loadVars() {
// 对于未定义变量值的,从环境中获取
// var2[xx] = super.getEnvironmentValue(varIndex.getName())
this.varIndices.stream()
.filter(VarIndex::isReference)
.forEach(varIndex -> this.load2()
.visitInt(varIndex.getIndex())
.load1()
.ldc(varIndex.getName())
.invoke(INVOKEVIRTUAL, MagicScriptContext.class, "getEnvironmentValue", Object.class, String.class)
.store()
);
}
public String visitMethod(String methodName, Runnable callback) {
return visitMethod(methodName, Collections.emptyList(), Collections.emptyList(), callback);
}
public String visitMethod(String methodName, List childNodes, List parameters, Runnable callback) {
childNodes.forEach(it -> it.visitMethod(this));
int index = this.getFunctionIndex();
methodName = methodName + "_" + index;
this.createMethod(ACC_PRIVATE, methodName, Descriptor.make_descriptor(Object.class, Variables.class, Object[].class))
.load1() // Variables
.load2() // 传入的参数
.visitInt(index)
// 构建参数
.visitInt(parameters.size())
.intInsn(NEWARRAY, T_INT); // new int[parameters.size()]
for (int i = 0; i < parameters.size(); i++) {
this.insn(DUP)
.visitInt(i)
.visitInt(parameters.get(i).getIndex())
.insn(IASTORE);
}
// 复制变量
this.invoke(INVOKEVIRTUAL, Variables.class, "copy", Variables.class, Object[].class, int.class, int[].class)
.store(2);
callback.run();
this.pop();
return methodName;
}
public String visitMethod(String methodName, List childNodes, List parameters) {
return visitMethod(methodName, childNodes, parameters, () -> this.compile(childNodes));
}
public Deque> finallyBlockStack() {
return finallyStack;
}
public void pushFinallyBlock(List finallyBlock) {
finallyStack.addFirst(finallyBlock);
}
public List popFinallyBlock() {
return finallyStack.pollFirst();
}
public MagicScriptCompiler pop() {
MethodVisitor visitor = methodVisitors.pop();
visitor.visitInsn(ACONST_NULL);
visitor.visitInsn(ARETURN);
visitor.visitMaxs(0, 0);
visitor.visitEnd();
vars.pop();
labelStack.pop();
return this;
}
public byte[] bytecode() {
pop();
classWriter.visitEnd();
return classWriter.toByteArray();
}
/**
* 获取类名
*/
public String getClassName() {
return "MagicScript_" + id;
}
private MethodVisitor self() {
return methodVisitors.peek();
}
private static String getJvmType(Class> target) {
return target == null ? null : target.getName().replace(".", "/");
}
private static Handle makeHandle(Class> target) {
return new Handle(H_INVOKESTATIC,
getJvmType(target),
"bootstrap",
make_descriptor(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class),
false);
}
}