Skip to content

Commit

Permalink
[GR-17457] Remove loop in special variable lookup
Browse files Browse the repository at this point in the history
PullRequest: truffleruby/3949
  • Loading branch information
horakivo authored and eregon committed Aug 18, 2023
2 parents f954b46 + be521f1 commit c3400a8
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 108 deletions.
7 changes: 4 additions & 3 deletions src/main/java/org/truffleruby/RubyLanguage.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
import org.truffleruby.language.objects.classvariables.ClassVariableStorage;
import org.truffleruby.language.threadlocal.SpecialVariableStorage;
import org.truffleruby.options.LanguageOptions;
import org.truffleruby.parser.BlockDescriptorInfo;
import org.truffleruby.parser.ParserContext;
import org.truffleruby.parser.ParsingParameters;
import org.truffleruby.parser.RubySource;
Expand Down Expand Up @@ -189,8 +190,8 @@ public final class RubyLanguage extends TruffleLanguage<RubyContext> {
public static final TruffleLogger LOGGER = TruffleLogger.getLogger(TruffleRuby.LANGUAGE_ID);

/** This is a truly empty frame descriptor and should only by dummy root nodes which require no variables. Any other
* root nodes should should use
* {@link TranslatorEnvironment#newFrameDescriptorBuilder(org.truffleruby.parser.ParentFrameDescriptor, boolean)}. */
* root nodes should should use either {@link TranslatorEnvironment#newFrameDescriptorBuilderForMethod()} or
* {@link TranslatorEnvironment#newFrameDescriptorBuilderForBlock(BlockDescriptorInfo)}. */
public static final FrameDescriptor EMPTY_FRAME_DESCRIPTOR = new FrameDescriptor(nil);

private RubyThread getOrCreateForeignThread(RubyContext context, Thread thread) {
Expand Down Expand Up @@ -336,7 +337,7 @@ private RubyThread getOrCreateForeignThread(RubyContext context, Thread thread)
* special variable storage. This frame descriptor should be used for those frames to provide a constant frame
* descriptor in those cases. */
public final FrameDescriptor emptyDeclarationDescriptor = TranslatorEnvironment
.newFrameDescriptorBuilder(null, true).build();
.newFrameDescriptorBuilderForMethod().build();

public MaterializedFrame createEmptyDeclarationFrame(Object[] packedArgs, SpecialVariableStorage variables) {
// createVirtualFrame().materialize() compiles better if this is in PE code
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/org/truffleruby/core/binding/BindingNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
import com.oracle.truffle.api.source.SourceSection;
import org.truffleruby.language.locals.WriteFrameSlotNode;
import org.truffleruby.language.locals.WriteFrameSlotNodeGen;
import org.truffleruby.parser.ParentFrameDescriptor;
import org.truffleruby.parser.BlockDescriptorInfo;
import org.truffleruby.parser.TranslatorEnvironment;

@CoreModule(value = "Binding", isClass = true)
Expand All @@ -80,8 +80,8 @@ public static RubyBinding createBinding(RubyContext context, RubyLanguage langua
@TruffleBoundary
public static FrameDescriptor newFrameDescriptor(RubyBinding binding) {
FrameDescriptor parentDescriptor = binding.getFrame().getFrameDescriptor();
var ref = new ParentFrameDescriptor(parentDescriptor);
return TranslatorEnvironment.newFrameDescriptorBuilder(ref, false).build();
var ref = new BlockDescriptorInfo(parentDescriptor);
return TranslatorEnvironment.newFrameDescriptorBuilderForBlock(ref).build();
}

static final int NEW_VAR_INDEX = 1;
Expand All @@ -90,8 +90,8 @@ public static FrameDescriptor newFrameDescriptor(RubyBinding binding) {
public static FrameDescriptor newFrameDescriptor(FrameDescriptor parentDescriptor, String name) {
assert name != null && !name.isEmpty();

var ref = new ParentFrameDescriptor(parentDescriptor);
var builder = TranslatorEnvironment.newFrameDescriptorBuilder(ref, false);
var ref = new BlockDescriptorInfo(parentDescriptor);
var builder = TranslatorEnvironment.newFrameDescriptorBuilderForBlock(ref);
int index = builder.addSlot(FrameSlotKind.Illegal, name, null);
if (index != NEW_VAR_INDEX) {
throw CompilerDirectives.shouldNotReachHere("new binding variable not at index 1");
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/truffleruby/debug/DebugHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import org.truffleruby.language.arguments.RubyArguments;
import org.truffleruby.language.loader.CodeLoader;
import org.truffleruby.language.methods.DeclarationContext;
import org.truffleruby.parser.ParentFrameDescriptor;
import org.truffleruby.parser.BlockDescriptorInfo;
import org.truffleruby.parser.ParserContext;
import org.truffleruby.parser.RubySource;
import org.truffleruby.parser.TranslatorEnvironment;
Expand Down Expand Up @@ -67,8 +67,8 @@ public static Object eval(RubyContext context, String code, Object... arguments)
RubyNode.EMPTY_ARGUMENTS);


var builder = TranslatorEnvironment.newFrameDescriptorBuilder(new ParentFrameDescriptor(currentFrameDescriptor),
false);
var builder = TranslatorEnvironment
.newFrameDescriptorBuilderForBlock(new BlockDescriptorInfo(currentFrameDescriptor));

for (int i = 0; i < nArgs; i++) {
final Object identifier = arguments[i * 2];
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/truffleruby/language/RubyRootNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.truffleruby.annotations.Split;
import org.truffleruby.parser.ParentFrameDescriptor;
import org.truffleruby.parser.BlockDescriptorInfo;

import java.util.ArrayList;
import java.util.IdentityHashMap;
Expand Down Expand Up @@ -83,8 +83,8 @@ public Object execute(VirtualFrame frame) {
@Override
public FrameDescriptor getParentFrameDescriptor() {
var info = getFrameDescriptor().getInfo();
if (info instanceof ParentFrameDescriptor) {
return ((ParentFrameDescriptor) info).getDescriptor();
if (info instanceof BlockDescriptorInfo) {
return ((BlockDescriptorInfo) info).getParentDescriptor();
} else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import org.truffleruby.core.kernel.TruffleKernelNodes.GetSpecialVariableStorage;
import org.truffleruby.language.arguments.ReadCallerVariablesNode;

import org.truffleruby.language.locals.FindDeclarationVariableNodes;
import org.truffleruby.language.threadlocal.SpecialVariableStorage;
import org.truffleruby.parser.BlockDescriptorInfo;

/** Some Ruby methods need access to the caller special variables: see usages of {@link ReadCallerVariablesNode}. This
* is used for methods which need to access the last regexp MatchData or the last IO line.
Expand Down Expand Up @@ -45,10 +45,12 @@ protected Assumption getSpecialVariableAssumption(Frame frame) {
return Assumption.ALWAYS_VALID;
}

var outerFrameDescriptor = FindDeclarationVariableNodes.getOuterFrameDescriptor(frame.getFrameDescriptor());
var descriptor = frame.getFrameDescriptor();

if (SpecialVariableStorage.hasSpecialVariableAssumption(outerFrameDescriptor)) {
return SpecialVariableStorage.getAssumption(outerFrameDescriptor);
if (SpecialVariableStorage.hasSpecialVariableAssumption(descriptor)) {
return SpecialVariableStorage.getAssumption(descriptor);
} else if (descriptor.getInfo() instanceof BlockDescriptorInfo blockDescriptorInfo) {
return blockDescriptorInfo.getSpecialVariableAssumption();
} else {
return Assumption.ALWAYS_VALID;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import com.oracle.truffle.api.dsl.ReportPolymorphism;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.FrameDescriptor;
import org.truffleruby.parser.ParentFrameDescriptor;

public abstract class FindDeclarationVariableNodes {
public static final class FrameSlotAndDepth {
Expand All @@ -50,13 +49,6 @@ public static MaterializedFrame getOuterDeclarationFrame(MaterializedFrame topFr
return frame;
}

public static FrameDescriptor getOuterFrameDescriptor(FrameDescriptor descriptor) {
while (descriptor.getInfo() instanceof ParentFrameDescriptor nextDescriptor) {
descriptor = nextDescriptor.getDescriptor();
}
return descriptor;
}

private static int findSlot(FrameDescriptor descriptor, String name) {
assert descriptor.getNumberOfAuxiliarySlots() == 0;
int slots = descriptor.getNumberOfSlots();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import org.truffleruby.parser.ParentFrameDescriptor;
import org.truffleruby.parser.BlockDescriptorInfo;

public final class ReadDeclarationVariableNode extends ReadLocalNode {

Expand Down Expand Up @@ -57,7 +57,7 @@ public WriteLocalNode makeWriteNode(RubyNode rhs) {

@Override
protected String getVariableName() {
var descriptor = ParentFrameDescriptor.getDeclarationFrameDescriptor(
var descriptor = BlockDescriptorInfo.getDeclarationFrameDescriptor(
getRootNode().getFrameDescriptor(), frameDepth);
return descriptor.getSlotName(frameSlot).toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import org.truffleruby.parser.ParentFrameDescriptor;
import org.truffleruby.parser.BlockDescriptorInfo;

public final class WriteDeclarationVariableNode extends WriteLocalNode {

Expand Down Expand Up @@ -60,7 +60,7 @@ public AssignableNode cloneUninitializedAssignable() {

@Override
protected String getVariableName() {
var descriptor = ParentFrameDescriptor.getDeclarationFrameDescriptor(
var descriptor = BlockDescriptorInfo.getDeclarationFrameDescriptor(
getRootNode().getFrameDescriptor(), frameDepth);
return descriptor.getSlotName(frameSlot).toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,13 @@ public static Assumption getAssumption(FrameDescriptor descriptor) {
return (Assumption) descriptor.getInfo();
}

public static boolean isSpecialVariableAssumption(Assumption assumption) {
return assumption.getName() == ASSUMPTION_NAME;
}

public static boolean hasSpecialVariableAssumption(FrameDescriptor descriptor) {
var info = descriptor.getInfo();
return info instanceof Assumption assumption && assumption.getName() == ASSUMPTION_NAME;
return info instanceof Assumption assumption && isSpecialVariableAssumption(assumption);
}

public static boolean hasSpecialVariableStorageSlot(Frame frame) {
Expand All @@ -65,7 +69,7 @@ private static boolean hasSpecialVariableStorageSlot(FrameDescriptor descriptor)
assert SLOT_INDEX < descriptor.getNumberOfSlots();
assert descriptor.getSlotName(SLOT_INDEX) == SLOT_NAME;
Assumption assumption = (Assumption) descriptor.getInfo();
return assumption.getName() == ASSUMPTION_NAME;
return isSpecialVariableAssumption(assumption);
}

/** $~ */
Expand Down
67 changes: 67 additions & 0 deletions src/main/java/org/truffleruby/parser/BlockDescriptorInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 2.0, or
* GNU General Public License version 2, or
* GNU Lesser General Public License version 2.1.
*/
package org.truffleruby.parser;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import org.truffleruby.language.threadlocal.SpecialVariableStorage;

/** This is the {@link FrameDescriptor#getInfo() descriptor info} for blocks. The descriptor info for methods is an
* {@link SpecialVariableStorage#getAssumption(FrameDescriptor) Assumption}. */
public final class BlockDescriptorInfo {

@ExplodeLoop
public static FrameDescriptor getDeclarationFrameDescriptor(FrameDescriptor topDescriptor, int depth) {
assert depth > 0;
FrameDescriptor descriptor = topDescriptor;
for (int i = 0; i < depth; i++) {
descriptor = ((BlockDescriptorInfo) descriptor.getInfo()).getParentDescriptor();
}
return descriptor;
}

@CompilationFinal private FrameDescriptor parentDescriptor;
private final Assumption specialVariableAssumption;

public BlockDescriptorInfo(Assumption specialVariableAssumption) {
assert SpecialVariableStorage.isSpecialVariableAssumption(specialVariableAssumption);
this.specialVariableAssumption = specialVariableAssumption;
}

public BlockDescriptorInfo(FrameDescriptor parentDescriptor) {
this.parentDescriptor = parentDescriptor;
this.specialVariableAssumption = getSpecialVariableAssumptionFromDescriptor(parentDescriptor);
}

private Assumption getSpecialVariableAssumptionFromDescriptor(FrameDescriptor descriptor) {
if (descriptor.getInfo() instanceof BlockDescriptorInfo blockDescriptorInfo) {
return blockDescriptorInfo.getSpecialVariableAssumption();
} else {
return SpecialVariableStorage.getAssumption(descriptor);
}
}

public FrameDescriptor getParentDescriptor() {
assert parentDescriptor != null;
return parentDescriptor;
}

void setParentDescriptor(FrameDescriptor parentDescriptor) {
assert this.parentDescriptor == null;
this.parentDescriptor = parentDescriptor;
}

public Assumption getSpecialVariableAssumption() {
assert specialVariableAssumption != null;
return specialVariableAssumption;
}
}
47 changes: 0 additions & 47 deletions src/main/java/org/truffleruby/parser/ParentFrameDescriptor.java

This file was deleted.

Loading

0 comments on commit c3400a8

Please sign in to comment.