Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move Android logic to the Ruboto project
Browse files Browse the repository at this point in the history
UweKubosch committed May 5, 2017
1 parent 5d70732 commit f3f86aa
Showing 3 changed files with 1 addition and 304 deletions.
1 change: 0 additions & 1 deletion core/pom.rb
Original file line number Diff line number Diff line change
@@ -77,7 +77,6 @@
jar 'org.slf4j:slf4j-simple:1.7.12', :scope => 'test'

jar 'me.qmx.jitescript:jitescript:0.4.1', :exclusions => ['org.ow2.asm:asm-all']
jar 'com.linkedin.dexmaker:dexmaker:2.2.0', type: 'pom'

plugin_management do
plugin( 'org.eclipse.m2e:lifecycle-mapping:1.0.0',
5 changes: 0 additions & 5 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -273,11 +273,6 @@ DO NOT MODIFIY - GENERATED CODE
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.linkedin.dexmaker</groupId>
<artifactId>dexmaker</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
<build>
<defaultGoal>package</defaultGoal>
299 changes: 1 addition & 298 deletions core/src/main/java/org/jruby/runtime/scope/DynamicScopeGenerator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jruby.runtime.scope;

import com.android.dx.*;
import me.qmx.jitescript.CodeBlock;
import me.qmx.jitescript.JDKVersion;
import me.qmx.jitescript.JiteClass;
@@ -95,14 +94,7 @@ public static MethodHandle generate(final int size) {
p = CDCL.loadClass(clsName);
} catch (ClassNotFoundException cnfe2) {
// proceed to actually generate the class
if (System.getProperty("java.vm.name").equalsIgnoreCase("Dalvik"))
try {
p = generateDex(size, clsPath, clsName);
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
else
p = generateInternal(size, clsPath, clsName);
p = generateInternal(size, clsPath, clsName);
}
}
}
@@ -303,295 +295,6 @@ private static Class generateInternal(final int size, final String clsPath, fina
}
}

private static <T, G extends T> void generateConstructor(DexMaker dexMaker, TypeId<G> generatedType, TypeId<T> superType) {
TypeId<?>[] paramTypes = new TypeId<?>[2];
paramTypes[0] = TypeId.get(StaticScope.class);
paramTypes[1] = TypeId.get(DynamicScope.class);

MethodId<?, ?> constructor = generatedType.getMethod(TypeId.VOID, "<init>", paramTypes);
Code code = dexMaker.declare(constructor, Modifier.PUBLIC);
MethodId<T, ?> superConstructor = superType.getConstructor(paramTypes);
Local<?>[] params = new Local<?>[2];
params[0] = code.getParameter(0, paramTypes[0]);
params[1] = code.getParameter(1, paramTypes[1]);
Local<G> thisLocal = code.getThis(generatedType);
code.invokeDirect(superConstructor, null, thisLocal, params);
code.returnVoid();
}

private static <T extends DynamicScope> Class<?> generateDex(final int size, final String clsPath, final String clsName) throws IOException, ClassNotFoundException {
// ensure only one thread will attempt to generate and define the new class
synchronized (CDCL) {
// create a new one
final String[] newFields = varList(size);

final String baseName = p(DynamicScope.class);

DexMaker dexMaker = new DexMaker();
TypeId<T> dexClass = TypeId.get("L" + clsPath + ";");
TypeId<DynamicScope> baseClass = TypeId.get("L" + baseName + ";");
dexMaker.declare(dexClass, clsName + ".generated", Modifier.PUBLIC, baseClass);
generateConstructor(dexMaker, dexClass, baseClass);
TypeId<IRubyObject> iRubyObjectTypeId = TypeId.get(IRubyObject.class);

// getValue
MethodId<T, IRubyObject> getValueMethod = dexClass.getMethod(iRubyObjectTypeId, "getValue", TypeId.INT, TypeId.INT);
Code code = dexMaker.declare(getValueMethod, Modifier.PUBLIC);
Local<Integer> depth = code.getParameter(1, TypeId.INT);
Local<Integer> zero = code.newLocal(TypeId.INT);
Local<Integer> one = code.newLocal(TypeId.INT);
com.android.dx.Label parentCall = new com.android.dx.Label();
TypeId<RuntimeException> runtimeExceptionTypeId = TypeId.get(RuntimeException.class);
Local<RuntimeException> sizeErrorVar = code.newLocal(runtimeExceptionTypeId);
Local<Integer> offset = code.getParameter(0, TypeId.INT);
Local<DynamicScope> parent = code.newLocal(baseClass);
Local<T> thisLocal = code.getThis(dexClass);
Local<IRubyObject> result = code.newLocal(iRubyObjectTypeId);
Local<Integer>[] compareValues = new Local[size];
for (int i = 0; i < size; i++) {
compareValues[i] = code.newLocal(TypeId.INT);
}
for (int i = 0; i < size; i++) {
code.loadConstant(compareValues[i], i);
}
code.loadConstant(zero, 0);

code.compare(Comparison.NE, parentCall, depth, zero);

if (size > 0) {
com.android.dx.Label defaultError = new com.android.dx.Label();
com.android.dx.Label[] cases = new com.android.dx.Label[size];


for (int i = 0; i < size; i++) {
cases[i] = new com.android.dx.Label();
code.compare(Comparison.EQ, cases[i], offset, compareValues[i]);
}
code.jump(defaultError);
for (int i = 0; i < size; i++) {
code.mark(cases[i]);
FieldId<T, IRubyObject> selectedField = dexClass.getField(iRubyObjectTypeId, newFields[i]);
code.iget(selectedField, result, thisLocal);
code.returnValue(result);
}
code.mark(defaultError);
}

MethodId<T, RuntimeException> sizeErrorMethod = dexClass.getMethod(runtimeExceptionTypeId, "sizeError");
code.invokeStatic(sizeErrorMethod, sizeErrorVar);
code.throwValue(sizeErrorVar);

code.mark(parentCall);
FieldId<T, DynamicScope> parentField = dexClass.getField(baseClass, "parent");
code.iget(parentField, parent, thisLocal);
MethodId<DynamicScope, IRubyObject> parentMethod = baseClass.getMethod(iRubyObjectTypeId, "getValue", TypeId.INT, TypeId.INT);
code.loadConstant(one, 1);
code.op(BinaryOp.SUBTRACT, depth, depth, one);
code.invokeVirtual(parentMethod, result, parent, offset, depth);
code.returnValue(result);

// setValueVoid
MethodId<T, Void> setValueVoidMethod = dexClass.getMethod(TypeId.VOID, "setValueVoid", iRubyObjectTypeId, TypeId.INT, TypeId.INT);
code = dexMaker.declare(setValueVoidMethod, Modifier.PUBLIC);
depth = code.getParameter(2, TypeId.INT);
zero = code.newLocal(TypeId.INT);
sizeErrorVar = code.newLocal(runtimeExceptionTypeId);
offset = code.getParameter(1, TypeId.INT);
// parent = code.newLocal(baseClass);
thisLocal = code.getThis(dexClass);
Local<IRubyObject> value = code.getParameter(0, iRubyObjectTypeId);
for (int i = 0; i < size; i++) {
compareValues[i] = code.newLocal(TypeId.INT);
}
for (int i = 0; i < size; i++) {
code.loadConstant(compareValues[i], i);
}
parentCall = new com.android.dx.Label();
code.loadConstant(zero, 0);
code.compare(Comparison.NE, parentCall, depth, zero);
if (size > 0) {
com.android.dx.Label defaultError = new com.android.dx.Label();
com.android.dx.Label[] cases = new com.android.dx.Label[size];

for (int i = 0; i < size; i++) {
cases[i] = new com.android.dx.Label();
code.compare(Comparison.EQ, cases[i], offset, compareValues[i]);
}
code.jump(defaultError);
for (int i = 0; i < size; i++) {
code.mark(cases[i]);
FieldId<T, IRubyObject> selectedField = dexClass.getField(iRubyObjectTypeId, newFields[i]);
code.iput(selectedField, thisLocal, value);
code.returnVoid();
}
code.mark(defaultError);
}

sizeErrorMethod = dexClass.getMethod(runtimeExceptionTypeId, "sizeError");
code.invokeStatic(sizeErrorMethod, sizeErrorVar);
code.throwValue(sizeErrorVar);

code.mark(parentCall);
// DynamicScope;.setValueVoid is abstract, so this cannot work :(
/* parentField = dexClass.getField(baseClass, "parent");
code.iget(parentField, parent, thisLocal);
MethodId<DynamicScope, Void> parentSetValueVoid = baseClass.getMethod(TypeId.VOID, "setValueVoid", iRubyObjectTypeId, TypeId.INT, TypeId.INT);
code.invokeVirtual(parentSetValueVoid, null, parent, offset, depth); */
code.returnVoid();

// getValueDepthZero
MethodId<T, IRubyObject> getValueDepthZeroMethod = dexClass.getMethod(iRubyObjectTypeId, "getValueDepthZero", TypeId.INT);
code = dexMaker.declare(getValueDepthZeroMethod, Modifier.PUBLIC);
sizeErrorVar = code.newLocal(runtimeExceptionTypeId);
result = code.newLocal(iRubyObjectTypeId);
offset = code.getParameter(0, TypeId.INT);
thisLocal = code.getThis(dexClass);
for (int i = 0; i < size; i++) {
compareValues[i] = code.newLocal(TypeId.INT);
}
for (int i = 0; i < size; i++) {
code.loadConstant(compareValues[i], i);
}
if (size > 0) {
com.android.dx.Label defaultError = new com.android.dx.Label();
com.android.dx.Label[] cases = new com.android.dx.Label[size];
for (int i = 0; i < size; i++) {
cases[i] = new com.android.dx.Label();
code.compare(Comparison.EQ, cases[i], offset, compareValues[i]);
}
code.jump(defaultError);
for (int i = 0; i < size; i++) {
code.mark(cases[i]);
FieldId<T, IRubyObject> selectedField = dexClass.getField(iRubyObjectTypeId, newFields[i]);
code.iget(selectedField, result, thisLocal);
code.returnValue(result);
}
code.mark(defaultError);
}
sizeErrorMethod = dexClass.getMethod(runtimeExceptionTypeId, "sizeError");
code.invokeStatic(sizeErrorMethod, sizeErrorVar);
code.throwValue(sizeErrorVar);

// setValueDepthZero
MethodId<T, Void> setValueDepthZeroMethod = dexClass.getMethod(TypeId.VOID, "setValueDepthZero", iRubyObjectTypeId, TypeId.INT);
code = dexMaker.declare(setValueDepthZeroMethod, Modifier.PUBLIC);
offset = code.getParameter(1, TypeId.INT);
value = code.getParameter(0, iRubyObjectTypeId);
sizeErrorVar = code.newLocal(runtimeExceptionTypeId);
for (int i = 0; i < size; i++) {
compareValues[i] = code.newLocal(TypeId.INT);
}
for (int i = 0; i < size; i++) {
code.loadConstant(compareValues[i], i);
}
thisLocal = code.getThis(dexClass);
if (size > 0) {
com.android.dx.Label defaultError = new com.android.dx.Label();
com.android.dx.Label[] cases = new com.android.dx.Label[size];
for (int i = 0; i < size; i++) {
cases[i] = new com.android.dx.Label();
code.compare(Comparison.EQ, cases[i], offset, compareValues[i]);
}
code.jump(defaultError);
for (int i = 0; i < size; i++) {
code.mark(cases[i]);
FieldId<T, IRubyObject> selectedField = dexClass.getField(iRubyObjectTypeId, newFields[i]);
code.iput(selectedField, thisLocal, value);
code.returnVoid();
}
code.mark(defaultError);
}
sizeErrorMethod = dexClass.getMethod(runtimeExceptionTypeId, "sizeError");
code.invokeStatic(sizeErrorMethod, sizeErrorVar);
code.throwValue(sizeErrorVar);

// SPECIALIZED_GETS
for (int i = 0; i < SPECIALIZED_GETS.size(); i++) {
final int currentOffset = i;

MethodId<T, IRubyObject> newMethod = dexClass.getMethod(iRubyObjectTypeId, SPECIALIZED_GETS.get(currentOffset));
code = dexMaker.declare(newMethod, Modifier.PUBLIC);
if (size <= currentOffset) {
sizeErrorVar = code.newLocal(runtimeExceptionTypeId);
sizeErrorMethod = dexClass.getMethod(runtimeExceptionTypeId, "sizeError");
code.invokeStatic(sizeErrorMethod, sizeErrorVar);
code.throwValue(sizeErrorVar);
} else {
result = code.newLocal(iRubyObjectTypeId);
FieldId<T, IRubyObject> selectedField = dexClass.getField(iRubyObjectTypeId, newFields[currentOffset]);
thisLocal = code.getThis(dexClass);
code.iget(selectedField, result, thisLocal);
code.returnValue(result);
}
}

// SPECIALIZED_GETS_OR_NIL
for (int i = 0; i < SPECIALIZED_GETS_OR_NIL.size(); i++) {
final int currentOffset = i;
MethodId<T, IRubyObject> newMethod = dexClass.getMethod(iRubyObjectTypeId, SPECIALIZED_GETS_OR_NIL.get(currentOffset), iRubyObjectTypeId);
code = dexMaker.declare(newMethod, Modifier.PUBLIC);
if (size <= currentOffset) {
sizeErrorVar = code.newLocal(runtimeExceptionTypeId);
sizeErrorMethod = dexClass.getMethod(runtimeExceptionTypeId, "sizeError");
code.invokeStatic(sizeErrorMethod, sizeErrorVar);
code.throwValue(sizeErrorVar);
} else {
thisLocal = code.getThis(dexClass);
value = code.newLocal(iRubyObjectTypeId);
Local<IRubyObject> nullValue = code.newLocal(iRubyObjectTypeId);
Local<IRubyObject> nilParam = code.getParameter(0, iRubyObjectTypeId);
code.loadConstant(nullValue, null);
FieldId<T, IRubyObject> selectedField = dexClass.getField(iRubyObjectTypeId, newFields[currentOffset]);
code.iget(selectedField, value, thisLocal);
com.android.dx.Label ok = new com.android.dx.Label();
code.compare(Comparison.NE, ok, value, nullValue);
code.iput(selectedField, thisLocal, nilParam);
code.returnValue(nilParam);
code.mark(ok);
code.returnValue(value);
}
}

// SPECIALIZED_SETS
for (int i = 0; i < SPECIALIZED_SETS.size(); i++) {
final int currentOffset = i;
MethodId<T, Void> newMethod = dexClass.getMethod(TypeId.VOID, SPECIALIZED_SETS.get(currentOffset), iRubyObjectTypeId);
code = dexMaker.declare(newMethod, Modifier.PUBLIC);
if (size <= currentOffset) {
sizeErrorVar = code.newLocal(runtimeExceptionTypeId);
sizeErrorMethod = dexClass.getMethod(runtimeExceptionTypeId, "sizeError");
code.invokeStatic(sizeErrorMethod, sizeErrorVar);
code.throwValue(sizeErrorVar);
} else {
thisLocal = code.getThis(dexClass);
value = code.getParameter(0, iRubyObjectTypeId);
FieldId<T, IRubyObject> selectedField = dexClass.getField(iRubyObjectTypeId, newFields[currentOffset]);

code.iput(selectedField, thisLocal, value);
code.returnVoid();
}
}

// fields
for (String prop : newFields) {
FieldId<T, IRubyObject> newField = dexClass.getField(iRubyObjectTypeId, prop);
dexMaker.declare(newField, Modifier.PUBLIC, null);
}

// utilities
MethodId<T, RuntimeException> sizeErrorMethodId = dexClass.getMethod(runtimeExceptionTypeId, "sizeError");
code = dexMaker.declare(sizeErrorMethodId, Modifier.PRIVATE | Modifier.STATIC);
Local<String> message = code.newLocal(TypeId.STRING);
Local<RuntimeException> returnValue = code.newLocal(runtimeExceptionTypeId);
code.loadConstant(message, clsName + " only supports scopes with " + size + " variables");
MethodId<RuntimeException, Void> runtimeExceptionInit = runtimeExceptionTypeId.getMethod(TypeId.VOID, "<init>", TypeId.STRING);
code.newInstance(returnValue, runtimeExceptionInit, message);
code.returnValue(returnValue);
ClassLoader loader = dexMaker.generateAndLoad((ClassLoader) CDCL, null);
return loader.loadClass(clsName);
}
}

private static void genGetSwitch(String clsPath, String[] newFields, CodeBlock block, int offsetVar) {
LabelNode defaultError = new LabelNode(new Label());
int size = newFields.length;

0 comments on commit f3f86aa

Please sign in to comment.