From d20accc20c279ec43b8c24c26b8388fdd7580c17 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 28 Aug 2018 15:47:08 +0300 Subject: [PATCH] Add support for Array.set --- .../lang/reflect/ArrayNativeGenerator.java | 48 +++++++++++++++++++ .../classlib/java/lang/reflect/TArray.java | 12 +++++ .../classlib/java/lang/reflect/ArrayTest.java | 17 +++++++ 3 files changed, 77 insertions(+) diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java index f89e411d4..09e3deeb5 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java @@ -53,6 +53,9 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin { case "getImpl": reachGet(agent, method); break; + case "setImpl": + reachSet(agent, method); + break; } } @@ -68,6 +71,9 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin { case "getImpl": generateGet(context, writer); break; + case "setImpl": + generateSet(context, writer); + break; } } @@ -126,6 +132,31 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin { writer.outdent().append("}").softNewLine(); } + private void generateSet(GeneratorContext context, SourceWriter writer) throws IOException { + String array = context.getParameterName(1); + String item = context.getParameterName(3); + writer.append("var type = " + array + ".constructor.$meta.item;").softNewLine(); + boolean first = true; + for (int i = 0; i < primitives.length; ++i) { + String wrapper = "java.lang." + primitiveWrappers[i]; + MethodReference methodRef = new MethodReference(wrapper, primitives[i].toLowerCase() + "Value", + primitiveTypes[i]); + ClassReader cls = context.getClassSource().get(methodRef.getClassName()); + if (cls == null || cls.getMethod(methodRef.getDescriptor()) == null) { + continue; + } + if (!first) { + writer.append(" else "); + } + first = false; + writer.append("if (type === $rt_" + primitives[i].toLowerCase() + "cls()) {").indent().softNewLine(); + writer.append(item + " = ").appendMethodBody(methodRef).append("(" + item + ");").softNewLine(); + writer.outdent().append("}"); + } + writer.softNewLine(); + writer.append(array + ".data[" + context.getParameterName(2) + "] = " + item + ";").softNewLine(); + } + private void reachGet(DependencyAgent agent, MethodDependency method) { method.getVariable(1).getArrayItem().connect(method.getResult()); method.getVariable(1).addConsumer(type -> { @@ -143,4 +174,21 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin { } }); } + + private void reachSet(DependencyAgent agent, MethodDependency method) { + method.getVariable(3).connect(method.getVariable(1).getArrayItem()); + method.getVariable(1).addConsumer(type -> { + if (type.getName().startsWith("[")) { + String typeName = type.getName().substring(1); + for (int i = 0; i < primitiveTypes.length; ++i) { + if (primitiveTypes[i].toString().equals(typeName)) { + String wrapper = "java.lang." + primitiveWrappers[i]; + MethodReference methodRef = new MethodReference(wrapper, + primitives[i].toLowerCase() + "Value", primitiveTypes[i]); + agent.linkMethod(methodRef, null).use(); + } + } + } + }); + } } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java index 6aa9971da..308afde37 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/reflect/TArray.java @@ -79,7 +79,19 @@ public final class TArray extends TObject { return getImpl(array, index); } + public static void set(TObject array, int index, TObject value) throws TIllegalArgumentException, + TArrayIndexOutOfBoundsException { + if (index < 0 || index >= getLength(array)) { + throw new TArrayIndexOutOfBoundsException(); + } + setImpl(array, index, value); + } + @GeneratedBy(ArrayNativeGenerator.class) @PluggableDependency(ArrayNativeGenerator.class) private static native TObject getImpl(TObject array, int index); + + @GeneratedBy(ArrayNativeGenerator.class) + @PluggableDependency(ArrayNativeGenerator.class) + private static native void setImpl(TObject array, int index, TObject value); } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/reflect/ArrayTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/reflect/ArrayTest.java index 196cc8c5d..8bd89e0f3 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/reflect/ArrayTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/reflect/ArrayTest.java @@ -15,6 +15,7 @@ */ package org.teavm.classlib.java.lang.reflect; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import java.lang.reflect.Array; import org.junit.Test; @@ -36,4 +37,20 @@ public class ArrayTest { assertEquals(int[].class, instance.getClass()); assertEquals(15, Array.getLength(instance)); } + + @Test + public void setWorks() { + Object array = Array.newInstance(String.class, 2); + Array.set(array, 0, "foo"); + Array.set(array, 1, "bar"); + assertArrayEquals(new String[] { "foo", "bar" }, (String[]) array); + } + + @Test + public void setPrimitiveWorks() { + Object array = Array.newInstance(int.class, 2); + Array.set(array, 0, 23); + Array.set(array, 1, 42); + assertArrayEquals(new int[] { 23, 42 }, (int[]) array); + } }