diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java index 9e60cc21fd4caeab36ffe79306617ecc27d1c8ea..2ee572ca4c6ee226ad4f84b4165a4976ce428747 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java @@ -71,7 +71,12 @@ public class RArgsValuesAndNamesMR { @Resolve(message = "KEYS") public abstract static class RArgsValuesAndNamesKeysNode extends Node { protected Object access(RArgsValuesAndNames receiver) { - return RDataFactory.createStringVector(receiver.getSignature().getNames(), RDataFactory.COMPLETE_VECTOR); + ArgumentsSignature signature = receiver.getSignature(); + String[] names = signature.getNames(); + if (names == null) { + return RDataFactory.createStringVector(new String[signature.getLength()], RDataFactory.COMPLETE_VECTOR); + } + return RDataFactory.createStringVector(names, RDataFactory.COMPLETE_VECTOR).makeSharedPermanent(); } } @@ -112,6 +117,10 @@ public class RArgsValuesAndNamesMR { protected Object access(RArgsValuesAndNames receiver, String identifier) { ArgumentsSignature sig = receiver.getSignature(); String[] names = sig.getNames(); + if (names == null) { + throw UnknownIdentifierException.raise("" + identifier); + } + int idx = -1; for (int i = 0; i < names.length; i++) { if (names[i].equals(identifier)) { @@ -150,6 +159,9 @@ public class RArgsValuesAndNamesMR { protected Object access(RArgsValuesAndNames receiver, String identifier) { ArgumentsSignature sig = receiver.getSignature(); String[] names = sig.getNames(); + if (names == null) { + return 0; + } int idx = -1; for (int i = 0; i < names.length; i++) { if (names[i].equals(identifier)) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java index 7fd4ccfd8cf47d00c8c5de672a6d7075b7954e36..9fdfeb7214524061323e7a79b66264f6bdb34de4 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/FortranAndCFunctions.java @@ -16,6 +16,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -331,12 +332,16 @@ public class FortranAndCFunctions { namesProfile.enter(); String[] argNames = sig.getNames(); String[] names = new String[sig.getLength()]; - for (int i = 0; i < sig.getLength(); i++) { - String argName = argNames[i]; - if (argName == null) { - names[i] = ""; - } else { - names[i] = argName; + if (argNames == null) { + Arrays.fill(names, ""); + } else { + for (int i = 0; i < sig.getLength(); i++) { + String argName = argNames[i]; + if (argName == null) { + names[i] = ""; + } else { + names[i] = argName; + } } } namesSetter.execute(result, RDataFactory.createStringVector(names, true)); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java index ae22e9d513dfb264e7b2d91fd4d0bbdf6d7afa11..ecd287b87b5bdf9a1c120d634bc935e074af3c8c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ArgumentsSignature.java @@ -45,6 +45,7 @@ public final class ArgumentsSignature implements Iterable<String> { */ public static final String UNMATCHED = new String(); public static final String VARARG_NAME = "..."; + public static final int[] EMPTY_VARARGS_INDEXES = new int[0]; public static final int NO_VARARG = -1; @CompilationFinal(dimensions = 1) private static final ArgumentsSignature[] EMPTY_SIGNATURES = new ArgumentsSignature[32]; @@ -89,46 +90,58 @@ public final class ArgumentsSignature implements Iterable<String> { @CompilationFinal(dimensions = 1) private final String[] names; @CompilationFinal(dimensions = 1) private final int[] varArgIndexes; @CompilationFinal(dimensions = 1) private final boolean[] isVarArg; + private final int length; private final int varArgIndex; private final int nonNullCount; private ArgumentsSignature(String[] names, boolean convertEmpty) { - this.names = new String[names.length]; + this.length = names.length; + String[] localNames = null; int nonNull = 0; for (int i = 0; i < names.length; i++) { String s = names[i]; if (s == null || (s.isEmpty() && convertEmpty)) { - this.names[i] = null; continue; + } else if (localNames == null) { + localNames = new String[names.length]; } nonNull++; - this.names[i] = s == UNMATCHED ? s : s.intern(); + localNames[i] = s == UNMATCHED ? s : s.intern(); } + this.names = localNames; this.nonNullCount = nonNull; - int index = NO_VARARG; - int count = 0; - this.isVarArg = new boolean[names.length]; - for (int i = 0; i < names.length; i++) { - String name = names[i]; - if (name != null) { - if (VARARG_NAME.equals(name)) { - this.isVarArg[i] = true; - count++; - if (index != NO_VARARG) { - index = i; + int varArgsCount = 0; + boolean[] isVarArgsLocal = null; + if (localNames != null) { + for (int i = 0; i < names.length; i++) { + String name = names[i]; + if (name != null) { + if (VARARG_NAME.equals(name)) { + if (isVarArgsLocal == null) { + isVarArgsLocal = new boolean[names.length]; + } + isVarArgsLocal[i] = true; + varArgsCount++; } } } } - int pos = 0; - this.varArgIndexes = new int[count]; - for (int i = 0; i < names.length; i++) { - if (isVarArg[i]) { - varArgIndexes[pos++] = i; + this.isVarArg = isVarArgsLocal; + + if (isVarArgsLocal == null) { + this.varArgIndexes = EMPTY_VARARGS_INDEXES; + this.varArgIndex = NO_VARARG; + } else { + int pos = 0; + this.varArgIndexes = new int[varArgsCount]; + for (int i = 0; i < names.length; i++) { + if (isVarArgsLocal[i]) { + varArgIndexes[pos++] = i; + } } + this.varArgIndex = varArgIndexes[0]; } - this.varArgIndex = varArgIndexes.length == 0 ? NO_VARARG : varArgIndexes[0]; } public boolean isEmpty() { @@ -136,7 +149,7 @@ public final class ArgumentsSignature implements Iterable<String> { } public int getLength() { - return names.length; + return length; } public int getNonNullCount() { @@ -157,6 +170,9 @@ public final class ArgumentsSignature implements Iterable<String> { } public String getName(int index) { + if (names == null) { + return null; + } return names[index] == UNMATCHED ? null : names[index]; } @@ -169,11 +185,11 @@ public final class ArgumentsSignature implements Iterable<String> { * {@link #getName(int)} returns {@code null} in either case. */ public boolean isUnmatched(int index) { - return names[index] == UNMATCHED; + return names != null && names[index] == UNMATCHED; } public boolean isVarArg(int index) { - return this.isVarArg[index]; + return this.isVarArg != null && this.isVarArg[index]; } /** @@ -181,6 +197,9 @@ public final class ArgumentsSignature implements Iterable<String> { * interned string. */ public int indexOfName(String find) { + if (names == null) { + return -1; + } for (int i = 0; i < names.length; i++) { if (names[i] == find) { return i; @@ -191,7 +210,7 @@ public final class ArgumentsSignature implements Iterable<String> { @Override public int hashCode() { - return Arrays.hashCode(names); + return Arrays.hashCode(names) ^ length; } @Override @@ -212,11 +231,13 @@ public final class ArgumentsSignature implements Iterable<String> { @Override public Iterator<String> iterator() { CompilerAsserts.neverPartOfCompilation(); - return Arrays.asList(names).iterator(); + String[] namesLocal = names == null ? new String[length] : names; + return Arrays.asList(namesLocal).iterator(); } @Override public String toString() { - return "Signature " + Arrays.toString(names); + String value = names == null ? length + " times null" : Arrays.toString(names); + return "Signature " + value; } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java index 3d0ebeeded4794001e641a87ef5fb5bd729c9423..24685419efb0e382b59e3599281dfcabb4d94d6e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java @@ -292,11 +292,14 @@ public final class RScope extends AbstractScope { assert RArguments.isRFrame(env.getFrame()); RFunction f = RArguments.getFunction(env.getFrame()); if (f != null) { - return RContext.getRRuntimeASTAccess().getArgumentsSignature(f).getNames(); + ArgumentsSignature signature = RContext.getRRuntimeASTAccess().getArgumentsSignature(f); + String[] names = signature.getNames(); + return names == null ? new String[signature.getLength()] : names; } else { ArgumentsSignature suppliedSignature = RArguments.getSuppliedSignature(env.getFrame()); if (suppliedSignature != null) { - return suppliedSignature.getNames(); + String[] names = suppliedSignature.getNames(); + return names == null ? new String[suppliedSignature.getLength()] : names; } } }