diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java index cd6d41817b4d91f61a22c6ba51876a49930b52da..3def348e2a7995a765fc1cd53c40eac769360d26 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java @@ -31,13 +31,16 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RFunction; @@ -57,28 +60,36 @@ public abstract class RfEvalNode extends FFIUpCallNode.Arg2 { return RfEvalNodeGen.create(); } + private static RCaller createCall(REnvironment env) { + Frame frame = Utils.getActualCurrentFrame(); + RCaller originalCaller = RArguments.getCall(env.getFrame()); + return RCaller.createForPromise(originalCaller, frame); + } + @Specialization @TruffleBoundary Object handlePromise(RPromise expr, @SuppressWarnings("unused") RNull nulLEnv) { - return getPromiseHelper().evaluate(null, expr); + return getPromiseHelper().evaluate(Utils.getActualCurrentFrame().materialize(), expr); } @Specialization @TruffleBoundary - Object handlePromise(RPromise expr, @SuppressWarnings("unused") REnvironment env) { - return getPromiseHelper().evaluate(null, expr); + Object handlePromise(RPromise expr, REnvironment env) { + return getPromiseHelper().evaluate(env.getFrame(), expr); } @Specialization @TruffleBoundary Object handleExpression(RExpression expr, Object envArg) { - return RContext.getEngine().eval(expr, getEnv(envArg), null); + REnvironment env = getEnv(envArg); + return RContext.getEngine().eval(expr, env, createCall(env)); } @Specialization(guards = "expr.isLanguage()") @TruffleBoundary Object handleLanguage(RPairList expr, Object envArg) { - return RContext.getEngine().eval(expr, getEnv(envArg), null); + REnvironment env = getEnv(envArg); + return RContext.getEngine().eval(expr, env, createCall(env)); } @Specialization @@ -124,7 +135,7 @@ public abstract class RfEvalNode extends FFIUpCallNode.Arg2 { @TruffleBoundary private static Object evalFunction(RFunction f, REnvironment env, ArgumentsSignature argsNames, Object... args) { - return RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : env.getFrame(), RCaller.topLevel, true, argsNames, args); + return RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : env.getFrame(), createCall(env), true, argsNames, args); } @Fallback diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java index 63e827950501127a3a6c4a981b22a6bc8d71f19c..962eb99b04fcd2c1b15def407e8c91e728e2d0f3 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Assign.java @@ -149,6 +149,7 @@ public abstract class Assign extends RBuiltinNode.Arg4 { } protected final ValueProfile frameAccessProfile = ValueProfile.createClassProfile(); + protected final ValueProfile frameProfile = ValueProfile.createClassProfile(); public abstract void execute(VirtualFrame frame, REnvironment env, String name, Object value); @@ -156,11 +157,15 @@ public abstract class Assign extends RBuiltinNode.Arg4 { return ResolvedWriteSuperFrameVariableNodeGen.create(name, Mode.REGULAR, null, null, FrameSlotNode.create(findOrAddFrameSlot(envDesc, name, FrameSlotKind.Illegal))); } - @Specialization(guards = {"env.getFrame(frameAccessProfile).getFrameDescriptor() == envDesc", "write.getName().equals(name)"}) + protected FrameDescriptor getFrameDescriptor(REnvironment env) { + return frameProfile.profile(env.getFrame(frameAccessProfile)).getFrameDescriptor(); + } + + @Specialization(guards = {"getFrameDescriptor(env) == envDesc", "write.getName().equals(name)"}) protected void assignCached(VirtualFrame frame, REnvironment env, @SuppressWarnings("unused") String name, Object value, @Cached("env.getFrame().getFrameDescriptor()") @SuppressWarnings("unused") FrameDescriptor envDesc, @Cached("createWrite(name, envDesc)") ResolvedWriteSuperFrameVariableNode write) { - write.execute(frame, value, env.getFrame(frameAccessProfile)); + write.execute(frame, value, frameProfile.profile(env.getFrame(frameAccessProfile))); } @Specialization(replaces = "assignCached") diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index c89561bf38828d6f30571f0cd98efd44e3cbef83..406d3eb5d20d3ec54199db9517ef1478bc52cf6d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -134,6 +134,8 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRStackTrace; import com.oracle.truffle.r.nodes.builtin.fastr.FastRStackTraceNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRSyntaxTree; import com.oracle.truffle.r.nodes.builtin.fastr.FastRSyntaxTreeNodeGen; +import com.oracle.truffle.r.nodes.builtin.fastr.FastRTestsTry; +import com.oracle.truffle.r.nodes.builtin.fastr.FastRTestsTryNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRThrowIt; import com.oracle.truffle.r.nodes.builtin.fastr.FastRThrowItNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRTrace; @@ -142,8 +144,6 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRTree; import com.oracle.truffle.r.nodes.builtin.fastr.FastRTreeNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRTreeStats; import com.oracle.truffle.r.nodes.builtin.fastr.FastRTreeStatsNodeGen; -import com.oracle.truffle.r.nodes.builtin.fastr.FastRTestsTry; -import com.oracle.truffle.r.nodes.builtin.fastr.FastRTestsTryNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrls; import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrlsNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.memprof.FastRprofmem; @@ -638,7 +638,6 @@ public class BasePackage extends RBuiltinPackage { add(MatMult.class, MatMult::create); add(Match.class, MatchNodeGen::create); add(MatchFun.class, MatchFunNodeGen::create); - add(MatchArg.class, MatchArgNodeGen::create); add(Matrix.class, MatrixNodeGen::create); add(Max.class, MaxNodeGen::create); add(Mean.class, MeanNodeGen::create); @@ -876,6 +875,7 @@ public class BasePackage extends RBuiltinPackage { addFastPath(baseFrame, "rbind", FastPathFactory.FORCED_EAGER_ARGS); addFastPath(baseFrame, "seq.default", SeqFunctionsFactory.SeqDefaultFastPathNodeGen::create, RVisibility.ON); addFastPath(baseFrame, "seq", SeqFunctionsFactory.SeqFastPathNodeGen::create, RVisibility.ON); + addFastPath(baseFrame, "match.arg", MatchArgFastPathNodeGen::create, MatchArgFastPath.class); setContainsDispatch(baseFrame, "eval", "[.data.frame", "[[.data.frame", "[<-.data.frame", "[[<-.data.frame"); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java index 5d56afcee2c928d467ea8394658de6d6351dd47c..49d139a0ebf9c5d9f25306b6e77863190784dff9 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/DoCall.java @@ -127,6 +127,7 @@ public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSynta @Child private GetNamesAttributeNode getNamesNode; @Child private SetVisibilityNode setVisibilityNode; private final ValueProfile frameAccessProfile = ValueProfile.createClassProfile(); + private final ValueProfile frameProfile = ValueProfile.createClassProfile(); private final RNodeClosureCache languagesClosureCache = new RNodeClosureCache(); private final SymbolClosureCache symbolsClosureCache = new SymbolClosureCache(); @@ -137,7 +138,7 @@ public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSynta public abstract Object execute(VirtualFrame virtualFrame, String funcName, RFunction func, RList argsAsList, boolean quote, REnvironment env); protected FrameDescriptor getFrameDescriptor(REnvironment env) { - return env.getFrame(frameAccessProfile).getFrameDescriptor(); + return frameProfile.profile(env.getFrame(frameAccessProfile)).getFrameDescriptor(); } /** @@ -152,7 +153,7 @@ public abstract class DoCall extends RBuiltinNode.Arg4 implements InternalRSynta @Cached("create()") GetVisibilityNode getVisibilityNode, @Cached("createBinaryProfile()") ConditionProfile quoteProfile, @Cached("create()") BranchProfile containsRSymbolProfile) { - MaterializedFrame promiseFrame = env.getFrame(frameAccessProfile).materialize(); + MaterializedFrame promiseFrame = frameProfile.profile(env.getFrame(frameAccessProfile)).materialize(); RArgsValuesAndNames args = getArguments(promiseFrame, quote, quoteProfile, containsRSymbolProfile, argsAsList); RCaller caller = getExplicitCaller(virtualFrame, promiseFrame, funcName, func, args); MaterializedFrame evalFrame = getEvalFrame(virtualFrame, promiseFrame); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java index 324249e38dd0faea4957f0c13ce9ccb2e940f4f1..70e06d1a1aa32c642169ba05311a2a54ef7a1e2b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/EnvFunctions.java @@ -349,7 +349,7 @@ public class EnvFunctions { MaterializedFrame matFrame = callerFrame.execute(frame); matFrame = matFrame instanceof VirtualEvalFrame ? ((VirtualEvalFrame) matFrame).getOriginalFrame() : matFrame; - deoptFrameNode.deoptimizeFrame(matFrame); + deoptFrameNode.deoptimizeFrame(RArguments.getArguments(matFrame)); return REnvironment.frameToEnvironment(matFrame); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java index 9cc46a846c6409de9e221fff7a041e45ddc4c7ac..418fd51854110fa8e0a83ae1382fb5b290ffc833 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FrameFunctions.java @@ -444,7 +444,7 @@ public class FrameFunctions { } // Deoptimize every promise which is now in this frame, as it might leave it's stack - deoptFrameNode.deoptimizeFrame(result.getFrame()); + deoptFrameNode.deoptimizeFrame(RArguments.getArguments(result.getFrame())); return result; } } @@ -465,7 +465,7 @@ public class FrameFunctions { RPairList next = result; for (int i = 1; i < depth; i++) { MaterializedFrame mf = helper.getNumberedFrame(frame, i).materialize(); - deoptFrameNode.deoptimizeFrame(mf); + deoptFrameNode.deoptimizeFrame(RArguments.getArguments(mf)); next.setCar(REnvironment.frameToEnvironment(mf)); if (i != depth - 1) { RPairList pl = RDataFactory.createPairList(); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java index d13b44e5c9c3c93526c95a9cc2a1eaffe2b81e77..ddb5992e1f16d27b82bd93efb3a6239157c4d389 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Lapply.java @@ -48,6 +48,7 @@ import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; import com.oracle.truffle.r.runtime.nodes.InternalRSyntaxNodeChildren; @@ -84,10 +85,11 @@ public abstract class Lapply extends RBuiltinNode.Arg2 { @Specialization protected Object lapply(VirtualFrame frame, RAbstractVector vec, RFunction fun, - @Cached("create()") ExtractNamesAttributeNode extractNamesNode) { + @Cached("create()") ExtractNamesAttributeNode extractNamesNode, + @Cached("create()") VectorFactory factory) { Object[] result = lapply.execute(frame, vec, fun); // set here else it gets overridden by the iterator evaluation - return RDataFactory.createList(result, extractNamesNode.execute(vec)); + return factory.createList(result, extractNamesNode.execute(vec)); } @Specialization diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java index dc16026b21480763d246b606c21b49e00d356ee1..4b22d2a7e57ac45fd84b0eba60df7f48a5e7fc89 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ListBuiltin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; @RBuiltin(name = "list", kind = PRIMITIVE, parameterNames = {"..."}, behavior = PURE) public abstract class ListBuiltin extends RBuiltinNode.Arg1 { @@ -48,6 +49,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 { protected static final int CACHE_LIMIT = 2; protected static final int MAX_SHARE_OBJECT_NODES = 16; + @Child private VectorFactory factory = VectorFactory.create(); @Children private final ShareObjectNode[] shareObjectNodes = new ShareObjectNode[MAX_SHARE_OBJECT_NODES]; private final ConditionProfile namesNull = ConditionProfile.createBinaryProfile(); @@ -78,8 +80,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 { String orgName = signature.getName(i); names[i] = (orgName == null ? RRuntime.NAMES_ATTR_EMPTY_VALUE : orgName); } - RStringVector result = RDataFactory.createStringVector(names, RDataFactory.COMPLETE_VECTOR); - return result; + return factory.createStringVector(names, RDataFactory.COMPLETE_VECTOR); } /** @@ -99,7 +100,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 { for (int i = 0; i < cachedLength; i++) { getShareObjectNode(i).execute(argArray[i]); } - return RDataFactory.createList(argArray, cachedArgNames); + return factory.createList(argArray, cachedArgNames); } @Specialization(guards = "!args.isEmpty()") @@ -109,7 +110,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 { for (int i = 0; i < argArray.length; i++) { shareObjectNode.execute(argArray[i]); } - return RDataFactory.createList(argArray, argNameVector(args.getSignature())); + return factory.createList(argArray, argNameVector(args.getSignature())); } @Specialization(guards = "args.isEmpty()") @@ -119,7 +120,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 { @Specialization protected RList listMissing(@SuppressWarnings("unused") RMissing missing) { - return RDataFactory.createList(new Object[]{}); + return factory.createList(new Object[]{}); } @Specialization(guards = {"!isRArgsValuesAndNames(value)", "!isRMissing(value)"}) @@ -130,7 +131,7 @@ public abstract class ListBuiltin extends RBuiltinNode.Arg1 { CompilerDirectives.transferToInterpreterAndInvalidate(); suppliedSignatureArgNames = argNameVector(ArgumentsSignature.empty(1)); } - return RDataFactory.createList(new Object[]{value}, suppliedSignatureArgNames); + return factory.createList(new Object[]{value}, suppliedSignatureArgNames); } private ShareObjectNode getShareObjectNode(int index) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArgFastPath.java similarity index 96% rename from com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java rename to com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArgFastPath.java index f58283148d64ef914a001351d4363ed2c8423d36..fa1c53e1df78b1696a37b1eab76625b78b965cf6 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArg.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/MatchArgFastPath.java @@ -23,6 +23,7 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.toBoolean; import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder; import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; @@ -39,9 +40,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.RRootNode; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.stringValue; -import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; -import com.oracle.truffle.r.nodes.builtin.base.MatchArgNodeGen.MatchArgInternalNodeGen; +import com.oracle.truffle.r.nodes.builtin.base.MatchArgFastPathNodeGen.MatchArgInternalNodeGen; import com.oracle.truffle.r.nodes.function.FormalArguments; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.unary.CastNode; @@ -59,20 +58,12 @@ import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RTypes; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.nodes.RFastPathNode; import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; @RBuiltin(name = "match.arg", kind = SUBSTITUTE, parameterNames = {"arg", "choices", "several.ok"}, nonEvalArgs = {0}, behavior = COMPLEX) -public abstract class MatchArg extends RBuiltinNode.Arg3 { - - static { - Casts.noCasts(MatchArg.class); - } - - @Override - public Object[] getDefaultParameterValues() { - return new Object[]{RMissing.instance, RMissing.instance, RRuntime.LOGICAL_FALSE}; - } +public abstract class MatchArgFastPath extends RFastPathNode { @TypeSystemReference(RTypes.class) protected abstract static class MatchArgInternal extends Node { @@ -225,7 +216,7 @@ public abstract class MatchArg extends RBuiltinNode.Arg3 { @Specialization(limit = "1", guards = "cache.choicesValue.isSupported(frame, arg)") protected Object matchArg(VirtualFrame frame, RPromise arg, @SuppressWarnings("unused") RMissing choices, Object severalOK, @Cached("new(frame, arg)") MatchArgNode cache) { - return cache.internal.castAndExecute(cache.promiseHelper.evaluate(frame, arg), cache.choicesValue.execute(frame), severalOK); + return cache.internal.castAndExecute(cache.promiseHelper.evaluate(frame, arg), cache.choicesValue.execute(frame), severalOK == RMissing.instance ? RRuntime.LOGICAL_FALSE : severalOK); } public static final class MatchArgNode extends Node { @@ -248,7 +239,7 @@ public abstract class MatchArg extends RBuiltinNode.Arg3 { protected Object matchArg(VirtualFrame frame, RPromise arg, Object choices, Object severalOK, @Cached("createInternal()") MatchArgInternal internal, @Cached("new()") PromiseHelperNode promiseHelper) { - return internal.castAndExecute(promiseHelper.evaluate(frame, arg), choices, severalOK); + return internal.castAndExecute(promiseHelper.evaluate(frame, arg), choices, severalOK == RMissing.instance ? RRuntime.LOGICAL_FALSE : severalOK); } @SuppressWarnings("unused") diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java index 6194da9a6cd385a21cac054592523df563b7df4f..806b73434a170c7cfef7077594fb58f726253810 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/StandardGeneric.java @@ -6,7 +6,7 @@ * Copyright (c) 1995, 1996, 1997 Robert Gentleman and Ross Ihaka * Copyright (c) 1995-2014, The R Core Team * Copyright (c) 2002-2008, The R Foundation - * Copyright (c) 2015, 2017, Oracle and/or its affiliates + * Copyright (c) 2015, 2018, Oracle and/or its affiliates * * All rights reserved. */ @@ -72,6 +72,8 @@ public abstract class StandardGeneric extends RBuiltinNode.Arg2 { private final BranchProfile noGenFunFound = BranchProfile.create(); private final ConditionProfile sameNamesProfile = ConditionProfile.createBinaryProfile(); + private final ConditionProfile isBuiltinProfile = ConditionProfile.createBinaryProfile(); + private final ConditionProfile isDeferredProfile = ConditionProfile.createBinaryProfile(); static { Casts casts = new Casts(StandardGeneric.class); @@ -83,9 +85,9 @@ public abstract class StandardGeneric extends RBuiltinNode.Arg2 { private Object stdGenericInternal(VirtualFrame frame, String fname, RFunction fdef) { RFunction def = fdef; - if (def.isBuiltin()) { + if (isBuiltinProfile.profile(def.isBuiltin())) { def = RContext.getInstance().getPrimitiveMethodsInfo().getPrimGeneric(def.getRBuiltin().getPrimMethodIndex()); - if (def == null) { + if (isDeferredProfile.profile(def == null)) { return RRuntime.DEFERRED_DEFAULT_MARKER; } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java index f67c254ce6760e5525ff1ef194c5455be9f1c515..533db2210151c99af8b2518e8367a45846453b9a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/variables/LocalReadVariableNode.java @@ -51,6 +51,7 @@ public final class LocalReadVariableNode extends Node { private final Object identifier; private final boolean forceResult; + @CompilationFinal private boolean firstExecution = true; @CompilationFinal(dimensions = 1) private boolean[] seenValueKinds; @CompilationFinal private ValueProfile valueProfile; @@ -144,6 +145,13 @@ public final class LocalReadVariableNode extends Node { isPromiseProfile = ConditionProfile.createBinaryProfile(); } if (isPromiseProfile.profile(result instanceof RPromise)) { + if (firstExecution) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + firstExecution = false; + if (identifier instanceof String) { + return ReadVariableNode.evalPromiseSlowPathWithName((String) identifier, frame, (RPromise) result); + } + } if (promiseHelper == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); promiseHelper = insert(new PromiseHelperNode()); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java index f677a2ecfd1eafa8d83508c7a005c345d7ae131d..9c46ea23e765f8d32b78a6df739c19d75b859573 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/FunctionExpressionNode.java @@ -35,6 +35,7 @@ import com.oracle.truffle.r.nodes.function.opt.EagerEvalHelper; import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.nodes.instrumentation.RInstrumentation; import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; @@ -68,7 +69,7 @@ public final class FunctionExpressionNode extends RSourceSectionNode implements MaterializedFrame matFrame = frame.materialize(); if (deoptFrameNode != null) { // Deoptimize every promise which is now in this frame, as it might leave it's stack - deoptFrameNode.deoptimizeFrame(matFrame); + deoptFrameNode.deoptimizeFrame(RArguments.getArguments(matFrame)); } if (!initialized) { CompilerDirectives.transferToInterpreterAndInvalidate(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java index 934265d3025a5bfeac28d296ede2b8cc06bf5a5a..104121b451716238ff88773c4d589aa3d2bbcb2c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/GetBaseEnvFrameNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import com.oracle.truffle.r.runtime.env.REnvironment; */ public final class GetBaseEnvFrameNode extends Node { private final ValueProfile frameAccessProfile = ValueProfile.createClassProfile(); + private final ValueProfile frameProfile = ValueProfile.createClassProfile(); private final ValueProfile baseEnvProfile = ValueProfile.createIdentityProfile(); public static GetBaseEnvFrameNode create() { @@ -41,6 +42,6 @@ public final class GetBaseEnvFrameNode extends Node { public MaterializedFrame execute() { REnvironment baseEnv = baseEnvProfile.profile(REnvironment.baseEnv()); - return baseEnv.getFrame(frameAccessProfile); + return frameProfile.profile(baseEnv.getFrame(frameAccessProfile)); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java index 71968032f21c367cc1e6fedd27b6f6997aff8f04..018515b742e3bcddefa873886878fa119959c481 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java @@ -28,9 +28,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.Frame; -import com.oracle.truffle.api.frame.FrameSlot; -import com.oracle.truffle.api.frame.FrameSlotKind; -import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; @@ -45,13 +42,11 @@ import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.VirtualEvalFrame; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RPromise.EagerPromise; import com.oracle.truffle.r.runtime.data.RPromise.PromiseState; import com.oracle.truffle.r.runtime.data.RShareable; -import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; import com.oracle.truffle.r.runtime.nodes.RBaseNode; /** @@ -88,32 +83,19 @@ public final class PromiseHelperNode extends RBaseNode { * Guarantees, that all {@link RPromise}s in frame are deoptimized and thus are safe to * leave it's stack-branch. * - * @param frame The frame to check for {@link RPromise}s to deoptimize + * @param arguments The frame's arguments, which will be checked for {@link RPromise}s to + * deoptimize * @return Whether there was at least on {@link RPromise} which needed to be deoptimized. */ - @TruffleBoundary - public boolean deoptimizeFrame(MaterializedFrame frame) { + public boolean deoptimizeFrame(Object[] arguments) { boolean deoptOne = false; - for (FrameSlot slot : frame.getFrameDescriptor().getSlots().toArray(new FrameSlot[0])) { - // We're only interested in RPromises - if (slot.getKind() != FrameSlotKind.Object || !(slot.getIdentifier() instanceof String)) { - continue; - } - - // Try to read it... - try { - Object value = FrameSlotChangeMonitor.getObject(slot, frame); - - // If it's a promise, deoptimize it! - if (value instanceof RPromise) { - RPromise promise = (RPromise) value; - if (!promise.isEvaluated()) { - deoptOne |= deoptimize(promise); - } + for (Object value : arguments) { + // If it's a promise, deoptimize it! + if (value instanceof RPromise) { + RPromise promise = (RPromise) value; + if (!promise.isEvaluated()) { + deoptOne |= deoptimize(promise); } - } catch (FrameSlotTypeException err) { - // Should not happen after former check on FrameSlotKind! - throw RInternalError.shouldNotReachHere(); } } return deoptOne; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java index 84fb2f06e21b2fb8e65bcec9db896f3cce97e87f..6f987abcbbe6212c1ee3d90b6fcc47c37eebc22d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java @@ -1202,4 +1202,9 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS public static Object createDeferredMemberAccess(TruffleObject object, String name) { return new DeferredFunctionValue(object, name); } + + @Override + public String toString() { + return "call: " + RDeparse.deparseSyntaxElement(this); + } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java index 7b425b9f8fac56ae5a24ce3e17564e472dd0e378..4bdd3dbe455a9a9eac21eb2c5ac7b3d5bf70259a 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/DispatchGeneric.java @@ -6,7 +6,7 @@ * Copyright (c) 1995, 1996, 1997 Robert Gentleman and Ross Ihaka * Copyright (c) 1995-2014, The R Core Team * Copyright (c) 2002-2008, The R Foundation - * Copyright (c) 2015, 2017, Oracle and/or its affiliates + * Copyright (c) 2015, 2018, Oracle and/or its affiliates * * All rights reserved. */ @@ -38,6 +38,7 @@ public abstract class DispatchGeneric extends RBaseNode { public abstract Object executeObject(VirtualFrame frame, REnvironment mtable, RStringVector classes, RFunction fdef, String fname); private final ConditionProfile singleStringProfile = ConditionProfile.createBinaryProfile(); + private final ConditionProfile isDeferredProfile = ConditionProfile.createBinaryProfile(); private final BranchProfile equalsMethodRequired = BranchProfile.create(); @Child private LoadMethod loadMethod = LoadMethodNodeGen.create(); @Child private ExecuteMethod executeMethod = new ExecuteMethod(); @@ -78,7 +79,7 @@ public abstract class DispatchGeneric extends RBaseNode { RFunction currentFunction = ReadVariableNode.lookupFunction(".InheritForDispatch", methodsEnv.getFrame(), true, true); method = (RFunction) RContext.getEngine().evalFunction(currentFunction, frame.materialize(), RCaller.create(frame, RASTUtils.getOriginalCall(this)), true, null, classes, fdef, mtable); } - if (method.isBuiltin() || getInheritsInternalDispatchCheckNode().execute(method)) { + if (isDeferredProfile.profile(method.isBuiltin() || getInheritsInternalDispatchCheckNode().execute(method))) { return RRuntime.DEFERRED_DEFAULT_MARKER; } method = loadMethod.executeRFunction(frame, method, fname); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java index 1803e88efbfda4b92f6f6c4b95f1097ec6477f8b..89b24089184494e10c033092b70fa966baf41598 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.java @@ -6,7 +6,7 @@ * Copyright (c) 1995, 1996, 1997 Robert Gentleman and Ross Ihaka * Copyright (c) 1995-2014, The R Core Team * Copyright (c) 2002-2008, The R Foundation - * Copyright (c) 2015, 2017, Oracle and/or its affiliates + * Copyright (c) 2015, 2018, Oracle and/or its affiliates * * All rights reserved. */ @@ -68,6 +68,7 @@ abstract class LoadMethod extends RBaseNode { @Specialization protected RFunction loadMethod(VirtualFrame frame, RFunction fdef, String fname, @Cached("createClassProfile()") ValueProfile regFrameAccessProfile, + @Cached("createClassProfile()") ValueProfile regFrameProfile, @Cached("createClassProfile()") ValueProfile methodsFrameAccessProfile) { DynamicObject attributes = fdef.getAttributes(); assert fdef.isBuiltin() || attributes != null; @@ -115,7 +116,7 @@ abstract class LoadMethod extends RBaseNode { RFunction ret; if (fdef.getAttributes() != null && moreAttributes.profile(found < fdef.getAttributes().size())) { RFunction currentFunction; - REnvironment methodsEnv = (REnvironment) methodsEnvRead.execute(frame, REnvironment.getNamespaceRegistry().getFrame(regFrameAccessProfile)); + REnvironment methodsEnv = (REnvironment) methodsEnvRead.execute(frame, regFrameProfile.profile(REnvironment.getNamespaceRegistry().getFrame(regFrameAccessProfile))); if (loadMethodFind == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); loadMethodFind = insert(ReadVariableNode.createFunctionLookup(RRuntime.R_LOAD_METHOD_NAME)); diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java index 2d17f16cb44ee8dc2a0e892eab4b31168e17540a..c54448034f70222006046e7952cb8762e17034b6 100644 --- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java @@ -97,6 +97,7 @@ public class ParserGeneration { "allow greek characters in identifiers", "allow everything but newlines in %<ident>% operators", "allow strings in :: and :::", - "use file for interactive single-line source" + "use file for interactive single-line source", + ":: and ::: do not set argument names" }; } diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g index a86d1728d7e0fd16b916f60228ab2a974b939586..daab0541ae8da9e5eb327ad196c7950d7165a873 100644 --- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g +++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g @@ -578,17 +578,17 @@ simple_expr returns [T v] | cstr=conststring { $v = $cstr.v; } | pkg=id op=(NS_GET|NS_GET_INT) n_ { SourceSection pkgSource = src($pkg.v); - args.add(RCodeBuilder.argument(pkgSource, "pkg", builder.lookup(pkgSource, $pkg.text, false))); + args.add(RCodeBuilder.argument(pkgSource, (String) null, builder.lookup(pkgSource, $pkg.text, false))); } ( compId=id { SourceSection compSource = src($compId.v); compToken = $compId.v; - args.add(RCodeBuilder.argument(compSource, "name", builder.lookup(compSource, $compId.text, false))); + args.add(RCodeBuilder.argument(compSource, (String) null, builder.lookup(compSource, $compId.text, false))); } | compString=STRING { SourceSection compSource = src($compString); compToken = $compString; - args.add(RCodeBuilder.argument(compSource, "name", builder.constant(compSource, $compString.text))); + args.add(RCodeBuilder.argument(compSource, (String) null, builder.constant(compSource, $compString.text))); } ) { $v = builder.call(src($pkg.v, compToken), operator($op), args); } | op=LPAR n_ ea=expr_or_assign n_ y=RPAR { $v = builder.call(src($op, $y), operator($op), $ea.v); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index bd968fce28658fa6a8960386888877b6d8a88099..dfdf08646513d442ee3f2cf655b81cc45fe3453d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -279,7 +279,7 @@ public final class RContext { private EnumSet<State> state = EnumSet.noneOf(State.class); - private PrimitiveMethodsInfo primitiveMethodsInfo; + @CompilationFinal private PrimitiveMethodsInfo primitiveMethodsInfo; /** Class loader for Java interop. */ private ClassLoader interopClassLoader = FastRConfig.InternalGridAwtSupport ? getClass().getClassLoader() : null; @@ -691,7 +691,6 @@ public final class RContext { s4ExtendsTable.put(key, value); } - @TruffleBoundary public PrimitiveMethodsInfo getPrimitiveMethodsInfo() { if (primitiveMethodsInfo == null) { // shared contexts do not run concurrently with their parent and re-use primitive diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java index 90cafa94aaac3d440f351bf0a8a81d448c5536b9..de16d7697a903ae5896c8b1d42abe732c7a8a338 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nodes/IdenticalVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,16 @@ */ package com.oracle.truffle.r.runtime.nodes; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.r.runtime.data.RAttributable; +import com.oracle.truffle.r.runtime.data.RPairList; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.env.REnvironment; + +/** + * Currently, this visitor is only necessary because we don't treat the body of an RFunction as a + * pairlist. It's slightly inaccurate in how it treats constants, attributes, etc. + */ public final class IdenticalVisitor extends RSyntaxArgVisitor<Boolean, RSyntaxElement> { @Override @@ -41,7 +51,65 @@ public final class IdenticalVisitor extends RSyntaxArgVisitor<Boolean, RSyntaxEl if (!(arg instanceof RSyntaxConstant)) { return false; } - return element.getValue().equals(((RSyntaxConstant) arg).getValue()); + return identicalValue(element.getValue(), ((RSyntaxConstant) arg).getValue()); + } + + private Boolean identicalValue(Object value, Object otherValue) { + if (value instanceof Number || value instanceof String) { + return value.equals(otherValue); + } + if (value instanceof RAttributable) { + if (!(otherValue instanceof RAttributable)) { + return false; + } + if (!identicalAttributes((RAttributable) value, (RAttributable) otherValue)) { + return false; + } + if (!identicalAttributes((RAttributable) otherValue, (RAttributable) value)) { + return false; + } + } + if (value instanceof RAbstractVector) { + RAbstractVector vector = (RAbstractVector) value; + if (!(otherValue instanceof RAbstractVector)) { + return false; + } + RAbstractVector otherVector = (RAbstractVector) otherValue; + if (vector.getLength() != otherVector.getLength() || vector.getRType() != otherVector.getRType()) { + return false; + } + for (int i = 0; i < vector.getLength(); i++) { + if (!identicalValue(vector.getDataAtAsObject(i), otherVector.getDataAtAsObject(i))) { + return false; + } + } + return true; + } + if (value instanceof RPairList && ((RPairList) value).isLanguage()) { + if (!(otherValue instanceof RPairList && ((RPairList) otherValue).isLanguage())) { + return false; + } + return accept(((RPairList) value).getSyntaxElement(), ((RPairList) otherValue).getSyntaxElement()); + } + if (value instanceof REnvironment) { + return value == otherValue; + } + return value == otherValue; + } + + private boolean identicalAttributes(RAttributable attributable, RAttributable otherAttributable) { + DynamicObject attributes = attributable.getAttributes(); + if (attributes != null) { + DynamicObject otherAttributes = otherAttributable.getAttributes(); + for (Object key : attributes.getShape().getKeys()) { + Object attributeValue = attributes.get(key); + Object otherAttributeValue = otherAttributes == null ? null : otherAttributes.get(key); + if ((attributeValue == null) != (otherAttributeValue == null) || !identicalValue(attributeValue, otherAttributeValue)) { + return false; + } + } + } + return true; } @Override diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 28e719055c235dd5c8ca7d1063e7c0edaeee97f6..963736621e0a6dc556d5a01aad82615d703a87df 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -29927,6 +29927,13 @@ attr(,"Rd_tag") #a <- quote(a(100)); b <- quote(a(101)); identical(a,b) [1] FALSE +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical# +#e1 <- quote(a+1); e2 <- quote(a+2); identical(e1, e2); e2[[3]] <- c(1,2,3); identical(e1, e2); e1[[3]] <- c(1,2,3); identical(e1, e2); attr(e2[[3]], 'foo') <- 'bar'; identical(e1, e2) +[1] FALSE +[1] FALSE +[1] TRUE +[1] FALSE + ##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical# #identical(pairlist(1, pairlist('foo')), pairlist(1, pairlist('bar'))) [1] FALSE diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java index d9e8d9df8e8cf413e2485220111a7a477c76ab2a..9aa604764d5d92769baab83b8004a012fb2ccdef 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java @@ -271,6 +271,7 @@ public class TestBuiltin_identical extends TestBase { assertEval("a <- quote(a(100)); b <- quote(a(100)); attr(a[[2]], 'foo') <- 'bar'; b[[2]] <- a[[2]]; identical(a,b)"); assertEval("a <- quote(a(100)); b <- quote(a(100)); attr(b[[2]], 'foo') <- 'baz'; attr(a[[2]], 'foo') <- 'bar'; identical(a,b)"); assertEval("a <- quote(a(100)); b <- quote(a(100)); attr(b[[2]], 'foo') <- 'bar'; attr(a[[2]], 'foo') <- 'bar'; identical(a,b)"); + assertEval("e1 <- quote(a+1); e2 <- quote(a+2); identical(e1, e2); e2[[3]] <- c(1,2,3); identical(e1, e2); e1[[3]] <- c(1,2,3); identical(e1, e2); attr(e2[[3]], 'foo') <- 'bar'; identical(e1, e2)"); } @Test