Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benchmarks/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jmh {
}
}
}
jvmArgs = ['-XX:+BackgroundCompilation']
jvmArgs = ['-XX:-BackgroundCompilation']

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you keep trying to sneak this in unrelated PRs... 🤣 here's an actual one: #2451

benchmarkMode = ['avgt']
fork = 1
iterations = 5
Expand Down
27 changes: 27 additions & 0 deletions rhino/src/main/java/org/mozilla/classfile/ClassFileWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ public ClassFileWriter(String className, String superClassName, String sourceFil
// class flag. This is specified in the first JVM spec, so it should
// be old enough that it's okay to always set it.
itsFlags = ACC_PUBLIC | ACC_SUPER;
if (DEBUGMETHODS) {
System.err.printf("Class start %s (%s).\n", generatedClassName, superClassName);
}
}

public final String getClassName() {
Expand Down Expand Up @@ -689,6 +692,24 @@ public void addLoadConstant(String k) {
add(ByteCode.LDC, itsConstantPool.addConstant(k));
}

/**
* Generate the load constant bytecode for the given class.
*
* @param k the constant
*/
public void addLoadConstant(Class<?> k) {
add(ByteCode.LDC, itsConstantPool.addClass(k.getName()));
}

/**
* Generate the load constant bytecode for the given class.
*
* @param k the constant
*/
public void addLoadConstantClass(String k) {
add(ByteCode.LDC, itsConstantPool.addClass(k));
}

/**
* Add the given two-operand bytecode to the current method.
*
Expand Down Expand Up @@ -2172,6 +2193,9 @@ private int execute(int bci) {
case ConstantPool.CONSTANT_String:
push(TypeInfo.OBJECT("java/lang/String", itsConstantPool));
break;
case ConstantPool.CONSTANT_Class:
push(TypeInfo.OBJECT("java/lang/Class", itsConstantPool));
break;
default:
throw new IllegalArgumentException("bad const type " + constType);
}
Expand Down Expand Up @@ -2865,6 +2889,9 @@ public byte[] toByteArray() {
throw new RuntimeException();
}

if (DEBUGCODE) {
System.err.println("Class end.");
}
return data;
}

Expand Down
176 changes: 115 additions & 61 deletions rhino/src/main/java/org/mozilla/javascript/optimizer/Bootstrapper.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public Object[] compileToClassFiles(
Codegen codegen = new Codegen();
codegen.setMainMethodClass(mainMethodClassName);
JSDescriptor.Builder builder = new JSDescriptor.Builder();
OptJSCode.BuilderEnv builderEnv = new OptJSCode.BuilderEnv(scriptClassName);
MHJSCode.BuilderEnv builderEnv = new MHJSCode.BuilderEnv(scriptClassName);
byte[] scriptClassBytes =
codegen.compileToClassFile(
compilerEnv, builder, builderEnv, scriptClassName, tree, source, false);
Expand Down Expand Up @@ -196,13 +196,13 @@ private Object[] buildDescriptorsAndMain(String mainClassName, JSDescriptor.Buil

var cfw = new ClassFileWriter(mainName, "java.lang.Object", "");
var builders = new ArrayList<JSDescriptor.Builder<?>>();
buildDescriptor(cfw, builder, classes, builders);
buildDescriptor(cfw, builder, classes, builders, mainClassName);
cfw.startMethod("<clinit>", "()V", ACC_STATIC);
cfw.addLoadConstant(builders.size());
cfw.add(ByteCode.ANEWARRAY, "org/mozilla/javascript/JSDescriptor");
for (var b : builders) {
int index = ((OptJSCode.Builder) b.code).index;
int parent = b.parent == null ? 0 : ((OptJSCode.Builder) b.parent.code).index;
int index = ((MHJSCode.Builder<?>) b.code).index;
int parent = b.parent == null ? 0 : ((MHJSCode.Builder<?>) b.parent.code).index;
populateDescriptorEntry(cfw, index, parent);
}
cfw.add(
Expand Down Expand Up @@ -259,7 +259,8 @@ private void buildDescriptor(
ClassFileWriter cfw,
JSDescriptor.Builder builder,
Map<String, byte[]> classes,
List<JSDescriptor.Builder<?>> builders) {
List<JSDescriptor.Builder<?>> builders,
String mainClassName) {
builders.add(builder);
cfw.startMethod(
"init" + functionId(builder),
Expand All @@ -268,8 +269,8 @@ private void buildDescriptor(

cfw.add(ByteCode.NEW, "org.mozilla.javascript.JSDescriptor");
cfw.add(ByteCode.DUP);
buildCode(cfw, builder.code, classes);
buildCode(cfw, builder.constructor, classes);
buildCode(cfw, builder.code, classes, mainClassName);
buildCode(cfw, builder.constructor, classes, mainClassName);
cfw.addALoad(0);
cfw.addLoadConstant(builder.paramAndVarNames.length);
cfw.add(ByteCode.ANEWARRAY, "java/lang/String");
Expand Down Expand Up @@ -370,7 +371,7 @@ private void buildDescriptor(
cfw.add(ByteCode.ARETURN);
cfw.stopMethod(3);
for (var child : builder.nestedFunctions) {
buildDescriptor(cfw, (JSDescriptor.Builder) child, classes, builders);
buildDescriptor(cfw, (JSDescriptor.Builder) child, classes, builders, mainClassName);
}
}

Expand All @@ -379,13 +380,14 @@ private void buildDescriptor(
* instantiate that class.
*/
private void buildCode(
ClassFileWriter cfw, JSCode.Builder builder, Map<String, byte[]> classes) {
ClassFileWriter cfw,
JSCode.Builder builder,
Map<String, byte[]> classes,
String mainClassName) {
if (builder instanceof JSCode.NullBuilder<?>) {
cfw.add(ByteCode.ACONST_NULL);
} else {
var code = (OptJSCode.Builder<?>) builder;
code.buildByteCode(cfw);
classes.put(code.getClassName(), code.getClassBytes());
((MHJSCode.Builder<?>) builder).buildByteCode(cfw, mainClassName);
}
}

Expand All @@ -405,8 +407,8 @@ private void populateDescriptorEntry(ClassFileWriter cfw, int index, int parent)
cfw.add(ByteCode.AASTORE);
}

private int functionId(JSDescriptor.Builder builder) {
var code = (OptJSCode.Builder) builder.code;
private int functionId(JSDescriptor.Builder<?> builder) {
var code = (MHJSCode.Builder<?>) builder.code;
return code.index;
}

Expand Down
20 changes: 10 additions & 10 deletions rhino/src/main/java/org/mozilla/javascript/optimizer/Codegen.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ private static class CodegenCompilationResult<T extends ScriptOrFn<T>>
final JSDescriptor.Builder<T> builder;
final String className;
final byte[] bytecode;
final OptJSCode.BuilderEnv builderEnv;
final MHJSCode.BuilderEnv builderEnv;

CodegenCompilationResult(
JSDescriptor.Builder<T> builder,
String className,
byte[] bytecode,
OptJSCode.BuilderEnv builderEnv) {
MHJSCode.BuilderEnv builderEnv) {
this.builder = builder;
this.className = className;
this.bytecode = bytecode;
Expand Down Expand Up @@ -127,7 +127,7 @@ private <T extends ScriptOrFn<T>> CodegenCompilationResult<T> doCompile(
String mainClassName = "org.mozilla.javascript.gen." + baseName + "_" + serial;

JSDescriptor.Builder<T> builder = new JSDescriptor.Builder<>();
OptJSCode.BuilderEnv builderEnv = new OptJSCode.BuilderEnv(mainClassName);
MHJSCode.BuilderEnv builderEnv = new MHJSCode.BuilderEnv(mainClassName);
byte[] mainClassBytes =
compileToClassFile(
compilerEnv,
Expand Down Expand Up @@ -202,7 +202,7 @@ private <T extends ScriptOrFn<T>> JSDescriptor<T> defineClass(
public byte[] compileToClassFile(
CompilerEnvirons compilerEnv,
JSDescriptor.Builder<?> builder,
OptJSCode.BuilderEnv builderEnv,
MHJSCode.BuilderEnv builderEnv,
String mainClassName,
ScriptNode scriptOrFn,
String rawSource,
Expand Down Expand Up @@ -281,7 +281,7 @@ private static void initOptFunctions_r(ScriptNode scriptOrFn) {
private <U extends ScriptOrFn<U>> void initScriptNodesData(
ScriptNode scriptOrFn,
JSDescriptor.Builder<U> builder,
OptJSCode.BuilderEnv builderEnv) {
MHJSCode.BuilderEnv builderEnv) {
ArrayList<ScriptNode> x = new ArrayList<>();
ArrayList<JSDescriptor.Builder<?>> b = new ArrayList<>();
collectScriptNodes_r(scriptOrFn, builder, builderEnv, x, b);
Expand All @@ -301,16 +301,16 @@ private <U extends ScriptOrFn<U>> void initScriptNodesData(
private <U extends ScriptOrFn<U>> void collectScriptNodes_r(
ScriptNode n,
JSDescriptor.Builder<U> builder,
OptJSCode.BuilderEnv builderEnv,
MHJSCode.BuilderEnv builderEnv,
List<ScriptNode> x,
List<JSDescriptor.Builder<?>> b) {

@SuppressWarnings("unchecked")
OptJSCode.Builder<U> code =
(OptJSCode.Builder<U>)
MHJSCode.Builder<U> code =
(MHJSCode.Builder<U>)
((n instanceof FunctionNode)
? new OptJSFunctionCode.Builder(builderEnv)
: new OptJSScriptCode.Builder(builderEnv));
? new MHJSFunctionCode.Builder(builderEnv)
: new MHJSScriptCode.Builder(builderEnv));
code.index = x.size();
code.methodName = getBodyMethodName(n, x.size());
code.methodType = getNonDirectBodyMethodSIgnature(n);
Expand Down
84 changes: 84 additions & 0 deletions rhino/src/main/java/org/mozilla/javascript/optimizer/MHJSCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.mozilla.javascript.optimizer;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import org.mozilla.classfile.ClassFileWriter;
import org.mozilla.javascript.JSCode;
import org.mozilla.javascript.ScriptOrFn;

/** Subclass of {@link JSCode} for compiled Java methods. */
public abstract class MHJSCode<T extends ScriptOrFn<T>> extends JSCode<T> {

/**
* Builder environment used in the creation of {@link OptJSCode} objects. This hold information
* on whether literals will need to be initialised, and a reference to the class containing the
* method implementation once it has been built.
*/
public static class BuilderEnv {
boolean hasRegExpLiterals;
boolean hasTemplateLiterals;
Class<?> compiledClass;
final String className;

public BuilderEnv(String className) {
this.className = className;
}
}

/**
* A builder for {@link OptJSCode}. Holds the builder environment, names and types of execute
* and resume methods, an index within the set of descriptors owned by the class, and the built
* version of the object (used to avoid generating duplicate classes at runtime).
*/
public abstract static class Builder<T extends ScriptOrFn<T>> extends JSCode.Builder<T> {
final BuilderEnv env;
String methodName;
String methodType;
String resumeName;
String resumeType;
int index;
MHJSCode<T> built;

public Builder(BuilderEnv env) {
this.env = env;
}

@Override
public JSCode<T> build() {
if (built != null) {
return built;
}
try {
MethodHandles.Lookup lookup =
(MethodHandles.Lookup)
env.compiledClass
.getDeclaredMethod("getLookup")
.invoke(env.compiledClass);
MethodHandle exec =
lookup.findStatic(
env.compiledClass,
methodName,
MethodType.fromMethodDescriptorString(
methodType, env.compiledClass.getClassLoader()));
MethodHandle resume = null;
if (resumeName != null) {
resume =
lookup.findStatic(
env.compiledClass,
resumeName,
MethodType.fromMethodDescriptorString(
resumeType, env.compiledClass.getClassLoader()));
}
return buildCode(exec, resume);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new Error("Gnerated class did not contain expected methods", e);
}
}

protected abstract MHJSCode<T> buildCode(MethodHandle exec, MethodHandle resume);

public abstract void buildByteCode(ClassFileWriter cfw, String mainClass);
}
}
Loading
Loading