mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +01:00
Add support for Replace annotation to replace a single method. fix #4
This commit is contained in:
parent
9d1e4ef6f3
commit
7904f4026e
@ -71,6 +71,11 @@ public class JWebAssembly {
|
|||||||
*/
|
*/
|
||||||
public static final String TEXTCODE_ANNOTATION = "de.inetsoftware.jwebassembly.api.annotation.WasmTextCode";
|
public static final String TEXTCODE_ANNOTATION = "de.inetsoftware.jwebassembly.api.annotation.WasmTextCode";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the annotation for replacing a single method of the Java runtime.
|
||||||
|
*/
|
||||||
|
public static final String REPLACE_ANNOTATION = "de.inetsoftware.jwebassembly.api.annotation.Replace";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a instance.
|
* Create a instance.
|
||||||
*/
|
*/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018 Volker Berlin (i-net software)
|
* Copyright 2018 - 2019 Volker Berlin (i-net software)
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -15,10 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package de.inetsoftware.jwebassembly.module;
|
package de.inetsoftware.jwebassembly.module;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import de.inetsoftware.classparser.MethodInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage the required function/methods
|
* Manage the required function/methods
|
||||||
*
|
*
|
||||||
@ -30,6 +34,8 @@ public class FunctionManager {
|
|||||||
|
|
||||||
private HashSet<FunctionName> toWriteLater = new HashSet<>();
|
private HashSet<FunctionName> toWriteLater = new HashSet<>();
|
||||||
|
|
||||||
|
private HashMap<FunctionName, MethodInfo> replacement = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark the a function as written to the wasm file.
|
* Mark the a function as written to the wasm file.
|
||||||
*
|
*
|
||||||
@ -76,4 +82,31 @@ public class FunctionManager {
|
|||||||
boolean isToWrite( FunctionName name ) {
|
boolean isToWrite( FunctionName name ) {
|
||||||
return toWriteLater.contains( name );
|
return toWriteLater.contains( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a replacement for a method
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the name of the method which should be replaced
|
||||||
|
* @param method
|
||||||
|
* the new implementation
|
||||||
|
*/
|
||||||
|
void addReplacement( FunctionName name, MethodInfo method ) {
|
||||||
|
replacement.put( name, method );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there is a replacement method
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* the name
|
||||||
|
* @param method
|
||||||
|
* the current method
|
||||||
|
* @return the method that should be write
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
MethodInfo replace( FunctionName name, MethodInfo method ) {
|
||||||
|
MethodInfo newMethod = replacement.get( name );
|
||||||
|
return newMethod != null ? newMethod : method;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
package de.inetsoftware.jwebassembly.module;
|
package de.inetsoftware.jwebassembly.module;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -38,8 +44,8 @@ import de.inetsoftware.classparser.MethodInfo;
|
|||||||
import de.inetsoftware.jwebassembly.JWebAssembly;
|
import de.inetsoftware.jwebassembly.JWebAssembly;
|
||||||
import de.inetsoftware.jwebassembly.WasmException;
|
import de.inetsoftware.jwebassembly.WasmException;
|
||||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
||||||
import de.inetsoftware.jwebassembly.wasm.NamedStorageType;
|
|
||||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||||
|
import de.inetsoftware.jwebassembly.wasm.NamedStorageType;
|
||||||
import de.inetsoftware.jwebassembly.wasm.ValueType;
|
import de.inetsoftware.jwebassembly.wasm.ValueType;
|
||||||
import de.inetsoftware.jwebassembly.wasm.ValueTypeParser;
|
import de.inetsoftware.jwebassembly.wasm.ValueTypeParser;
|
||||||
import de.inetsoftware.jwebassembly.watparser.WatParser;
|
import de.inetsoftware.jwebassembly.watparser.WatParser;
|
||||||
@ -77,11 +83,57 @@ public class ModuleGenerator {
|
|||||||
* @param libraries
|
* @param libraries
|
||||||
* libraries
|
* libraries
|
||||||
*/
|
*/
|
||||||
public ModuleGenerator( @Nonnull ModuleWriter writer, List<URL> libraries ) {
|
public ModuleGenerator( @Nonnull ModuleWriter writer, @Nonnull List<URL> libraries ) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
this.libraries = new URLClassLoader( libraries.toArray( new URL[libraries.size()] ) );
|
this.libraries = new URLClassLoader( libraries.toArray( new URL[libraries.size()] ) );
|
||||||
javaCodeBuilder.init( types );
|
javaCodeBuilder.init( types );
|
||||||
((WasmCodeBuilder)watParser).init( types );
|
((WasmCodeBuilder)watParser).init( types );
|
||||||
|
scanLibraries( libraries );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan the libraries for annotated methods
|
||||||
|
*
|
||||||
|
* @param libraries
|
||||||
|
* libraries
|
||||||
|
*/
|
||||||
|
private void scanLibraries( @Nonnull List<URL> libraries ) {
|
||||||
|
// search for replacement methods in the libraries
|
||||||
|
for( URL url : libraries ) {
|
||||||
|
try {
|
||||||
|
File file = new File(url.toURI());
|
||||||
|
if( file.isDirectory() ) {
|
||||||
|
for( Iterator<Path> iterator = Files.walk( file.toPath() ).iterator(); iterator.hasNext(); ) {
|
||||||
|
Path path = iterator.next();
|
||||||
|
if( path.toString().endsWith( ".class" ) ) {
|
||||||
|
ClassFile classFile = new ClassFile( new BufferedInputStream( Files.newInputStream( path ) ) );
|
||||||
|
prepare( classFile );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch( Exception e ) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ZipInputStream input = new ZipInputStream( url.openStream() )) {
|
||||||
|
do {
|
||||||
|
ZipEntry entry = input.getNextEntry();
|
||||||
|
if( entry == null ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( entry.getName().endsWith( ".class" ) ) {
|
||||||
|
ClassFile classFile = new ClassFile( new BufferedInputStream( input ) {
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
} // does not close the zip stream
|
||||||
|
} );
|
||||||
|
prepare( classFile );
|
||||||
|
}
|
||||||
|
} while( true );
|
||||||
|
} catch( IOException e ) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,9 +187,10 @@ public class ModuleGenerator {
|
|||||||
name = new FunctionName( method, signature );
|
name = new FunctionName( method, signature );
|
||||||
} else {
|
} else {
|
||||||
name = new FunctionName( method );
|
name = new FunctionName( method );
|
||||||
|
method = functions.replace( name, method );
|
||||||
}
|
}
|
||||||
if( functions.isToWrite( name ) ) {
|
if( functions.isToWrite( name ) ) {
|
||||||
writeMethod( method );
|
writeMethod( name, method );
|
||||||
}
|
}
|
||||||
} catch (IOException ioex){
|
} catch (IOException ioex){
|
||||||
throw WasmException.create( ioex, sourceFile, className, -1 );
|
throw WasmException.create( ioex, sourceFile, className, -1 );
|
||||||
@ -235,8 +288,8 @@ public class ModuleGenerator {
|
|||||||
private void prepareMethod( MethodInfo method ) throws WasmException {
|
private void prepareMethod( MethodInfo method ) throws WasmException {
|
||||||
try {
|
try {
|
||||||
FunctionName name = new FunctionName( method );
|
FunctionName name = new FunctionName( method );
|
||||||
Map<String,Object> annotationValues = method.getAnnotation( JWebAssembly.IMPORT_ANNOTATION );
|
Map<String,Object> annotationValues;
|
||||||
if( annotationValues != null ) {
|
if( (annotationValues = method.getAnnotation( JWebAssembly.IMPORT_ANNOTATION )) != null ) {
|
||||||
if( !method.isStatic() ) {
|
if( !method.isStatic() ) {
|
||||||
throw new WasmException( "Import method must be static: " + name.fullName, -1 );
|
throw new WasmException( "Import method must be static: " + name.fullName, -1 );
|
||||||
}
|
}
|
||||||
@ -245,14 +298,22 @@ public class ModuleGenerator {
|
|||||||
String importName = (String)annotationValues.get( "name" );
|
String importName = (String)annotationValues.get( "name" );
|
||||||
writer.prepareImport( name, impoarModule, importName );
|
writer.prepareImport( name, impoarModule, importName );
|
||||||
writeMethodSignature( name, true, null, null );
|
writeMethodSignature( name, true, null, null );
|
||||||
} else {
|
return;
|
||||||
annotationValues = method.getAnnotation( JWebAssembly.EXPORT_ANNOTATION );
|
}
|
||||||
if( annotationValues != null ) {
|
if( (annotationValues = method.getAnnotation( JWebAssembly.EXPORT_ANNOTATION )) != null ) {
|
||||||
if( !method.isStatic() ) {
|
if( !method.isStatic() ) {
|
||||||
throw new WasmException( "Export method must be static: " + name.fullName, -1 );
|
throw new WasmException( "Export method must be static: " + name.fullName, -1 );
|
||||||
}
|
|
||||||
functions.functionCall( name );
|
|
||||||
}
|
}
|
||||||
|
functions.functionCall( name );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( (annotationValues = method.getAnnotation( JWebAssembly.REPLACE_ANNOTATION )) != null ) {
|
||||||
|
String className = ((String)annotationValues.get( "className" )).replace( ".", "/" );
|
||||||
|
String methodName = (String)annotationValues.get( "methodName" );
|
||||||
|
String signature = (String)annotationValues.get( "signature" );
|
||||||
|
name = new FunctionName( className, methodName, signature );
|
||||||
|
functions.addReplacement( name, method );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} catch( Exception ioex ) {
|
} catch( Exception ioex ) {
|
||||||
throw WasmException.create( ioex, sourceFile, className, -1 );
|
throw WasmException.create( ioex, sourceFile, className, -1 );
|
||||||
@ -267,7 +328,7 @@ public class ModuleGenerator {
|
|||||||
* @throws WasmException
|
* @throws WasmException
|
||||||
* if some Java code can't converted
|
* if some Java code can't converted
|
||||||
*/
|
*/
|
||||||
private void writeMethod( MethodInfo method ) throws WasmException {
|
private void writeMethod( FunctionName name, MethodInfo method ) throws WasmException {
|
||||||
CodeInputStream byteCode = null;
|
CodeInputStream byteCode = null;
|
||||||
try {
|
try {
|
||||||
if( method.getAnnotation( JWebAssembly.IMPORT_ANNOTATION ) != null ) {
|
if( method.getAnnotation( JWebAssembly.IMPORT_ANNOTATION ) != null ) {
|
||||||
@ -276,7 +337,6 @@ public class ModuleGenerator {
|
|||||||
WasmCodeBuilder codeBuilder;
|
WasmCodeBuilder codeBuilder;
|
||||||
Code code = method.getCode();
|
Code code = method.getCode();
|
||||||
LocalVariableTable localVariableTable;
|
LocalVariableTable localVariableTable;
|
||||||
FunctionName name;
|
|
||||||
if( method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ) != null ) {
|
if( method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ) != null ) {
|
||||||
Map<String, Object> wat = method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION );
|
Map<String, Object> wat = method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION );
|
||||||
String watCode = (String)wat.get( "value" );
|
String watCode = (String)wat.get( "value" );
|
||||||
@ -284,12 +344,10 @@ public class ModuleGenerator {
|
|||||||
if( signature == null ) {
|
if( signature == null ) {
|
||||||
signature = method.getType();
|
signature = method.getType();
|
||||||
}
|
}
|
||||||
name = new FunctionName( method, signature );
|
|
||||||
watParser.parse( watCode, code == null ? -1 : code.getFirstLineNr() );
|
watParser.parse( watCode, code == null ? -1 : code.getFirstLineNr() );
|
||||||
codeBuilder = watParser;
|
codeBuilder = watParser;
|
||||||
localVariableTable = null;
|
localVariableTable = null;
|
||||||
} else if( code != null ) { // abstract methods and interface methods does not have code
|
} else if( code != null ) { // abstract methods and interface methods does not have code
|
||||||
name = new FunctionName( method );
|
|
||||||
javaCodeBuilder.buildCode( code, !method.getType().endsWith( ")V" ) );
|
javaCodeBuilder.buildCode( code, !method.getType().endsWith( ")V" ) );
|
||||||
codeBuilder = javaCodeBuilder;
|
codeBuilder = javaCodeBuilder;
|
||||||
localVariableTable = code.getLocalVariableTable();
|
localVariableTable = code.getLocalVariableTable();
|
||||||
|
@ -111,6 +111,15 @@ public class WasmRule extends TemporaryFolder {
|
|||||||
wasm.addFile( url );
|
wasm.addFile( url );
|
||||||
}
|
}
|
||||||
wasm.setProperty( JWebAssembly.DEBUG_NAMES, "true" );
|
wasm.setProperty( JWebAssembly.DEBUG_NAMES, "true" );
|
||||||
|
|
||||||
|
// add the libraries that it can be scanned for annotations
|
||||||
|
final String[] libraries = System.getProperty("java.class.path").split(File.pathSeparator);
|
||||||
|
for( String lib : libraries ) {
|
||||||
|
if( lib.endsWith( ".jar" ) || lib.toLowerCase().contains( "jwebassembly-api" ) ) {
|
||||||
|
wasm.addLibrary( new File(lib) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
textCompiled = wasm.compileToText();
|
textCompiled = wasm.compileToText();
|
||||||
try {
|
try {
|
||||||
create();
|
create();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user