Unsafe.putInt and Unsafe.putLong

This commit is contained in:
Volker Berlin 2023-02-28 16:03:48 +01:00
parent 3de41deb3e
commit 3c2e431a9c
No known key found for this signature in database
GPG Key ID: 988423EF815BE4CB
6 changed files with 152 additions and 14 deletions

View File

@ -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");
* you may not use this file except in compliance with the License.
@ -65,10 +65,10 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
* {@inheritDoc}
*/
@Override
void init( WasmOptions options, ClassFileLoader classFileLoader ) {
void init( @Nonnull WasmOptions options, @Nonnull ClassFileLoader classFileLoader ) {
super.init( options, classFileLoader );
this.branchManager = new BranchManager( options, getInstructions(), getLocalVariables() );
this.unsafeManager = new UnsafeManager( options.functions );
this.unsafeManager = new UnsafeManager( options, classFileLoader );
}
/**

View File

@ -15,6 +15,7 @@
*/
package de.inetsoftware.jwebassembly.module;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -23,10 +24,12 @@ import java.util.Set;
import javax.annotation.Nonnull;
import de.inetsoftware.classparser.FieldInfo;
import de.inetsoftware.jwebassembly.WasmException;
import de.inetsoftware.jwebassembly.module.StackInspector.StackValue;
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
import de.inetsoftware.jwebassembly.wasm.AnyType;
import de.inetsoftware.jwebassembly.wasm.NamedStorageType;
import de.inetsoftware.jwebassembly.wasm.ValueType;
import de.inetsoftware.jwebassembly.wasm.VariableOperator;
@ -84,16 +87,27 @@ class UnsafeManager {
@Nonnull
private final FunctionManager functions;
@Nonnull
private final TypeManager types;
@Nonnull
private final ClassFileLoader classFileLoader;
private final HashMap<FunctionName, UnsafeState> unsafes = new HashMap<>();
/**
* Create an instance of the manager
*
* @param functions
* The function manager to register the synthetic functions.
* @param options
* compiler option/properties
* @param classFileLoader
* for loading the class files
*/
UnsafeManager( @Nonnull FunctionManager functions ) {
this.functions = functions;
UnsafeManager( @Nonnull WasmOptions options, @Nonnull ClassFileLoader classFileLoader ) {
this.functions = options.functions;
this.types = options.types;
this.classFileLoader = classFileLoader;
}
/**
@ -101,8 +115,10 @@ class UnsafeManager {
*
* @param instructions
* 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
for( int i = 0; i < instructions.size(); i++ ) {
WasmInstruction instr = instructions.get( i );
@ -135,8 +151,10 @@ class UnsafeManager {
* the index in the instructions
* @param callInst
* 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();
switch( name.signatureName ) {
case "sun/misc/Unsafe.getUnsafe()Lsun/misc/Unsafe;":
@ -332,8 +350,10 @@ class UnsafeManager {
* the index in the instructions
* @param callInst
* 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 );
// 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 );
}
useFieldName( state );
nop( instructions, from, idx + 2 );
}
@ -373,8 +394,10 @@ class UnsafeManager {
* the method call to Unsafe
* @param isAtomicReferenceFieldUpdater
* 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 );
// objectFieldOffset() has 3 parameters THIS(Unsafe), class and the fieldname
@ -389,6 +412,7 @@ class UnsafeManager {
stackValue = StackInspector.findInstructionThatPushValue( paramInstructions, classParamIdx, callInst.getCodePosition() );
state.typeName = getClassConst( instructions, stackValue );
useFieldName( state );
nop( instructions, from, idx + 2 );
}
@ -435,6 +459,20 @@ class UnsafeManager {
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
*
@ -550,10 +588,17 @@ class UnsafeManager {
+ " local.get 3" // x
+ " struct.set " + state.typeName + ' ' + state.fieldName;
case "getInt":
case "getLong":
return "local.get 1" // THIS
+ " struct.get " + state.typeName + ' ' + state.fieldName //
+ " return";
case "getObjectVolatile":
return "local.get 1" // array
+ " local.get 2" // the array index
+ " array.get " + state.typeName;
+ " array.get " + state.typeName
+ " return";
}
throw new RuntimeException( name.signatureName );

View File

@ -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");
* you may not use this file except in compliance with the License.
@ -103,7 +103,7 @@ public abstract class WasmCodeBuilder {
* @param classFileLoader
* 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.types = options.types;
this.functions = options.functions;
@ -250,10 +250,20 @@ public abstract class WasmCodeBuilder {
*
* @return the type manager
*/
@Nonnull
protected TypeManager getTypeManager() {
return types;
}
/**
* For loading missing class declarations
* @return the loader
*/
@Nonnull
protected ClassFileLoader getClassFileLoader() {
return classFileLoader;
}
/**
* Reset the code builder.
*

View File

@ -229,6 +229,7 @@ class WasmStructInstruction extends WasmInstruction {
}
}
comment = fieldName.getName();
assert idx >=0;
break;
case INSTANCEOF:
case CAST:

View 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 );
}
}
}

View File

@ -19,6 +19,7 @@ import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
@ -58,6 +59,7 @@ public class UnsafeTest extends AbstractBaseTest {
addParam( list, script, "getAndSetReference" );
addParam( list, script, "lazySetReference" );
addParam( list, script, "atomicReferenceFieldUpdater" );
addParam( list, script, "putLong" );
}
rule.setTestParameters( list );
@ -179,5 +181,11 @@ public class UnsafeTest extends AbstractBaseTest {
stream.close();
return 42;
}
@Export
static int putLong() {
ThreadLocalRandom.current().nextInt();
return 42;
}
}
}