/* * Copyright 2018 - 2022 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 java.util.LinkedList; import java.util.List; import java.util.function.DoubleUnaryOperator; import java.util.function.IntSupplier; import java.util.function.IntUnaryOperator; 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; @SuppressWarnings( { "javadoc", "null", "rawtypes", "cast", "boxing" } ) public class StructsNonGC extends AbstractBaseTest { @ClassRule public static WasmRule rule = new WasmRule( TestClass.class, Abc.class ); public StructsNonGC( ScriptEngine script, String method, Object[] params ) { super( rule, script, method, params ); } @Parameters( name = "{0}-{1}" ) public static Collection data() { ArrayList list = new ArrayList<>(); ScriptEngine[] engines = ScriptEngine.testEngines(); for( ScriptEngine script : engines ) { addParam( list, script, "isNull" ); addParam( list, script, "isNotNull" ); addParam( list, script, "isSame" ); addParam( list, script, "isNotSame" ); addParam( list, script, "simple" ); addParam( list, script, "callSuperMethod" ); addParam( list, script, "callVirtualMethod" ); addParam( list, script, "useGlobalObject" ); addParam( list, script, "multipleAssign" ); addParam( list, script, "getDefaultValue" ); addParam( list, script, "callAbstractMethod" ); addParam( list, script, "instanceof1" ); addParam( list, script, "instanceof2" ); addParam( list, script, "instanceof3" ); addParam( list, script, "instanceof4" ); addParam( list, script, "cast1" ); addParam( list, script, "cast2" ); addParam( list, script, "objectClassName" ); addParam( list, script, "integerClassName" ); addParam( list, script, "classClassName" ); addParam( list, script, "classConst" ); addParam( list, script, "intClassName" ); addParam( list, script, "getComponentType" ); addParam( list, script, "branchWithObjectResult" ); addParam( list, script, "callParameterFromCondition" ); addParam( list, script, "lambda0" ); addParam( list, script, "lambda1" ); addParam( list, script, "lambda2" ); addParam( list, script, "lambda3" ); addParam( list, script, "lambdaWithInstanceAccess" ); addParam( list, script, "lambdaInsideTryCatch" ); addParam( list, script, "simpleName_Object" ); addParam( list, script, "simpleName_Anonymous" ); addParam( list, script, "simpleName_Array" ); addParam( list, script, "simpleName_InnerClass" ); addParam( list, script, "simpleName_LocalClass" ); addParam( list, script, "isPrimitive_int" ); addParam( list, script, "isPrimitive_Object" ); } rule.setTestParameters( list ); return list; } static class TestClass { @Export static boolean isNull() { Object val = null; return val == null; } @Export static boolean isNotNull() { Object val = null; return val != null; } @Export static boolean isSame() { Object val1 = null; Object val2 = null; return val1 == val2; } @Export static boolean isNotSame() { Object val1 = null; Object val2 = null; return val1 != val2; } @Export static int simple() { Abc val = new Abc2(); val.a = 63; return val.a; } /** * Call a method that is declared in the super class of the instance */ @Export static int callSuperMethod() { Abc2 val = new Abc2(); val.foo(); return val.a; } /** * Call an overridden method */ @Export static int callVirtualMethod() { Abc val = new Abc2(); val.bar(); return val.a; } /** * Access a object in a global/static variable. */ static Abc2 valGlobal; @Export static int useGlobalObject() { valGlobal = new Abc2(); valGlobal.foo(); return valGlobal.a; } /** * Assign multiple with a field. There are complex stack operation */ @Export static int multipleAssign() { Abc2 val = new Abc2(); for( int i = 0; i < 1_000; i++ ) { val = val.abc = new Abc2(); val.a = i; } return val.a; } @Export static int getDefaultValue() { Abc2 val = new Abc2(); return val.getDefault(); } @Export static int callAbstractMethod() { Ab val = new Abc2(); return val.abstractBar(); } @Export static boolean instanceof1() { Object obj = new Object(); return obj instanceof Integer; } @Export static boolean instanceof2() { Object obj = new Object(); return obj instanceof Object; } @Export static boolean instanceof3() { Object obj = new LinkedList(); return obj instanceof List; } @Export static boolean instanceof4() { Object obj = null; return obj instanceof List; } @Export static int cast1() { Object obj = new Integer(42); Integer val = (Integer)obj; return val.intValue(); } @Export static Integer cast2() { Object obj = null; Integer val = (Integer)obj; return val; } @Export static DOMString objectClassName() { Object obj = new Object(); Class clazz = obj.getClass(); return JSObject.domString( clazz.getName() ); } @Export static DOMString integerClassName() { Object obj = new Integer(42); Class clazz = obj.getClass(); return JSObject.domString( clazz.getName() ); } @Export static DOMString classClassName() { Object obj = new Object(); Class clazz = obj.getClass().getClass(); return JSObject.domString( clazz.getName() ); } @Export static DOMString classConst() { Class clazz = Float.class; return JSObject.domString( clazz.getName() ); } @Export static Object intClassName() { Class clazz = int.class; // Integer.TYPE; return JSObject.domString( clazz.getName() ); } @Export static DOMString simpleName_Object() { Object obj = new Object(); Class clazz = obj.getClass(); return JSObject.domString( clazz.getSimpleName() ); } @Export static DOMString simpleName_Anonymous() { Object obj = new Object() {}; Class clazz = obj.getClass(); return JSObject.domString( clazz.getSimpleName() ); } @Export static DOMString simpleName_Array() { Object obj = new Object[0]; Class clazz = obj.getClass(); return JSObject.domString( clazz.getSimpleName() ); } @Export static DOMString simpleName_InnerClass() { Class clazz = TestClass.class; return JSObject.domString( clazz.getSimpleName() ); } @Export static DOMString simpleName_LocalClass() { class Foobar {} Object obj = new Foobar(); Class clazz = obj.getClass(); return JSObject.domString( clazz.getSimpleName() ); } @Export static boolean getComponentType() { Class clazz = byte.class; clazz = clazz.getComponentType(); return clazz == null; } @Export static int branchWithObjectResult() { Integer val1 = 42; Integer val2 = 7; Integer val = val1 == val2 ? val1 : val2; return val; } /** * To find the instruction that push the object of the method call we need to consider an IF THEN ELSE when analyzing the stack. */ @Export static int callParameterFromCondition() { Abc abc = new Abc(); return abc.add( 42, abc == null ? 7 : 13 ); } @Export static int lambda0() { IntSupplier val = () -> 42; return val.getAsInt(); } @Export static int lambda1() { IntUnaryOperator val = (x) -> x; return val.applyAsInt( 13 ); } @Export static int lambda2() { int v1 = 42; IntUnaryOperator val = (x) -> x + v1; return val.applyAsInt( 13 ); } @Export static double lambda3() { int v1 = 42; int v2 = 7; DoubleUnaryOperator val = (x) -> x * v2 + v1; return val.applyAsDouble( 13 ); } @Export public static int lambdaWithInstanceAccess() { TestClass test = new TestClass(); return test.lambdaWithInstanceAccessImpl(); } private int field; private int lambdaWithInstanceAccessImpl() { field = 13; IntSupplier val = () -> field; return val.getAsInt(); } @Export public static int lambdaInsideTryCatch() { int result = 17; int field = 13; try { IntSupplier val = () -> field; result = val.getAsInt(); } catch( Throwable ex ) { result = 42; } return result; } @Export static boolean isPrimitive_int() { return int.class.isPrimitive(); } @Export static boolean isPrimitive_Object() { return Object.class.isPrimitive(); } } interface TestDefault { default int getDefault() { return 7; } } static abstract class Ab { abstract int abstractBar(); } static class Abc extends Ab implements TestDefault { int a; long b; final void foo() { a = 1; } void bar() { a = 2; } @Override int abstractBar() { return 2; } int add( int a, int b ) { return a + b; } } static class Abc2 extends Abc { Abc2 abc; @Override void bar() { a = 3; } @Override int abstractBar() { return 3; } } }