Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix lookup issues caused by incorrect outer object reads #50

Merged
merged 1 commit into from
Oct 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion core-lib/Actors.som
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ class Actors usingVmMirror: vmMirror usingKernel: kernel = Value (
)
)


public createPromisePair = (
^ vmMirror actorsCreatePromisePair: nil.
)
Expand Down
14 changes: 14 additions & 0 deletions core-lib/TestSuite/ActorTests.som
Original file line number Diff line number Diff line change
Expand Up @@ -434,4 +434,18 @@ class ActorTests usingPlatform: platform testFramework: minitest = Value (
) : (
TEST_CONTEXT = ()
)

public class RegressionTests = AsyncTestContext ()(
(* This test is to identify issues in the OuterObjectRead node.
It did not handle properly the different cases of outer scope
semantics, depending on the point in the inheritance tree, i.e.,
starting lexical scope. *)
public testFarReferenceLookupInKernel = (
| ref |
ref := (actors createActorFromValue: DeepChain).
assert: ref asString println equals: 'instance of FarReference'.
)
) : (
TEST_CONTEXT = ()
)
)
127 changes: 96 additions & 31 deletions src/som/interpreter/nodes/OuterObjectRead.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package som.interpreter.nodes;

import java.math.BigInteger;

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.instrumentation.StandardTags.StatementTag;
Expand All @@ -15,18 +18,32 @@
import som.interpreter.objectstorage.ClassFactory;
import som.primitives.actors.ActorClasses;
import som.vm.constants.KernelObj;
import som.vmobjects.SArray;
import som.vmobjects.SBlock;
import som.vmobjects.SClass;
import som.vmobjects.SObjectWithClass;
import som.vmobjects.SSymbol;


@ImportStatic(ActorClasses.class)
@NodeChild(value = "receiver", type = ExpressionNode.class)
public abstract class OuterObjectRead
extends ExprWithTagsNode implements ISpecialSend {

protected static final int INLINE_CACHE_SIZE = VmSettings.DYNAMIC_METRICS ? 100 : 3;

/**
* The level of lexical context. A level of 0 is self, level of 1 is the first
* outer lexical context, so, the directly enclosing object.
*/
protected final int contextLevel;
private final MixinDefinitionId mixinId;

/**
* Mixin where the lookup starts, can be a mixin different from the `self`.
* Thus, it can be one in the inheritance chain, for instance.
*/
protected final MixinDefinitionId mixinId;

private final MixinDefinitionId enclosingMixinId;

private final ValueProfile enclosingObj;
Expand Down Expand Up @@ -54,6 +71,8 @@ public MixinDefinitionId getEnclosingMixinId() {
@Override
public boolean isSuperSend() { return false; }

public abstract Object executeEvaluated(Object receiver);

protected final SClass getEnclosingClass(final SObjectWithClass rcvr) {
SClass lexicalClass = rcvr.getSOMClass().getClassCorrespondingTo(mixinId);
assert lexicalClass != null;
Expand All @@ -76,7 +95,7 @@ public final Object doForOuterIsDirectClass(final SObjectWithClass receiver) {
public final Object doForFurtherOuter(final SObjectWithClass receiver,
@Cached("receiver.getSOMClass()") final SClass rcvrClass,
@Cached("getEnclosingClass(receiver)") final SClass lexicalClass) {
return getEnclosingObject(receiver, lexicalClass);
return getEnclosingObject(lexicalClass);
}

protected final int getIdx(final SObjectWithClass rcvr) {
Expand All @@ -98,53 +117,99 @@ public final Object fixedLookup(final SObjectWithClass receiver,
@Cached("getIdx(receiver)") final int superclassIdx,
@Cached("getEnclosingClass(receiver).getInstanceFactory()") final ClassFactory factory) {
assert factory != null;
return getEnclosingObject(receiver, getEnclosingClassWithPotentialFailure(receiver, superclassIdx));
return getEnclosingObject(getEnclosingClassWithPotentialFailure(receiver, superclassIdx));
}

@Specialization(guards = {"contextLevel != 0"}, contains = "fixedLookup")
public final Object fallback(final SObjectWithClass receiver) {
return getEnclosingObject(receiver, getEnclosingClass(receiver));
return getEnclosingObject(getEnclosingClass(receiver));
}

public abstract Object executeEvaluated(Object receiver);
@ExplodeLoop
private Object getEnclosingObject(final SClass lexicalClass) {
int ctxLevel = contextLevel - 1; // 0 is already covered with specialization
SObjectWithClass enclosing = lexicalClass.getEnclosingObject();

protected static final boolean notSObjectWithClass(final Object receiver) {
return !(receiver instanceof SObjectWithClass) && !(receiver instanceof SFarReference);
while (ctxLevel > 0) {
ctxLevel--;
enclosing = enclosing.getSOMClass().getEnclosingObject();
}
return enclosingObj.profile(enclosing);
}

protected static final boolean notSObjectWithClassClass(final Class<?> rcvrClass) {
return !rcvrClass.isAssignableFrom(SObjectWithClass.class) && !rcvrClass.isAssignableFrom(SFarReference.class);
/**
* Need to get the outer scope for FarReference, while in the Actors module.
*/
@Specialization(guards = {"mixinId == FarRefId", "contextLevel == 1"})
public Object doFarReferenceInActorModuleScope(final SFarReference receiver) {
assert ActorClasses.ActorModule != null;
return ActorClasses.ActorModule;
}

@Specialization(guards = {"receiver.getClass() == rcvrClass",
"notSObjectWithClassClass(rcvrClass)"})
public Object doObject(final Object receiver, @Cached("receiver.getClass()") final Class<?> rcvrClass) {
/**
* Need to get the outer scope for FarReference, but it is not the actors module.
* Since there are only super classes in Kernel, we know it is going to be the Kernel.
*/
@Specialization(guards = {"mixinId != FarRefId", "contextLevel == 1"})
public Object doFarReferenceInKernelModuleScope(final SFarReference receiver) {
return KernelObj.kernel;
}

@Specialization(guards = "notSObjectWithClass(receiver)")
public Object doObject(final Object receiver) {
return KernelObj.kernel;
/**
* Need to get outer scope of contextLevel == 0, which is self.
*/
@Specialization(guards = {"contextLevel == 0"})
public SFarReference doFarReferenceDirect(final SFarReference receiver) {
return receiver;
}

@Specialization
public Object doFarReference(final SFarReference receiver) {
assert ActorClasses.ActorModule != null;
return ActorClasses.ActorModule;
}
@Specialization(guards = "contextLevel != 0")
public Object doBool(final boolean receiver) { return KernelObj.kernel; }

@ExplodeLoop
private Object getEnclosingObject(final SObjectWithClass receiver,
final SClass lexicalClass) {
int ctxLevel = contextLevel - 1; // 0 is already covered with specialization
SObjectWithClass enclosing = lexicalClass.getEnclosingObject();
@Specialization(guards = "contextLevel != 0")
public Object doLong(final long receiver) { return KernelObj.kernel; }

while (ctxLevel > 0) {
ctxLevel--;
enclosing = enclosing.getSOMClass().getEnclosingObject();
}
return enclosingObj.profile(enclosing);
}
@Specialization(guards = "contextLevel != 0")
public Object doString(final String receiver) { return KernelObj.kernel; }

@Specialization(guards = "contextLevel != 0")
public Object doBigInteger(final BigInteger receiver) { return KernelObj.kernel; }

@Specialization(guards = "contextLevel != 0")
public Object doDouble(final double receiver) { return KernelObj.kernel; }

@Specialization(guards = "contextLevel != 0")
public Object doSSymbol(final SSymbol receiver) { return KernelObj.kernel; }

@Specialization(guards = "contextLevel != 0")
public Object doSArray(final SArray receiver) { return KernelObj.kernel; }

@Specialization(guards = "contextLevel != 0")
public Object doSBlock(final SBlock receiver) { return KernelObj.kernel; }

@Specialization(guards = "contextLevel == 0")
public boolean doBoolDirect(final boolean receiver) { return receiver; }

@Specialization(guards = "contextLevel == 0")
public long doLongDirect(final long receiver) { return receiver; }

@Specialization(guards = "contextLevel == 0")
public String doStringDirect(final String receiver) { return receiver; }

@Specialization(guards = "contextLevel == 0")
public BigInteger doBigIntegerDirect(final BigInteger receiver) { return receiver; }

@Specialization(guards = "contextLevel == 0")
public Double doDoubleDirect(final double receiver) { return receiver; }

@Specialization(guards = "contextLevel == 0")
public SSymbol doSSymbolDirect(final SSymbol receiver) { return receiver; }

@Specialization(guards = "contextLevel == 0")
public SArray doSArrayDirect(final SArray receiver) { return receiver; }

@Specialization(guards = "contextLevel == 0")
public SBlock doSBlockDirect(final SBlock receiver) { return receiver; }

@Override
protected boolean isTaggedWith(final Class<?> tag) {
Expand Down
8 changes: 7 additions & 1 deletion src/som/primitives/actors/ActorClasses.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;

import som.compiler.MixinBuilder.MixinDefinitionId;
import som.interpreter.actors.SFarReference;
import som.interpreter.actors.SPromise;
import som.interpreter.actors.SPromise.SResolver;
Expand All @@ -15,6 +16,10 @@


public final class ActorClasses {

@CompilationFinal public static SImmutableObject ActorModule;
@CompilationFinal public static MixinDefinitionId FarRefId;

@GenerateNodeFactory
@Primitive(primitive = "actorsFarReferenceClass:")
public abstract static class SetFarReferenceClassPrim extends UnaryExpressionNode {
Expand All @@ -23,6 +28,7 @@ public abstract static class SetFarReferenceClassPrim extends UnaryExpressionNod
@Specialization
public final SClass setClass(final SClass value) {
SFarReference.setSOMClass(value);
FarRefId = value.getMixinDefinition().getMixinId();
return value;
}
}
Expand Down Expand Up @@ -63,7 +69,7 @@ public final SClass setClass(final SClass value) {
}
}

@CompilationFinal public static SImmutableObject ActorModule;


@GenerateNodeFactory
@Primitive(primitive = "actorsModule:")
Expand Down