Skip to content

Commit

Permalink
Better trap API, hooked up sandboxing to JVM code generation.
Browse files Browse the repository at this point in the history
  • Loading branch information
danielperano committed Nov 7, 2023
1 parent fe1ae1e commit 2b4e287
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 58 deletions.
35 changes: 28 additions & 7 deletions Lang/src/main/java/chipmunk/vm/ChipmunkVM.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@
import chipmunk.vm.invoke.security.AllowChipmunkLinkage;
import chipmunk.vm.invoke.security.LinkingPolicy;
import chipmunk.vm.invoke.security.SecurityMode;
import chipmunk.vm.jvm.CompilationUnit;
import chipmunk.vm.jvm.JvmCompilation;
import chipmunk.vm.jvm.JvmCompiler;
import chipmunk.vm.jvm.JvmCompilerConfig;
import chipmunk.vm.jvm.*;
import chipmunk.vm.scheduler.Scheduler;
import jdk.dynalink.linker.GuardedInvocation;

Expand Down Expand Up @@ -78,7 +75,7 @@ public ChipmunkVM(SecurityMode securityMode) {
// TODO - make configurable
scriptPool = new ForkJoinPool(4,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
(thread, throwable) -> {throwable.printStackTrace();},
(thread, throwable) -> throwable.printStackTrace(),
true,
4,
8,
Expand All @@ -88,7 +85,7 @@ public ChipmunkVM(SecurityMode securityMode) {
TimeUnit.SECONDS);
scheduler = new Scheduler();

defaultJvmCompilerConfig = new JvmCompilerConfig();
defaultJvmCompilerConfig = new JvmCompilerConfig(defaultLinkPolicy);
}

public LinkingPolicy getDefaultLinkPolicy(){
Expand Down Expand Up @@ -255,7 +252,7 @@ public ChipmunkModule load(BinaryModule module) {
}

public ChipmunkModule load(JvmCompiler jvmCompiler, BinaryModule module) {
JvmCompilation compilation = new JvmCompilation(module, new ModuleLoader());
JvmCompilation compilation = new JvmCompilation(module, new ModuleLoader(), defaultLinkPolicy);
return jvmCompiler.compileModule(compilation);
}

Expand Down Expand Up @@ -429,4 +426,28 @@ protected boolean isSamType(Class<?> interfaceType){
return nonDefaults == 1;
}

public static void trap(Object payload){

}

public static void backJump(TrapSite site){

}

public static void trapObjectAlloc(TrapSite site, Class<?> objectType){

}

public static void trapArrayAlloc(TrapSite site, Class<?> arrayType, int dimensions, int capacity){

}

public static void trapMethodCall(TrapSite site, MethodIdentifier method){

}

public static void trapObjectInit(TrapSite site, Object object){

}

}
13 changes: 8 additions & 5 deletions Lang/src/main/java/chipmunk/vm/TrapHandler.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package chipmunk.vm;

import chipmunk.vm.jvm.MethodIdentifier;
import chipmunk.vm.jvm.TrapSite;

public interface TrapHandler {

default void runtimeTrap(Object payload){}

// TODO - replace this verbosity with dynamically computed constants
default void backJump(TrapSite site){}
default void methodCall(TrapSite site,
String targetCls, String targetMethodName, String targetMethodSignature){}
default void methodCall(TrapSite site, MethodIdentifier method){}

default void arrayAlloc(TrapSite site, int dimensions, int capacity){}
default void arrayAlloc(TrapSite site, Class<?> arrayClass, int dimensions, int capacity){}

default void objectAlloc(TrapSite site, String targetCls, String targetConstructorSignature){}
default void objectAlloc(TrapSite site, Class<?> type){}

default void objectInit(TrapSite site, Object object){

}

}
11 changes: 10 additions & 1 deletion Lang/src/main/java/chipmunk/vm/jvm/JvmCompilation.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import chipmunk.binary.BinaryModule;
import chipmunk.vm.ModuleLoader;
import chipmunk.vm.invoke.security.LinkingPolicy;

import java.util.ArrayDeque;
import java.util.Deque;
Expand All @@ -38,11 +39,15 @@ public class JvmCompilation {
protected final Set<String> bindings;
protected final Deque<NamespaceInfo> namespaceInfo;

public JvmCompilation(BinaryModule module, ModuleLoader loader){
protected final LinkingPolicy policy;

public JvmCompilation(BinaryModule module, ModuleLoader loader, LinkingPolicy policy){
this.module = module;
this.loader = loader;
namespaceInfo = new ArrayDeque<>();
bindings = new HashSet<>();

this.policy = policy;
}

public BinaryModule getModule() {
Expand All @@ -53,6 +58,10 @@ public ModuleLoader getLoader(){
return loader;
}

public LinkingPolicy getLinkingPolicy(){
return policy;
}

public String getPackagePrefix() {
return packagePrefix;
}
Expand Down
35 changes: 20 additions & 15 deletions Lang/src/main/java/chipmunk/vm/jvm/JvmCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import chipmunk.vm.ModuleLoader;
import chipmunk.vm.invoke.Binder;
import chipmunk.vm.invoke.security.AllowChipmunkLinkage;
import chipmunk.vm.invoke.security.LinkingPolicy;
import org.objectweb.asm.*;

import java.io.IOException;
Expand All @@ -42,8 +43,8 @@ public class JvmCompiler {

protected final JvmCompilerConfig config;

public JvmCompiler(){
this(new JvmCompilerConfig());
public JvmCompiler(LinkingPolicy linkingPolicy){
this(new JvmCompilerConfig(linkingPolicy));
}

public JvmCompiler(JvmCompilerConfig config){
Expand Down Expand Up @@ -134,7 +135,7 @@ public ChipmunkScript compile(CompilationUnit sources) throws IOException, Binar
}

public ChipmunkModule compileModule(BinaryModule module){
return compileModule(new JvmCompilation(module, new ModuleLoader()));
return compileModule(new JvmCompilation(module, new ModuleLoader(), config.getLinkingPolicy()));
}

public ChipmunkModule compileModule(JvmCompilation compilation){
Expand Down Expand Up @@ -191,7 +192,8 @@ public ChipmunkModule compileModule(JvmCompilation compilation){
getDependencies.visitEnd();*/

// Module constructor/initializer
MethodVisitor moduleInit = new JvmSandboxingVisitor(moduleWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", Type.getMethodType(Type.VOID_TYPE).getDescriptor(), null, null), null);
var sandbox = new SandboxContext(compilation.getPrefixedModuleName(), "<init>", Type.getMethodType(Type.VOID_TYPE).getDescriptor(), compilation.getLinkingPolicy());
MethodVisitor moduleInit = new Sandbox(moduleWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", Type.getMethodType(Type.VOID_TYPE).getDescriptor(), null, null), sandbox);
moduleInit.visitCode();
moduleInit.visitVarInsn(Opcodes.ALOAD, 0);
moduleInit.visitMethodInsn(Opcodes.INVOKESPECIAL, objType.getInternalName(), "<init>", Type.getMethodType(Type.VOID_TYPE).getDescriptor(), false);
Expand Down Expand Up @@ -247,7 +249,8 @@ protected Class<?> visitChipmunkClass(JvmCompilation compilation, BinaryClass cl
cClassWriter.visitAnnotation(Type.getDescriptor(AllowChipmunkLinkage.class), true).visitEnd();

// Generate class constructor
MethodVisitor clsConstructor = new JvmSandboxingVisitor(cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", Type.getMethodType(Type.VOID_TYPE).getDescriptor(), null, null), null);
var sandbox = new SandboxContext(qualifiedCClassName, "<init>", Type.getMethodType(Type.VOID_TYPE).getDescriptor(), compilation.getLinkingPolicy());
MethodVisitor clsConstructor = new Sandbox(cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", Type.getMethodType(Type.VOID_TYPE).getDescriptor(), null, null), sandbox);
clsConstructor.visitCode();
clsConstructor.visitVarInsn(Opcodes.ALOAD, 0);
clsConstructor.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", Type.getMethodType(Type.VOID_TYPE).getDescriptor(), false);
Expand Down Expand Up @@ -299,7 +302,8 @@ protected Class<?> visitChipmunkClass(JvmCompilation compilation, BinaryClass cl
// 1+: binaryConstructor params
Type[] constructorTypes = paramTypes(binaryConstructor.getArgCount() - 1);

MethodVisitor insConstructor = new JvmSandboxingVisitor(cInsWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", Type.getMethodType(Type.VOID_TYPE, initTypes).getDescriptor(), null, null), null);
sandbox = new SandboxContext(qualifiedInsName, "<init>", Type.getMethodType(Type.VOID_TYPE, initTypes).getDescriptor(), compilation.getLinkingPolicy());
MethodVisitor insConstructor = new Sandbox(cInsWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", Type.getMethodType(Type.VOID_TYPE, initTypes).getDescriptor(), null, null), sandbox);
insConstructor.visitCode();
insConstructor.visitVarInsn(Opcodes.ALOAD, 0);
insConstructor.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", Type.getMethodType(Type.VOID_TYPE).getDescriptor(), false);
Expand All @@ -313,7 +317,7 @@ protected Class<?> visitChipmunkClass(JvmCompilation compilation, BinaryClass cl
if(cls.getInstanceNamespace().has("toString")
&& cls.getInstanceNamespace().getEntry("toString").getType() == FieldType.METHOD){

MethodVisitor toString = new JvmSandboxingVisitor(cInsWriter.visitMethod(Opcodes.ACC_PUBLIC, "toString", Type.getMethodType(Type.getType(String.class)).getDescriptor(), null, null), null);
MethodVisitor toString = cInsWriter.visitMethod(Opcodes.ACC_PUBLIC, "toString", Type.getMethodType(Type.getType(String.class)).getDescriptor(), null, null);
toString.visitCode();

// Invoke the toString() method defined in Chipmunk code
Expand Down Expand Up @@ -364,7 +368,7 @@ protected Class<?> visitChipmunkClass(JvmCompilation compilation, BinaryClass cl
Type insType = Type.getObjectType(jvmName(qualifiedInsName));
Type newMethodType = Type.getMethodType(insType, constructorTypes);

MethodVisitor callMethod = new JvmSandboxingVisitor(cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "new", newMethodType.getDescriptor(), null, null), null);
MethodVisitor callMethod = cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "new", newMethodType.getDescriptor(), null, null);
callMethod.visitCode();
callMethod.visitTypeInsn(Opcodes.NEW, insType.getInternalName());
callMethod.visitInsn(Opcodes.DUP);
Expand All @@ -378,7 +382,7 @@ protected Class<?> visitChipmunkClass(JvmCompilation compilation, BinaryClass cl
callMethod.visitEnd();

// Generate CClass.getModule()
MethodVisitor cClassGetModule = new JvmSandboxingVisitor(cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "getModule", Type.getMethodType(Type.getType(ChipmunkModule.class)).getDescriptor(), null, null), null);
MethodVisitor cClassGetModule = cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "getModule", Type.getMethodType(Type.getType(ChipmunkModule.class)).getDescriptor(), null, null);
cClassGetModule.visitCode();
// TODO - pass module to cClass constructor?
cClassGetModule.visitMethodInsn(Opcodes.INVOKESTATIC,
Expand Down Expand Up @@ -407,7 +411,7 @@ protected Class<?> visitChipmunkClass(JvmCompilation compilation, BinaryClass cl
cClassGetModule.visitEnd();

// Generate cClass.getTraits()
MethodVisitor getTraits = new JvmSandboxingVisitor(cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "getTraits", Type.getMethodType(Type.getType(TraitField[].class)).getDescriptor(), null, null), null);
MethodVisitor getTraits = cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "getTraits", Type.getMethodType(Type.getType(TraitField[].class)).getDescriptor(), null, null);
getTraits.visitCode();
getTraits.visitVarInsn(Opcodes.ALOAD, 0);
getTraits.visitFieldInsn(Opcodes.GETFIELD, jvmName(qualifiedCClassName), "$traits", Type.getDescriptor(TraitField[].class));
Expand All @@ -416,7 +420,7 @@ protected Class<?> visitChipmunkClass(JvmCompilation compilation, BinaryClass cl
getTraits.visitEnd();

// Generate cClass.getSharedTraits()
MethodVisitor getSharedTraits = new JvmSandboxingVisitor(cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "getSharedTraits", Type.getMethodType(Type.getType(TraitField[].class)).getDescriptor(), null, null), null);
MethodVisitor getSharedTraits = cClassWriter.visitMethod(Opcodes.ACC_PUBLIC, "getSharedTraits", Type.getMethodType(Type.getType(TraitField[].class)).getDescriptor(), null, null);
getSharedTraits.visitCode();
getSharedTraits.visitVarInsn(Opcodes.ALOAD, 0);
getSharedTraits.visitFieldInsn(Opcodes.GETFIELD, jvmName(qualifiedCClassName), "$sharedTraits", Type.getDescriptor(TraitField[].class));
Expand All @@ -427,7 +431,7 @@ protected Class<?> visitChipmunkClass(JvmCompilation compilation, BinaryClass cl
cClassWriter.visitEnd();

// Implement ChipmunkObject.getChipmunkClass()
MethodVisitor insGetCClass = new JvmSandboxingVisitor(cInsWriter.visitMethod(Opcodes.ACC_PUBLIC, "getChipmunkClass", Type.getMethodType(Type.getType(ChipmunkClass.class)).getDescriptor(), null, null), null);
MethodVisitor insGetCClass = cInsWriter.visitMethod(Opcodes.ACC_PUBLIC, "getChipmunkClass", Type.getMethodType(Type.getType(ChipmunkClass.class)).getDescriptor(), null, null);
insGetCClass.visitVarInsn(Opcodes.ALOAD, 0);
insGetCClass.visitFieldInsn(Opcodes.GETFIELD, jvmName(qualifiedInsName), "$cClass", Type.getType(ChipmunkClass.class).getDescriptor());
insGetCClass.visitInsn(Opcodes.ARETURN);
Expand Down Expand Up @@ -455,7 +459,7 @@ protected void visitNamespace(JvmCompilation compilation, BinaryNamespace ns){
}

if(entry.getType() == FieldType.METHOD){
visitMethod(compilation, namespaceInfo.getWriter(), flags, entry.getName(), entry.getBinaryMethod());
visitMethod(compilation, namespaceInfo.getWriter(), namespaceInfo.getName(), flags, entry.getName(), entry.getBinaryMethod());
}else if(entry.getType() == FieldType.CLASS){

// Generate class
Expand Down Expand Up @@ -516,7 +520,7 @@ protected void visitTraits(JvmCompilation compilation, String fieldName, BinaryN

}

protected void visitMethod(JvmCompilation compilation, ClassWriter cw, int flags, String name, BinaryMethod method){
protected void visitMethod(JvmCompilation compilation, ClassWriter cw, String className, int flags, String name, BinaryMethod method){

final Type objType = Type.getType(Object.class);

Expand All @@ -526,7 +530,8 @@ protected void visitMethod(JvmCompilation compilation, ClassWriter cw, int flags

Type methodType = Type.getMethodType(objType, pTypes);

MethodVisitor mv = new JvmSandboxingVisitor(cw.visitMethod(flags, name, methodType.getDescriptor(), null, null), null);
var sandbox = new SandboxContext(compilation.getPrefixedModuleName() + "." + className, name, methodType.getDescriptor(), compilation.getLinkingPolicy());
MethodVisitor mv = new Sandbox(cw.visitMethod(flags, name, methodType.getDescriptor(), null, null), sandbox);
mv.visitCode();

Map<Integer, Label> labelMappings = new HashMap<>();
Expand Down
12 changes: 11 additions & 1 deletion Lang/src/main/java/chipmunk/vm/jvm/JvmCompilerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,28 @@

package chipmunk.vm.jvm;

import chipmunk.vm.invoke.security.LinkingPolicy;

public class JvmCompilerConfig {

public enum YieldType {
THREAD_YIELD, FORCED_PREEMPT
}

protected final LinkingPolicy linkingPolicy;

protected volatile boolean disableBackjumpChecks;
protected volatile YieldType yieldType;

public JvmCompilerConfig(){
public JvmCompilerConfig(LinkingPolicy policy){
disableBackjumpChecks = false;
yieldType = YieldType.THREAD_YIELD;

linkingPolicy = policy;
}

public LinkingPolicy getLinkingPolicy(){
return linkingPolicy;
}

public void setIsCompilingBackjumpChecks(boolean useChecks){
Expand Down
23 changes: 23 additions & 0 deletions Lang/src/main/java/chipmunk/vm/jvm/MethodIdentifier.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 MyWorld, LLC
* All rights reserved.
*
* This file is part of Chipmunk.
*
* Chipmunk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chipmunk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Chipmunk. If not, see <https://www.gnu.org/licenses/>.
*/

package chipmunk.vm.jvm;

public record MethodIdentifier(Class<?> cls, String methodName, Class<?>[] signature) {}
Loading

0 comments on commit 2b4e287

Please sign in to comment.