Skip to content

Commit

Permalink
Fix no-context-switching closure primitives
Browse files Browse the repository at this point in the history
- Ensure interrupt handler remains functional (turning it off was the wrong thing to do)
- Use normal value primitives instead
- Avoid check for interrupts when a closure is activated
  • Loading branch information
fniephaus committed May 27, 2020
1 parent 04507ea commit c47ae92
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import de.hpi.swa.trufflesqueak.exceptions.ProcessSwitch;
import de.hpi.swa.trufflesqueak.exceptions.Returns.NonLocalReturn;
import de.hpi.swa.trufflesqueak.exceptions.Returns.NonVirtualReturn;
import de.hpi.swa.trufflesqueak.model.CompiledBlockObject;
import de.hpi.swa.trufflesqueak.model.CompiledCodeObject;
import de.hpi.swa.trufflesqueak.model.ContextObject;
import de.hpi.swa.trufflesqueak.nodes.accessing.AbstractPointersObjectNodes.AbstractPointersObjectReadNode;
Expand Down Expand Up @@ -69,12 +70,13 @@ protected ExecuteContextNode(final CompiledCodeObject code, final boolean resume
}
frameInitializationNode = resume ? null : FrameStackInitializationNode.create();
/*
* Only check for interrupts if method is relatively large. Also, skip timer interrupts here
* as they trigger too often, which causes a lot of context switches and therefore
* materialization and deopts. Timer inputs are currently handled in
* Only check for interrupts if method is relatively large. Avoid check if a closure is
* activated (effectively what #primitiveClosureValueNoContextSwitch is for). Also, skip
* timer interrupts here as they trigger too often, which causes a lot of context switches
* and therefore materialization and deopts. Timer inputs are currently handled in
* primitiveRelinquishProcessor (#230) only.
*/
interruptHandlerNode = bytecodeNodes.length < MIN_NUMBER_OF_BYTECODE_FOR_INTERRUPT_CHECKS ? null : InterruptHandlerNode.createOrNull(false);
interruptHandlerNode = code instanceof CompiledBlockObject || bytecodeNodes.length < MIN_NUMBER_OF_BYTECODE_FOR_INTERRUPT_CHECKS ? null : InterruptHandlerNode.createOrNull(false);
materializeContextOnMethodExitNode = resume ? null : MaterializeContextOnMethodExitNode.create();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.util.List;

import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CachedContext;
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.NodeFactory;
Expand All @@ -17,14 +16,12 @@
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.IndirectCallNode;

import de.hpi.swa.trufflesqueak.SqueakLanguage;
import de.hpi.swa.trufflesqueak.image.SqueakImageContext;
import de.hpi.swa.trufflesqueak.model.ArrayObject;
import de.hpi.swa.trufflesqueak.model.BlockClosureObject;
import de.hpi.swa.trufflesqueak.model.CompiledBlockObject;
import de.hpi.swa.trufflesqueak.nodes.accessing.ArrayObjectNodes.ArrayObjectCopyIntoObjectArrayNode;
import de.hpi.swa.trufflesqueak.nodes.context.frame.GetContextOrMarkerNode;
import de.hpi.swa.trufflesqueak.nodes.accessing.SqueakObjectSizeNode;
import de.hpi.swa.trufflesqueak.nodes.context.frame.GetContextOrMarkerNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveFactoryHolder;
import de.hpi.swa.trufflesqueak.nodes.primitives.AbstractPrimitiveNode;
import de.hpi.swa.trufflesqueak.nodes.primitives.PrimitiveInterfaces.BinaryPrimitive;
Expand All @@ -40,7 +37,7 @@ public final class BlockClosurePrimitives extends AbstractPrimitiveFactoryHolder
protected static final int INLINE_CACHE_SIZE = 3;

@GenerateNodeFactory
@SqueakPrimitive(indices = 201)
@SqueakPrimitive(indices = {201, 221})
@ImportStatic(BlockClosurePrimitives.class)
public abstract static class PrimClosureValue0Node extends AbstractPrimitiveNode implements UnaryPrimitive {
@SuppressWarnings("unused")
Expand Down Expand Up @@ -206,7 +203,7 @@ protected static final Object doValue5Indirect(final VirtualFrame frame, final B
}

@GenerateNodeFactory
@SqueakPrimitive(indices = 206)
@SqueakPrimitive(indices = {206, 222})
@ImportStatic(BlockClosurePrimitives.class)
protected abstract static class PrimClosureValueAryNode extends AbstractPrimitiveNode implements BinaryPrimitive {
@SuppressWarnings("unused")
Expand Down Expand Up @@ -235,93 +232,6 @@ protected static final Object doValueIndirect(final VirtualFrame frame, final Bl
}
}

@GenerateNodeFactory
@SqueakPrimitive(indices = 221)
@ImportStatic(BlockClosurePrimitives.class)
public abstract static class PrimClosureValueNoContextSwitchNode extends AbstractPrimitiveNode implements UnaryPrimitive {
@SuppressWarnings("unused")
@Specialization(guards = {"closure.getCompiledBlock() == cachedBlock", "cachedBlock.getNumArgs() == 0"}, assumptions = {"cachedBlock.getCallTargetStable()"}, limit = "INLINE_CACHE_SIZE")
protected static final Object doValueDirect(final VirtualFrame frame, final BlockClosureObject closure,
@Cached("closure.getCompiledBlock()") final CompiledBlockObject cachedBlock,
@Cached final GetContextOrMarkerNode getContextOrMarkerNode,
@Cached("create(cachedBlock.getCallTarget())") final DirectCallNode directCallNode,
@CachedContext(SqueakLanguage.class) final SqueakImageContext image) {
final boolean wasActive = image.interrupt.isActive();
image.interrupt.deactivate();
try {
return directCallNode.call(FrameAccess.newClosureArgumentsTemplate(closure, cachedBlock, getContextOrMarkerNode.execute(frame), 0));
} finally {
if (wasActive) {
image.interrupt.activate();
}
}
}

@Specialization(guards = {"closure.getNumArgs() == 0"}, replaces = "doValueDirect")
protected static final Object doValueIndirect(final VirtualFrame frame, final BlockClosureObject closure,
@Cached final GetContextOrMarkerNode getContextOrMarkerNode,
@Cached final IndirectCallNode indirectCallNode,
@CachedContext(SqueakLanguage.class) final SqueakImageContext image) {
final boolean wasActive = image.interrupt.isActive();
image.interrupt.deactivate();
try {
return indirectCallNode.call(closure.getCompiledBlock().getCallTarget(), FrameAccess.newClosureArgumentsTemplate(closure, getContextOrMarkerNode.execute(frame), 0));
} finally {
if (wasActive) {
image.interrupt.activate();
}
}
}
}

@GenerateNodeFactory
@SqueakPrimitive(indices = 222)
@ImportStatic(BlockClosurePrimitives.class)
protected abstract static class PrimClosureValueAryNoContextSwitchNode extends AbstractPrimitiveNode implements BinaryPrimitive {
@SuppressWarnings("unused")
@Specialization(guards = {"closure.getCompiledBlock() == cachedBlock", "cachedBlock.getNumArgs() == sizeNode.execute(argArray)"}, //
assumptions = {"cachedBlock.getCallTargetStable()"}, limit = "INLINE_CACHE_SIZE")
protected static final Object doValueDirect(final VirtualFrame frame, final BlockClosureObject closure, final ArrayObject argArray,
@SuppressWarnings("unused") @Cached final SqueakObjectSizeNode sizeNode,
@Cached("closure.getCompiledBlock()") final CompiledBlockObject cachedBlock,
@Cached("createForFrameArguments()") final ArrayObjectCopyIntoObjectArrayNode copyIntoNode,
@Cached final GetContextOrMarkerNode getContextOrMarkerNode,
@Cached("create(cachedBlock.getCallTarget())") final DirectCallNode directCallNode,
@CachedContext(SqueakLanguage.class) final SqueakImageContext image) {
final Object[] frameArguments = FrameAccess.newClosureArgumentsTemplate(closure, getContextOrMarkerNode.execute(frame), sizeNode.execute(argArray));
copyIntoNode.execute(frameArguments, argArray);
final boolean wasActive = image.interrupt.isActive();
image.interrupt.deactivate();
try {
return directCallNode.call(frameArguments);
} finally {
if (wasActive) {
image.interrupt.activate();
}
}
}

@Specialization(guards = {"closure.getNumArgs() == sizeNode.execute(argArray)"}, replaces = "doValueDirect", limit = "1")
protected static final Object doValueIndirect(final VirtualFrame frame, final BlockClosureObject closure, final ArrayObject argArray,
@SuppressWarnings("unused") @Cached final SqueakObjectSizeNode sizeNode,
@Cached("createForFrameArguments()") final ArrayObjectCopyIntoObjectArrayNode copyIntoNode,
@Cached final GetContextOrMarkerNode getContextOrMarkerNode,
@Cached final IndirectCallNode indirectCallNode,
@CachedContext(SqueakLanguage.class) final SqueakImageContext image) {
final Object[] frameArguments = FrameAccess.newClosureArgumentsTemplate(closure, getContextOrMarkerNode.execute(frame), sizeNode.execute(argArray));
copyIntoNode.execute(frameArguments, argArray);
final boolean wasActive = image.interrupt.isActive();
image.interrupt.deactivate();
try {
return indirectCallNode.call(closure.getCompiledBlock().getCallTarget(), frameArguments);
} finally {
if (wasActive) {
image.interrupt.activate();
}
}
}
}

@Override
public List<NodeFactory<? extends AbstractPrimitiveNode>> getFactories() {
return BlockClosurePrimitivesFactory.getFactories();
Expand Down

0 comments on commit c47ae92

Please sign in to comment.