InvokeDynamic, WIP

This commit is contained in:
Volker Berlin 2020-01-25 21:17:42 +01:00
parent 4872dd137a
commit 45b5a4a955
4 changed files with 118 additions and 18 deletions

View File

@ -0,0 +1,56 @@
/*
Copyright 2020 Volker Berlin (i-net software)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package de.inetsoftware.classparser;
import java.io.DataInputStream;
import java.io.IOException;
/**
* https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23
*
* @author Volker Berlin
*/
public class BootstrapMethod {
/**
* Signature and return type of method to be implemented by the function object.
*/
private String samMethodType;
/**
* A direct method handle describing the implementation method which should be called
*/
private ConstantMethodRef implMethod;
/**
* The signature and return type that should be enforced dynamically at invocation time. This may be the same as
* {@code samMethodType}, or may be a specialization of it.
*/
private String instantiatedMethodType;
BootstrapMethod( DataInputStream input, ConstantPool constantPool ) throws IOException {
int ref = input.readUnsignedShort();
//ConstantMethodRef method = (ConstantMethodRef)constantPool.get( ref ); // ever: java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
int argCount = input.readUnsignedShort(); // ever: 3 parameters
// the 3 values
samMethodType = (String)constantPool.get( input.readUnsignedShort() );
implMethod = (ConstantMethodRef)constantPool.get( input.readUnsignedShort() );
instantiatedMethodType = (String)constantPool.get( input.readUnsignedShort() );
}
}

View File

@ -62,6 +62,8 @@ public class ClassFile {
private Map<String,Map<String,Object>> annotations;
private BootstrapMethod[] bootstrapMethods;
/**
* Load a class file and create a model of the class.
*
@ -200,6 +202,30 @@ public class ClassFile {
return annotations.get( annotation );
}
/**
* Get the x-the BootstrapMethod. Bootstrap methods are used for creating an lambda object.
*
* @param methodIdx
* the index of the method
* @return the method
* @throws IOException
* if any error occur
*/
public BootstrapMethod getBootstrapMethod( int methodIdx ) throws IOException {
if( bootstrapMethods == null ) {
AttributeInfo data = attributes.get( "BootstrapMethods" );
if( data != null ) {
DataInputStream input = data.getDataInputStream();
int count = input.readUnsignedShort();
bootstrapMethods = new BootstrapMethod[count];
for( int i = 0; i < count; i++ ) {
bootstrapMethods[i] = new BootstrapMethod( input, constantPool );
}
}
}
return bootstrapMethods[methodIdx];
}
public ConstantPool getConstantPool() {
return constantPool;
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 Volker Berlin (i-net software)
Copyright 2019 - 2020 Volker Berlin (i-net software)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -19,10 +19,12 @@ package de.inetsoftware.classparser;
/**
* @author Volker Berlin
*/
public class ConstantInvokeDynamic implements Member {
public class ConstantInvokeDynamic {
private final ConstantNameAndType nameAndType;
private final int bootstrapMethodIndex;
/**
* Invoke dynamic info in the constant pool.
* https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4.10
@ -33,31 +35,35 @@ public class ConstantInvokeDynamic implements Member {
* the name and type
*/
ConstantInvokeDynamic( int bootstrapMethodAttrIndex, ConstantNameAndType nameAndType ) {
this.bootstrapMethodIndex = bootstrapMethodAttrIndex;
this.nameAndType = nameAndType;
}
/**
* {@inheritDoc}
* The simple name of the generated method of the single function interface.
*
* @return the name
*/
@Override
public String getName() {
return nameAndType.getName();
}
/**
* {@inheritDoc}
* Get the signature of the factory method. For example "()Ljava.lang.Runnable;" for the lamba expression "Runnable
* run = () -> foo();"
*
* @return the type
*/
@Override
public String getClassName() {
return null;
}
/**
* Get the type of the method. For example "(Ljava.lang.String;)I"
*/
@Override
public String getType() {
return nameAndType.getType();
}
}
/**
* Get the index to the bootstrap methods.
*
* @return the index
*/
public int getBootstrapMethodIndex() {
return bootstrapMethodIndex;
}
}

View File

@ -19,9 +19,12 @@ import java.io.IOException;
import javax.annotation.Nonnull;
import de.inetsoftware.classparser.BootstrapMethod;
import de.inetsoftware.classparser.ClassFile;
import de.inetsoftware.classparser.Code;
import de.inetsoftware.classparser.CodeInputStream;
import de.inetsoftware.classparser.ConstantClass;
import de.inetsoftware.classparser.ConstantInvokeDynamic;
import de.inetsoftware.classparser.ConstantPool;
import de.inetsoftware.classparser.ConstantRef;
import de.inetsoftware.classparser.MethodInfo;
@ -62,7 +65,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
byteCode = code.getByteCode();
boolean hasReturn = !method.getType().endsWith( ")V" );
writeCode( byteCode, code.getConstantPool(), hasReturn );
writeCode( byteCode, code.getConstantPool(), method.getDeclaringClassFile(), hasReturn );
calculateVariables();
} catch( Exception ioex ) {
int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber();
@ -77,12 +80,14 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
* a stream of byte code
* @param constantPool
* the constant pool of the the current class
* @param classFile
* the declaring class file
* @param hasReturn
* if the method has a return value
* @throws WasmException
* if some Java code can't converted
*/
private void writeCode( CodeInputStream byteCode, ConstantPool constantPool, boolean hasReturn ) throws WasmException {
private void writeCode( CodeInputStream byteCode, ConstantPool constantPool, ClassFile classFile, boolean hasReturn ) throws WasmException {
int lineNumber = -1;
try {
boolean wide = false;
@ -589,7 +594,14 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
}
break;
//TODO case 185: // invokeinterface
//TODO case 186: // invokedynamic
case 186: // invokedynamic
idx = byteCode.readUnsignedShort();
ConstantInvokeDynamic dynamic = (ConstantInvokeDynamic)constantPool.get( idx );
idx = byteCode.readUnsignedShort(); // ever zero
idx = dynamic.getBootstrapMethodIndex();
BootstrapMethod method = classFile.getBootstrapMethod( idx );
throw new WasmException( "InvokeDynamic/Lambda is not supported.", lineNumber );
//TODO break;
case 187: // new
String name = ((ConstantClass)constantPool.get( byteCode.readUnsignedShort() )).getName();
addStructInstruction( StructOperator.NEW_DEFAULT, name, null, codePos, lineNumber );