Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.enso.compiler.context

import org.enso.scala.wrapper.ScalaConversions
import org.enso.compiler.pass.analyse.FrameAnalysisMeta
import org.enso.compiler.pass.analyse.FramePointer
import org.enso.compiler.pass.analyse.FrameVariableNames
import org.enso.compiler.pass.analyse.DataflowAnalysis
Expand Down Expand Up @@ -39,7 +38,7 @@ class LocalScope(
final val aliasingGraph: () => AliasGraph,
final private val scopeProvider: () => AliasGraph.Scope,
final private val dataflowInfoProvider: () => DataflowAnalysis.Metadata,
final private val symbolsProvider: () => FrameAnalysisMeta = null,
final private val symbolsProvider: () => FrameVariableNames = null,
final val flattenToParent: Boolean = false,
private val parentFrameSlotIdxs: () => Map[AliasGraph.Id, Int] = () => Map()
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.enso.interpreter.node.scope;

import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.FrameSlotKind;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInfo;
import org.enso.interpreter.node.ExpressionNode;
import org.enso.interpreter.runtime.callable.function.Function;

/** This node represents an assignment to a variable in a given scope. */
@NodeInfo(shortName = "=", description = "Lazily assigns expression result to a variable.")
@NodeChild(value = "rhsNode", type = ExpressionNode.class)
public abstract class LazyAssignmentNode extends ExpressionNode {

private final int parentLevel;
private final int frameSlotIdx;

LazyAssignmentNode(int parentLevel, int frameSlotIdx) {
this.parentLevel = parentLevel;
this.frameSlotIdx = frameSlotIdx;
}

/**
* Creates an instance of this node.
*
* @param expression the expression being assigned
* @param frameSlotIdx the slot index to which {@code expression} is being assigned
* @return a node representing an assignment
*/
public static LazyAssignmentNode build(
ExpressionNode expression, int parentLevel, int frameSlotIdx) {
return LazyAssignmentNodeGen.create(parentLevel, frameSlotIdx, expression);
}

/**
* Writes a long value into the provided frame.
*
* @param frame the frame to write to
* @param value the value to write
* @return the unit type
*/
@Specialization(guards = "isLongOrIllegal(frame)")
protected Object writeLong(VirtualFrame frame, long value) {
var realFrame = getParentFrame(frame);
realFrame.getFrameDescriptor().setSlotKind(frameSlotIdx, FrameSlotKind.Long);
realFrame.setLong(frameSlotIdx, value);
return value;
}

/**
* Writes an object value into the provided frame.
*
* @param frame the frame to write to
* @param value the value to write
* @return the unit type
*/
@Fallback
protected Object writeObject(VirtualFrame frame, Object value) {
var realFrame = getParentFrame(frame);
realFrame.getFrameDescriptor().setSlotKind(frameSlotIdx, FrameSlotKind.Object);
realFrame.setObject(frameSlotIdx, value);

return value;
}

boolean isLongOrIllegal(VirtualFrame frame) {
var realFrame = getParentFrame(frame);
FrameSlotKind kind = realFrame.getFrameDescriptor().getSlotKind(frameSlotIdx);
return kind == FrameSlotKind.Long || kind == FrameSlotKind.Illegal;
}

private MaterializedFrame getParentFrame(Frame frame) {
return Function.ArgumentsHelper.getLocalScope(frame.getArguments());
}

private MaterializedFrame getProperFrame(Frame frame) {
MaterializedFrame currentFrame = getParentFrame(frame);
for (int i = 1; i < parentLevel; i++) {
currentFrame = getParentFrame(currentFrame);
}
return currentFrame;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ import org.enso.interpreter.node.expression.builtin.BuiltinRootNode
import org.enso.interpreter.node.expression.constant._
import org.enso.interpreter.node.expression.foreign.ForeignMethodCallNode
import org.enso.interpreter.node.expression.literal.LiteralNode
import org.enso.interpreter.node.scope.{AssignmentNode, ReadLocalVariableNode}
import org.enso.interpreter.node.scope.LazyAssignmentNode
import org.enso.interpreter.node.scope.AssignmentNode
import org.enso.interpreter.node.scope.ReadLocalVariableNode
import org.enso.interpreter.node.{
BaseNode,
ClosureRootNode,
Expand Down Expand Up @@ -255,10 +257,12 @@ private[runtime] class IrToTruffle(
DataflowAnalysis,
"Method definition missing dataflow information."
)
def frameInfo() = conversion.unsafeGetMetadata(
FramePointerAnalysis,
"Method definition missing frame information."
)
def frameInfo() = conversion
.unsafeGetMetadata(
FramePointerAnalysis,
"Method definition missing frame information."
)
.asInstanceOf[FrameVariableNames]

val toType =
conversion.methodReference.typePointer match {
Expand Down Expand Up @@ -335,10 +339,12 @@ private[runtime] class IrToTruffle(
DataflowAnalysis,
"Method definition missing dataflow information."
)
def frameInfo() = method.unsafeGetMetadata(
FramePointerAnalysis,
"Method definition missing frame information."
)
def frameInfo() = method
.unsafeGetMetadata(
FramePointerAnalysis,
"Method definition missing frame information."
)
.asInstanceOf[FrameVariableNames]

@tailrec
def getContext(tp: Expression): Option[String] = tp match {
Expand Down Expand Up @@ -447,10 +453,12 @@ private[runtime] class IrToTruffle(
DataflowAnalysis,
"No dataflow information associated with an atom."
)
def frameInfo() = atomDefn.unsafeGetMetadata(
FramePointerAnalysis,
"Method definition missing frame information."
)
def frameInfo() = atomDefn
.unsafeGetMetadata(
FramePointerAnalysis,
"Method definition missing frame information."
)
.asInstanceOf[FrameVariableNames]
val localScope = new LocalScope(
None,
() => scopeInfo().graph,
Expand Down Expand Up @@ -676,10 +684,12 @@ private[runtime] class IrToTruffle(
scopeElements.init
.mkString(Constants.SCOPE_SEPARATOR)
)
def frameInfo() = annotation.unsafeGetMetadata(
FramePointerAnalysis,
"Method definition missing frame information."
)
def frameInfo() = annotation
.unsafeGetMetadata(
FramePointerAnalysis,
"Method definition missing frame information."
)
.asInstanceOf[FrameVariableNames]
val expressionProcessor = new ExpressionProcessor(
scopeName,
() => scopeInfo().graph,
Expand Down Expand Up @@ -1182,7 +1192,7 @@ private[runtime] class IrToTruffle(
scope: () => AliasScope,
dataflowInfo: () => DataflowAnalysis.Metadata,
initialName: String,
frameInfo: () => FramePointerAnalysis.Metadata = null
frameInfo: () => FrameVariableNames = null
) = {
this(
new LocalScope(None, graph, scope, dataflowInfo, frameInfo),
Expand Down Expand Up @@ -1220,20 +1230,21 @@ private[runtime] class IrToTruffle(
def run(
ir: Expression,
subjectToInstrumentation: Boolean
): RuntimeExpression = run(ir, false, subjectToInstrumentation)
): RuntimeExpression = run(ir, -1, subjectToInstrumentation)

private def run(
ir: Expression,
binding: Boolean,
bindingToIndex: Int,
subjectToInstrumentation: Boolean
): RuntimeExpression = {
var runtimeExpression = ir match {
case block: Expression.Block => processBlock(block)
case block: Expression.Block => processBlock(block, bindingToIndex)
case literal: Literal => processLiteral(literal)
case app: Application =>
processApplication(app, subjectToInstrumentation)
case name: Name => processName(name)
case function: Function => processFunction(function, binding)
case name: Name => processName(name)
case function: Function =>
processFunction(function, bindingToIndex >= 0)
case binding: Expression.Binding => processBinding(binding)
case caseExpr: Case =>
processCase(caseExpr, subjectToInstrumentation)
Expand All @@ -1245,7 +1256,7 @@ private[runtime] class IrToTruffle(
asc.signature
)
if (checkNode != null) {
val body = run(asc.typed, binding, subjectToInstrumentation)
val body = run(asc.typed, bindingToIndex, subjectToInstrumentation)
TypeCheckValueNode.wrap(body, checkNode)
} else {
processType(asc)
Expand Down Expand Up @@ -1304,8 +1315,11 @@ private[runtime] class IrToTruffle(
* @param block the block to generate code for
* @return the truffle nodes corresponding to `block`
*/
private def processBlock(block: Expression.Block): RuntimeExpression = {
if (block.suspended) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • block.suspended check

private def processBlock(
block: Expression.Block,
bindingToIndex: Int
): RuntimeExpression = {
if (block.suspended && bindingToIndex >= 0) {
val scopeInfo = childScopeInfo("block", block)
def frameInfo() = block
.unsafeGetMetadata(
Expand All @@ -1322,13 +1336,15 @@ private[runtime] class IrToTruffle(
)
val childScope = childFactory.scope

val blockNode = childFactory.processBlock(block.copy(suspended = false))
val blockNode = childFactory.processBlock(block, -1)
val blockNodeWithAssignment =
LazyAssignmentNode.build(blockNode, 1, bindingToIndex)

val defaultRootNode = ClosureRootNode.build(
language,
childScope,
scopeBuilder.asModuleScope(),
blockNode,
blockNodeWithAssignment,
makeSource(scopeBuilder.getModule),
makeLocation(block.location),
currentVarName,
Expand Down Expand Up @@ -1843,8 +1859,9 @@ private[runtime] class IrToTruffle(

currentVarName = binding.name.name
val slotIdx = fp.frameSlotIdx()
val rhs = this.run(binding.expression, slotIdx, true)
setLocation(
AssignmentNode.build(this.run(binding.expression, true, true), slotIdx),
AssignmentNode.build(rhs, slotIdx),
binding.location
)
}
Expand Down Expand Up @@ -2209,7 +2226,7 @@ private[runtime] class IrToTruffle(
argSlotIdxs
)
case _ =>
ExpressionProcessor.this.run(body, false, subjectToInstrumentation)
ExpressionProcessor.this.run(body, -1, subjectToInstrumentation)
}

if (typeCheck == null) {
Expand Down
4 changes: 2 additions & 2 deletions test/Base_Tests/src/Data/Vector_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,9 @@ type_spec suite_builder name alter = suite_builder.group name group_builder->
Vector.new 100 (ix -> ix + 1) . fold 0 (+) . should_equal 5050

r = Ref.new 0
next =
next _ =
r.put r.get+1
const = Vector.new 4 _->next
const = Vector.new 4 next
const.should_equal [0, 1, 2, 3]

group_builder.specify "should allow vector creation with a constant constructor" <|
Expand Down
2 changes: 1 addition & 1 deletion test/Base_Tests/src/Runtime/Lazy_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ add_specs suite_builder = suite_builder.group "Lazy" group_builder->
compute . should_equal "Value"
compute . should_equal "Value"

ref.get . should_equal 3
ref.get . should_equal 1

group_builder.specify "should compute the result only once, even if copied" <|
ref = Ref.new 0
Expand Down
Loading