From 3c2e431a9c353a82446c4537fb37aa9f0d6fa86e Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Tue, 28 Feb 2023 16:03:48 +0100 Subject: [PATCH] Unsafe.putInt and Unsafe.putLong --- .../module/JavaMethodWasmCodeBuilder.java | 6 +- .../jwebassembly/module/UnsafeManager.java | 63 +++++++++++++--- .../jwebassembly/module/WasmCodeBuilder.java | 14 +++- .../module/WasmStructInstruction.java | 1 + .../jwebassembly/runtime/ThreadTest.java | 74 +++++++++++++++++++ .../jwebassembly/runtime/UnsafeTest.java | 8 ++ 6 files changed, 152 insertions(+), 14 deletions(-) create mode 100644 test/de/inetsoftware/jwebassembly/runtime/ThreadTest.java diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index 677e9dc..9631746 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -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 ); } /** diff --git a/src/de/inetsoftware/jwebassembly/module/UnsafeManager.java b/src/de/inetsoftware/jwebassembly/module/UnsafeManager.java index ede5b7f..ffa2cc2 100644 --- a/src/de/inetsoftware/jwebassembly/module/UnsafeManager.java +++ b/src/de/inetsoftware/jwebassembly/module/UnsafeManager.java @@ -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 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 instructions ) { + void replaceUnsafe( @Nonnull List 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 instructions, int idx, WasmCallInstruction callInst ) { + private void patch( List 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 instructions, int idx, WasmCallInstruction callInst ) { + private void patch_objectFieldOffset_Java8( List 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 instructions, int idx, WasmCallInstruction callInst, boolean isAtomicReferenceFieldUpdater ) { + private void patch_objectFieldOffset_Java11( List 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 ); diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index c2d1f1d..851493a 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -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. * diff --git a/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java index 9cd3677..91012e6 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java @@ -229,6 +229,7 @@ class WasmStructInstruction extends WasmInstruction { } } comment = fieldName.getName(); + assert idx >=0; break; case INSTANCEOF: case CAST: diff --git a/test/de/inetsoftware/jwebassembly/runtime/ThreadTest.java b/test/de/inetsoftware/jwebassembly/runtime/ThreadTest.java new file mode 100644 index 0000000..3387413 --- /dev/null +++ b/test/de/inetsoftware/jwebassembly/runtime/ThreadTest.java @@ -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 data() { + ArrayList 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 ); + } + } +} diff --git a/test/de/inetsoftware/jwebassembly/runtime/UnsafeTest.java b/test/de/inetsoftware/jwebassembly/runtime/UnsafeTest.java index aea9756..ee6625f 100644 --- a/test/de/inetsoftware/jwebassembly/runtime/UnsafeTest.java +++ b/test/de/inetsoftware/jwebassembly/runtime/UnsafeTest.java @@ -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; + } } }