mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-15 10:44:47 +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";
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -15,10 +15,14 @@
|
||||
*/
|
||||
package de.inetsoftware.jwebassembly.module;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import de.inetsoftware.classparser.MethodInfo;
|
||||
|
||||
/**
|
||||
* Manage the required function/methods
|
||||
*
|
||||
@ -30,6 +34,8 @@ public class FunctionManager {
|
||||
|
||||
private HashSet<FunctionName> toWriteLater = new HashSet<>();
|
||||
|
||||
private HashMap<FunctionName, MethodInfo> replacement = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Mark the a function as written to the wasm file.
|
||||
*
|
||||
@ -76,4 +82,31 @@ public class FunctionManager {
|
||||
boolean isToWrite( FunctionName 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;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -38,8 +44,8 @@ import de.inetsoftware.classparser.MethodInfo;
|
||||
import de.inetsoftware.jwebassembly.JWebAssembly;
|
||||
import de.inetsoftware.jwebassembly.WasmException;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
||||
import de.inetsoftware.jwebassembly.wasm.NamedStorageType;
|
||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||
import de.inetsoftware.jwebassembly.wasm.NamedStorageType;
|
||||
import de.inetsoftware.jwebassembly.wasm.ValueType;
|
||||
import de.inetsoftware.jwebassembly.wasm.ValueTypeParser;
|
||||
import de.inetsoftware.jwebassembly.watparser.WatParser;
|
||||
@ -77,11 +83,57 @@ public class ModuleGenerator {
|
||||
* @param libraries
|
||||
* libraries
|
||||
*/
|
||||
public ModuleGenerator( @Nonnull ModuleWriter writer, List<URL> libraries ) {
|
||||
public ModuleGenerator( @Nonnull ModuleWriter writer, @Nonnull List<URL> libraries ) {
|
||||
this.writer = writer;
|
||||
this.libraries = new URLClassLoader( libraries.toArray( new URL[libraries.size()] ) );
|
||||
javaCodeBuilder.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 );
|
||||
} else {
|
||||
name = new FunctionName( method );
|
||||
method = functions.replace( name, method );
|
||||
}
|
||||
if( functions.isToWrite( name ) ) {
|
||||
writeMethod( method );
|
||||
writeMethod( name, method );
|
||||
}
|
||||
} catch (IOException ioex){
|
||||
throw WasmException.create( ioex, sourceFile, className, -1 );
|
||||
@ -235,8 +288,8 @@ public class ModuleGenerator {
|
||||
private void prepareMethod( MethodInfo method ) throws WasmException {
|
||||
try {
|
||||
FunctionName name = new FunctionName( method );
|
||||
Map<String,Object> annotationValues = method.getAnnotation( JWebAssembly.IMPORT_ANNOTATION );
|
||||
if( annotationValues != null ) {
|
||||
Map<String,Object> annotationValues;
|
||||
if( (annotationValues = method.getAnnotation( JWebAssembly.IMPORT_ANNOTATION )) != null ) {
|
||||
if( !method.isStatic() ) {
|
||||
throw new WasmException( "Import method must be static: " + name.fullName, -1 );
|
||||
}
|
||||
@ -245,14 +298,22 @@ public class ModuleGenerator {
|
||||
String importName = (String)annotationValues.get( "name" );
|
||||
writer.prepareImport( name, impoarModule, importName );
|
||||
writeMethodSignature( name, true, null, null );
|
||||
} else {
|
||||
annotationValues = method.getAnnotation( JWebAssembly.EXPORT_ANNOTATION );
|
||||
if( annotationValues != null ) {
|
||||
if( !method.isStatic() ) {
|
||||
throw new WasmException( "Export method must be static: " + name.fullName, -1 );
|
||||
}
|
||||
functions.functionCall( name );
|
||||
return;
|
||||
}
|
||||
if( (annotationValues = method.getAnnotation( JWebAssembly.EXPORT_ANNOTATION )) != null ) {
|
||||
if( !method.isStatic() ) {
|
||||
throw new WasmException( "Export method must be static: " + name.fullName, -1 );
|
||||
}
|
||||
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 ) {
|
||||
throw WasmException.create( ioex, sourceFile, className, -1 );
|
||||
@ -267,7 +328,7 @@ public class ModuleGenerator {
|
||||
* @throws WasmException
|
||||
* 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;
|
||||
try {
|
||||
if( method.getAnnotation( JWebAssembly.IMPORT_ANNOTATION ) != null ) {
|
||||
@ -276,7 +337,6 @@ public class ModuleGenerator {
|
||||
WasmCodeBuilder codeBuilder;
|
||||
Code code = method.getCode();
|
||||
LocalVariableTable localVariableTable;
|
||||
FunctionName name;
|
||||
if( method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ) != null ) {
|
||||
Map<String, Object> wat = method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION );
|
||||
String watCode = (String)wat.get( "value" );
|
||||
@ -284,12 +344,10 @@ public class ModuleGenerator {
|
||||
if( signature == null ) {
|
||||
signature = method.getType();
|
||||
}
|
||||
name = new FunctionName( method, signature );
|
||||
watParser.parse( watCode, code == null ? -1 : code.getFirstLineNr() );
|
||||
codeBuilder = watParser;
|
||||
localVariableTable = null;
|
||||
} else if( code != null ) { // abstract methods and interface methods does not have code
|
||||
name = new FunctionName( method );
|
||||
javaCodeBuilder.buildCode( code, !method.getType().endsWith( ")V" ) );
|
||||
codeBuilder = javaCodeBuilder;
|
||||
localVariableTable = code.getLocalVariableTable();
|
||||
|
@ -111,6 +111,15 @@ public class WasmRule extends TemporaryFolder {
|
||||
wasm.addFile( url );
|
||||
}
|
||||
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();
|
||||
try {
|
||||
create();
|
||||
|
Loading…
x
Reference in New Issue
Block a user