mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +01:00
Unsafe.putInt and Unsafe.putLong
This commit is contained in:
parent
3de41deb3e
commit
3c2e431a9c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018 - 2022 Volker Berlin (i-net software)
|
* Copyright 2018 - 2023 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.
|
||||||
@ -65,10 +65,10 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
void init( WasmOptions options, ClassFileLoader classFileLoader ) {
|
void init( @Nonnull WasmOptions options, @Nonnull ClassFileLoader classFileLoader ) {
|
||||||
super.init( options, classFileLoader );
|
super.init( options, classFileLoader );
|
||||||
this.branchManager = new BranchManager( options, getInstructions(), getLocalVariables() );
|
this.branchManager = new BranchManager( options, getInstructions(), getLocalVariables() );
|
||||||
this.unsafeManager = new UnsafeManager( options.functions );
|
this.unsafeManager = new UnsafeManager( options, classFileLoader );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package de.inetsoftware.jwebassembly.module;
|
package de.inetsoftware.jwebassembly.module;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -23,10 +24,12 @@ import java.util.Set;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import de.inetsoftware.classparser.FieldInfo;
|
||||||
import de.inetsoftware.jwebassembly.WasmException;
|
import de.inetsoftware.jwebassembly.WasmException;
|
||||||
import de.inetsoftware.jwebassembly.module.StackInspector.StackValue;
|
import de.inetsoftware.jwebassembly.module.StackInspector.StackValue;
|
||||||
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
|
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
|
||||||
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.VariableOperator;
|
import de.inetsoftware.jwebassembly.wasm.VariableOperator;
|
||||||
|
|
||||||
@ -84,16 +87,27 @@ class UnsafeManager {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
private final FunctionManager functions;
|
private final FunctionManager functions;
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final TypeManager types;
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final ClassFileLoader classFileLoader;
|
||||||
|
|
||||||
private final HashMap<FunctionName, UnsafeState> unsafes = new HashMap<>();
|
private final HashMap<FunctionName, UnsafeState> unsafes = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of the manager
|
* Create an instance of the manager
|
||||||
*
|
*
|
||||||
* @param functions
|
* @param options
|
||||||
* The function manager to register the synthetic functions.
|
* compiler option/properties
|
||||||
|
* @param classFileLoader
|
||||||
|
* for loading the class files
|
||||||
*/
|
*/
|
||||||
UnsafeManager( @Nonnull FunctionManager functions ) {
|
UnsafeManager( @Nonnull WasmOptions options, @Nonnull ClassFileLoader classFileLoader ) {
|
||||||
this.functions = functions;
|
this.functions = options.functions;
|
||||||
|
this.types = options.types;
|
||||||
|
this.classFileLoader = classFileLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,8 +115,10 @@ class UnsafeManager {
|
|||||||
*
|
*
|
||||||
* @param instructions
|
* @param instructions
|
||||||
* the instruction list of a function/method
|
* the instruction list of a function/method
|
||||||
|
* @throws IOException
|
||||||
|
* If any I/O error occur
|
||||||
*/
|
*/
|
||||||
void replaceUnsafe( List<WasmInstruction> instructions ) {
|
void replaceUnsafe( @Nonnull List<WasmInstruction> instructions ) throws IOException {
|
||||||
// search for Unsafe function calls
|
// search for Unsafe function calls
|
||||||
for( int i = 0; i < instructions.size(); i++ ) {
|
for( int i = 0; i < instructions.size(); i++ ) {
|
||||||
WasmInstruction instr = instructions.get( i );
|
WasmInstruction instr = instructions.get( i );
|
||||||
@ -135,8 +151,10 @@ class UnsafeManager {
|
|||||||
* the index in the instructions
|
* the index in the instructions
|
||||||
* @param callInst
|
* @param callInst
|
||||||
* the method call to Unsafe
|
* the method call to Unsafe
|
||||||
|
* @throws IOException
|
||||||
|
* If any I/O error occur
|
||||||
*/
|
*/
|
||||||
private void patch( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst ) {
|
private void patch( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst ) throws IOException {
|
||||||
FunctionName name = callInst.getFunctionName();
|
FunctionName name = callInst.getFunctionName();
|
||||||
switch( name.signatureName ) {
|
switch( name.signatureName ) {
|
||||||
case "sun/misc/Unsafe.getUnsafe()Lsun/misc/Unsafe;":
|
case "sun/misc/Unsafe.getUnsafe()Lsun/misc/Unsafe;":
|
||||||
@ -332,8 +350,10 @@ class UnsafeManager {
|
|||||||
* the index in the instructions
|
* the index in the instructions
|
||||||
* @param callInst
|
* @param callInst
|
||||||
* the method call to Unsafe
|
* the method call to Unsafe
|
||||||
|
* @throws IOException
|
||||||
|
* If any I/O error occur
|
||||||
*/
|
*/
|
||||||
private void patch_objectFieldOffset_Java8( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst ) {
|
private void patch_objectFieldOffset_Java8( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst ) throws IOException {
|
||||||
UnsafeState state = findUnsafeState( instructions, idx );
|
UnsafeState state = findUnsafeState( instructions, idx );
|
||||||
|
|
||||||
// objectFieldOffset() has 2 parameters THIS(Unsafe) and a Field
|
// objectFieldOffset() has 2 parameters THIS(Unsafe) and a Field
|
||||||
@ -359,6 +379,7 @@ class UnsafeManager {
|
|||||||
throw new WasmException( "Unsupported Unsafe method to get target field: " + fieldFuncName.signatureName, -1 );
|
throw new WasmException( "Unsupported Unsafe method to get target field: " + fieldFuncName.signatureName, -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useFieldName( state );
|
||||||
nop( instructions, from, idx + 2 );
|
nop( instructions, from, idx + 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,8 +394,10 @@ class UnsafeManager {
|
|||||||
* the method call to Unsafe
|
* the method call to Unsafe
|
||||||
* @param isAtomicReferenceFieldUpdater
|
* @param isAtomicReferenceFieldUpdater
|
||||||
* true, if is AtomicReferenceFieldUpdater
|
* true, if is AtomicReferenceFieldUpdater
|
||||||
|
* @throws IOException
|
||||||
|
* If any I/O error occur
|
||||||
*/
|
*/
|
||||||
private void patch_objectFieldOffset_Java11( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst, boolean isAtomicReferenceFieldUpdater ) {
|
private void patch_objectFieldOffset_Java11( List<WasmInstruction> instructions, int idx, WasmCallInstruction callInst, boolean isAtomicReferenceFieldUpdater ) throws IOException {
|
||||||
UnsafeState state = findUnsafeState( instructions, idx );
|
UnsafeState state = findUnsafeState( instructions, idx );
|
||||||
|
|
||||||
// objectFieldOffset() has 3 parameters THIS(Unsafe), class and the fieldname
|
// objectFieldOffset() has 3 parameters THIS(Unsafe), class and the fieldname
|
||||||
@ -389,6 +412,7 @@ class UnsafeManager {
|
|||||||
stackValue = StackInspector.findInstructionThatPushValue( paramInstructions, classParamIdx, callInst.getCodePosition() );
|
stackValue = StackInspector.findInstructionThatPushValue( paramInstructions, classParamIdx, callInst.getCodePosition() );
|
||||||
state.typeName = getClassConst( instructions, stackValue );
|
state.typeName = getClassConst( instructions, stackValue );
|
||||||
|
|
||||||
|
useFieldName( state );
|
||||||
nop( instructions, from, idx + 2 );
|
nop( instructions, from, idx + 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,6 +459,20 @@ class UnsafeManager {
|
|||||||
instructions.set( idx, new WasmConstNumberInstruction( 1, callInst.getCodePosition(), callInst.getLineNumber() ) );
|
instructions.set( idx, new WasmConstNumberInstruction( 1, callInst.getCodePosition(), callInst.getLineNumber() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the field as used
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* the state
|
||||||
|
* @throws IOException
|
||||||
|
* If any I/O error occur
|
||||||
|
*/
|
||||||
|
private void useFieldName( @Nonnull UnsafeState state ) throws IOException {
|
||||||
|
FieldInfo fieldInfo = classFileLoader.get( state.typeName ).getField( state.fieldName );
|
||||||
|
NamedStorageType fieldName = new NamedStorageType( state.typeName, fieldInfo, types );
|
||||||
|
types.valueOf( state.typeName ).useFieldName( fieldName );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Patch an unsafe function that access a field
|
* Patch an unsafe function that access a field
|
||||||
*
|
*
|
||||||
@ -550,10 +588,17 @@ class UnsafeManager {
|
|||||||
+ " local.get 3" // x
|
+ " local.get 3" // x
|
||||||
+ " struct.set " + state.typeName + ' ' + state.fieldName;
|
+ " struct.set " + state.typeName + ' ' + state.fieldName;
|
||||||
|
|
||||||
|
case "getInt":
|
||||||
|
case "getLong":
|
||||||
|
return "local.get 1" // THIS
|
||||||
|
+ " struct.get " + state.typeName + ' ' + state.fieldName //
|
||||||
|
+ " return";
|
||||||
|
|
||||||
case "getObjectVolatile":
|
case "getObjectVolatile":
|
||||||
return "local.get 1" // array
|
return "local.get 1" // array
|
||||||
+ " local.get 2" // the array index
|
+ " local.get 2" // the array index
|
||||||
+ " array.get " + state.typeName;
|
+ " array.get " + state.typeName
|
||||||
|
+ " return";
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new RuntimeException( name.signatureName );
|
throw new RuntimeException( name.signatureName );
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018 - 2022 Volker Berlin (i-net software)
|
* Copyright 2018 - 2023 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.
|
||||||
@ -103,7 +103,7 @@ public abstract class WasmCodeBuilder {
|
|||||||
* @param classFileLoader
|
* @param classFileLoader
|
||||||
* for loading the class files
|
* for loading the class files
|
||||||
*/
|
*/
|
||||||
void init( WasmOptions options, ClassFileLoader classFileLoader ) {
|
void init( @Nonnull WasmOptions options, @Nonnull ClassFileLoader classFileLoader ) {
|
||||||
this.localVariables.init( options.types );
|
this.localVariables.init( options.types );
|
||||||
this.types = options.types;
|
this.types = options.types;
|
||||||
this.functions = options.functions;
|
this.functions = options.functions;
|
||||||
@ -250,10 +250,20 @@ public abstract class WasmCodeBuilder {
|
|||||||
*
|
*
|
||||||
* @return the type manager
|
* @return the type manager
|
||||||
*/
|
*/
|
||||||
|
@Nonnull
|
||||||
protected TypeManager getTypeManager() {
|
protected TypeManager getTypeManager() {
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For loading missing class declarations
|
||||||
|
* @return the loader
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
protected ClassFileLoader getClassFileLoader() {
|
||||||
|
return classFileLoader;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the code builder.
|
* Reset the code builder.
|
||||||
*
|
*
|
||||||
|
@ -229,6 +229,7 @@ class WasmStructInstruction extends WasmInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
comment = fieldName.getName();
|
comment = fieldName.getName();
|
||||||
|
assert idx >=0;
|
||||||
break;
|
break;
|
||||||
case INSTANCEOF:
|
case INSTANCEOF:
|
||||||
case CAST:
|
case CAST:
|
||||||
|
74
test/de/inetsoftware/jwebassembly/runtime/ThreadTest.java
Normal file
74
test/de/inetsoftware/jwebassembly/runtime/ThreadTest.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 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.jwebassembly.runtime;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
|
||||||
|
import de.inetsoftware.jwebassembly.ScriptEngine;
|
||||||
|
import de.inetsoftware.jwebassembly.WasmRule;
|
||||||
|
import de.inetsoftware.jwebassembly.api.annotation.Export;
|
||||||
|
import de.inetsoftware.jwebassembly.web.DOMString;
|
||||||
|
import de.inetsoftware.jwebassembly.web.JSObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Volker Berlin
|
||||||
|
*/
|
||||||
|
public class ThreadTest extends AbstractBaseTest {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static WasmRule rule = new WasmRule( TestClass.class );
|
||||||
|
|
||||||
|
public ThreadTest( ScriptEngine script, String method, Object[] params ) {
|
||||||
|
super( rule, script, method, params );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parameters( name = "{0}-{1}" )
|
||||||
|
public static Collection<Object[]> data() {
|
||||||
|
ArrayList<Object[]> list = new ArrayList<>();
|
||||||
|
for( ScriptEngine script : ScriptEngine.testEngines() ) {
|
||||||
|
addParam( list, script, "currentThreadName" );
|
||||||
|
addParam( list, script, "groupThreadName" );
|
||||||
|
}
|
||||||
|
rule.setTestParameters( list );
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TestClass {
|
||||||
|
|
||||||
|
@Export
|
||||||
|
static DOMString currentThreadName() {
|
||||||
|
Thread thread = Thread.currentThread();
|
||||||
|
String name = thread.getName();
|
||||||
|
return JSObject.domString( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Export
|
||||||
|
static DOMString groupThreadName() {
|
||||||
|
Thread thread = Thread.currentThread();
|
||||||
|
ThreadGroup group = thread.getThreadGroup();
|
||||||
|
String name;
|
||||||
|
do {
|
||||||
|
name = group.getName();
|
||||||
|
group = group.getParent();
|
||||||
|
} while( group != null );
|
||||||
|
return JSObject.domString( name );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@ import java.io.BufferedInputStream;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@ -58,6 +59,7 @@ public class UnsafeTest extends AbstractBaseTest {
|
|||||||
addParam( list, script, "getAndSetReference" );
|
addParam( list, script, "getAndSetReference" );
|
||||||
addParam( list, script, "lazySetReference" );
|
addParam( list, script, "lazySetReference" );
|
||||||
addParam( list, script, "atomicReferenceFieldUpdater" );
|
addParam( list, script, "atomicReferenceFieldUpdater" );
|
||||||
|
addParam( list, script, "putLong" );
|
||||||
}
|
}
|
||||||
rule.setTestParameters( list );
|
rule.setTestParameters( list );
|
||||||
|
|
||||||
@ -179,5 +181,11 @@ public class UnsafeTest extends AbstractBaseTest {
|
|||||||
stream.close();
|
stream.close();
|
||||||
return 42;
|
return 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Export
|
||||||
|
static int putLong() {
|
||||||
|
ThreadLocalRandom.current().nextInt();
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user