Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2d33ba628617
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 51116141af9a
Choose a head ref
  • 8 commits
  • 23 files changed
  • 1 contributor

Commits on Dec 4, 2016

  1. Copy the full SHA
    0b13ee0 View commit details
  2. [Truffle] Track where dynamic constant lookup is necessary.

    * Such as in [Object.new, Object.new].each { |obj| class << obj; <HERE>; end }
    * Optionally log such usages as they can affect performance.
    eregon committed Dec 4, 2016
    Copy the full SHA
    af274c3 View commit details
  3. [Truffle] Track the dynamic LexicalScope in InternalMethod.

    * Make RunModuleDefinitionNode Instrumentable instead of ModuleBodyDefinitionNode.
    eregon committed Dec 4, 2016
    Copy the full SHA
    60effd1 View commit details
  4. Copy the full SHA
    229232b View commit details
  5. Copy the full SHA
    1c5ef12 View commit details
  6. [Truffle] Implement dynamic constant lookup when inside class << expr…

    …ession.
    
    * Use the LexicalScope from the InternalMethod instead of the static one.
    * Assert that the static scope is not used when in dynamic mode.
    eregon committed Dec 4, 2016
    Copy the full SHA
    8cd1994 View commit details
  7. Copy the full SHA
    95f9e06 View commit details
  8. [Truffle] Restore old behavior in DeclarationContext#getModuleToDefin…

    …eMethods.
    
    * It seems to break ecosystem tests otherwise.
    eregon committed Dec 4, 2016
    Copy the full SHA
    5111614 View commit details
Showing with 422 additions and 107 deletions.
  1. +0 −3 spec/truffle/tags/language/constants_tags.txt
  2. +1 −0 tool/truffle/options.yml
  3. +3 −2 truffle/src/main/java/org/jruby/truffle/builtins/CoreMethodNodeManager.java
  4. +2 −1 truffle/src/main/java/org/jruby/truffle/core/kernel/KernelNodes.java
  5. +3 −2 truffle/src/main/java/org/jruby/truffle/core/module/ModuleNodes.java
  6. +1 −1 truffle/src/main/java/org/jruby/truffle/core/symbol/SymbolNodes.java
  7. +2 −2 truffle/src/main/java/org/jruby/truffle/language/LazyRubyRootNode.java
  8. +105 −0 truffle/src/main/java/org/jruby/truffle/language/constants/LookupConstantWithDynamicScopeNode.java
  9. +1 −1 truffle/src/main/java/org/jruby/truffle/language/constants/LookupConstantWithLexicalScopeNode.java
  10. +69 −0 truffle/src/main/java/org/jruby/truffle/language/constants/ReadConstantWithDynamicScopeNode.java
  11. +10 −0 truffle/src/main/java/org/jruby/truffle/language/loader/CodeLoader.java
  12. +24 −20 truffle/src/main/java/org/jruby/truffle/language/methods/InternalMethod.java
  13. +5 −2 truffle/src/main/java/org/jruby/truffle/language/methods/MethodDefinitionNode.java
  14. +40 −23 truffle/src/main/java/org/jruby/truffle/language/methods/ModuleBodyDefinitionNode.java
  15. +1 −0 truffle/src/main/java/org/jruby/truffle/language/methods/SharedMethodInfo.java
  16. +29 −0 truffle/src/main/java/org/jruby/truffle/language/objects/DynamicLexicalScopeNode.java
  17. +2 −10 truffle/src/main/java/org/jruby/truffle/language/objects/RunModuleDefinitionNode.java
  18. +2 −0 truffle/src/main/java/org/jruby/truffle/options/Options.java
  19. +3 −0 truffle/src/main/java/org/jruby/truffle/options/OptionsCatalog.java
  20. +68 −29 truffle/src/main/java/org/jruby/truffle/parser/BodyTranslator.java
  21. +20 −2 truffle/src/main/java/org/jruby/truffle/parser/ParseEnvironment.java
  22. +6 −4 truffle/src/main/java/org/jruby/truffle/parser/TranslatorDriver.java
  23. +25 −5 truffle/src/main/java/org/jruby/truffle/parser/TranslatorEnvironment.java
3 changes: 0 additions & 3 deletions spec/truffle/tags/language/constants_tags.txt

This file was deleted.

1 change: 1 addition & 0 deletions tool/truffle/options.yml
Original file line number Diff line number Diff line change
@@ -105,3 +105,4 @@ SHARED_OBJECTS_FORCE: [shared.objects.force, boolean, false, Force sharing of ob
SHARED_OBJECTS_SHARE_ALL: [shared.objects.share_all, boolean, false, Consider all objects as shared]

CEXTS_LOG_LOAD: [cexts.log.load, boolean, false, Log loading of cexts]
LOG_DYNAMIC_CONSTANT_LOOKUP: [constant.dynamic_lookup.log, boolean, false, Log source code positions where dynamic constant lookup is performed]
Original file line number Diff line number Diff line change
@@ -160,18 +160,19 @@ private static void addMethod(RubyContext context, DynamicObject module, SharedM
if (ModuleOperations.isMethodPrivateFromName(name)) {
visibility = Visibility.PRIVATE;
}
final InternalMethod method = new InternalMethod(context, sharedMethodInfo, name, module, visibility, callTarget);
final InternalMethod method = new InternalMethod(context, sharedMethodInfo, sharedMethodInfo.getLexicalScope(), name, module, visibility, callTarget);

Layouts.MODULE.getFields(module).addMethod(context, null, method);
}
}

private static SharedMethodInfo makeSharedMethodInfo(RubyContext context, DynamicObject module, MethodDetails methodDetails) {
final CoreMethod method = methodDetails.getMethodAnnotation();
final LexicalScope lexicalScope = new LexicalScope(context.getRootLexicalScope(), module);

return new SharedMethodInfo(
context.getCoreLibrary().getSourceSection(),
LexicalScope.NONE,
lexicalScope,
new Arity(method.required(), method.optional(), method.rest()),
module,
methodDetails.getPrimaryName(),
Original file line number Diff line number Diff line change
@@ -626,6 +626,7 @@ public Object evalNoBindingCached(
final InternalMethod method = new InternalMethod(
getContext(),
cachedRootNode.getRootNode().getSharedMethodInfo(),
RubyArguments.getMethod(parentFrame).getLexicalScope(),
cachedRootNode.getRootNode().getSharedMethodInfo().getName(),
RubyArguments.getMethod(parentFrame).getDeclaringModule(),
Visibility.PUBLIC,
@@ -1267,7 +1268,7 @@ private InternalMethod createMissingMethod(Object self, DynamicObject name, Stri
final CallTarget newCallTarget = Truffle.getRuntime().createCallTarget(newRootNode);

final DynamicObject module = coreLibrary().getMetaClass(self);
return new InternalMethod(getContext(), info, normalizedName, module, Visibility.PUBLIC, newCallTarget);
return new InternalMethod(getContext(), info, methodMissing.getLexicalScope(), normalizedName, module, Visibility.PUBLIC, newCallTarget);
}

private static class CallMethodMissingWithStaticName extends RubyNode {
Original file line number Diff line number Diff line change
@@ -383,9 +383,10 @@ private void createAccesor(DynamicObject module, String name) {

final RubyNode checkArity = Translator.createCheckArityNode(getContext(), sourceSection.getSource(), rubySourceSection, arity);

final LexicalScope lexicalScope = new LexicalScope(getContext().getRootLexicalScope(), module);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(
sourceSection,
LexicalScope.NONE,
lexicalScope,
arity,
module,
accessorName,
@@ -406,7 +407,7 @@ private void createAccesor(DynamicObject module, String name) {
final RubyNode sequence = Translator.sequence(getContext(), sourceSection.getSource(), rubySourceSection, Arrays.asList(checkArity, accessInstanceVariable));
final RubyRootNode rootNode = new RubyRootNode(getContext(), sourceSection, null, sharedMethodInfo, sequence, false);
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
final InternalMethod method = new InternalMethod(getContext(), sharedMethodInfo, accessorName, module, visibility, callTarget);
final InternalMethod method = new InternalMethod(getContext(), sharedMethodInfo, lexicalScope, accessorName, module, visibility, callTarget);

Layouts.MODULE.getFields(module).addMethod(getContext(), this, method);
}
Original file line number Diff line number Diff line change
@@ -112,7 +112,7 @@ protected DynamicObject createProc(InternalMethod method, DynamicObject symbol)

final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(
sourceSection,
null,
method.getLexicalScope(),
Arity.AT_LEAST_ONE,
null,
Layouts.SYMBOL.getString(symbol),
Original file line number Diff line number Diff line change
@@ -75,8 +75,8 @@ public Object execute(VirtualFrame frame) {
callNode.forceInlining();

mainObject = context.getCoreLibrary().getMainObject();
method = new InternalMethod(context, rootNode.getSharedMethodInfo(), rootNode.getSharedMethodInfo().getName(),
context.getCoreLibrary().getObjectClass(), Visibility.PUBLIC, callTarget);
method = new InternalMethod(context, rootNode.getSharedMethodInfo(), rootNode.getSharedMethodInfo().getLexicalScope(),
rootNode.getSharedMethodInfo().getName(), context.getCoreLibrary().getObjectClass(), Visibility.PUBLIC, callTarget);
}

Object[] arguments = RubyArguments.pack(
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2015, 2016 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 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.language.constants;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.core.module.ModuleOperations;
import org.jruby.truffle.language.LexicalScope;
import org.jruby.truffle.language.RubyConstant;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.WarnNode;
import org.jruby.truffle.language.arguments.RubyArguments;
import org.jruby.truffle.language.control.RaiseException;

public abstract class LookupConstantWithDynamicScopeNode extends RubyNode implements LookupConstantInterface {

private final String name;
@Child private WarnNode warnNode;

public LookupConstantWithDynamicScopeNode(String name) {
this.name = name;
}

public abstract RubyConstant executeLookupConstant(VirtualFrame frame);

public RubyConstant lookupConstant(VirtualFrame frame, Object module, String name) {
assert name == this.name;
return executeLookupConstant(frame);
}

public LexicalScope getLexicalScope(VirtualFrame frame) {
return RubyArguments.getMethod(frame).getLexicalScope();
}

@Specialization(guards = "getLexicalScope(frame) == lexicalScope",
assumptions = "getUnmodifiedAssumption(lexicalScope.getLiveModule())",
limit = "getCacheLimit()")
protected RubyConstant lookupConstant(VirtualFrame frame,
@Cached("getLexicalScope(frame)") LexicalScope lexicalScope,
@Cached("doLookup(lexicalScope)") RubyConstant constant,
@Cached("isVisible(lexicalScope, constant)") boolean isVisible) {
if (!isVisible) {
throw new RaiseException(coreExceptions().nameErrorPrivateConstant(constant.getDeclaringModule(), name, this));
}
if (constant != null && constant.isDeprecated()) {
warnDeprecatedConstant(frame, name);
}
return constant;
}

@Specialization
protected RubyConstant lookupConstantUncached(VirtualFrame frame,
@Cached("createBinaryProfile()") ConditionProfile isVisibleProfile,
@Cached("createBinaryProfile()") ConditionProfile isDeprecatedProfile) {
final LexicalScope lexicalScope = getLexicalScope(frame);
final RubyConstant constant = doLookup(lexicalScope);
if (isVisibleProfile.profile(!isVisible(lexicalScope, constant))) {
throw new RaiseException(coreExceptions().nameErrorPrivateConstant(constant.getDeclaringModule(), name, this));
}
if (isDeprecatedProfile.profile(constant != null && constant.isDeprecated())) {
warnDeprecatedConstant(frame, name);
}
return constant;
}

protected Assumption getUnmodifiedAssumption(DynamicObject module) {
return Layouts.MODULE.getFields(module).getUnmodifiedAssumption();
}

@TruffleBoundary
protected RubyConstant doLookup(LexicalScope lexicalScope) {
return ModuleOperations.lookupConstantWithLexicalScope(getContext(), lexicalScope, name);
}

@TruffleBoundary
protected boolean isVisible(LexicalScope lexicalScope, RubyConstant constant) {
return constant == null || constant.isVisibleTo(getContext(), lexicalScope, lexicalScope.getLiveModule());
}

private void warnDeprecatedConstant(VirtualFrame frame, String name) {
if (warnNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
warnNode = insert(new WarnNode());
}
warnNode.execute(frame, "constant ", name, " is deprecated");
}

protected int getCacheLimit() {
return getContext().getOptions().CONSTANT_CACHE;
}
}
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ protected RubyConstant lookupConstant(VirtualFrame frame,
return constant;
}

@Specialization(assumptions = "getUnmodifiedAssumption(getModule())")
@Specialization
protected RubyConstant lookupConstantUncached(VirtualFrame frame,
@Cached("createBinaryProfile()") ConditionProfile isVisibleProfile,
@Cached("createBinaryProfile()") ConditionProfile isDeprecatedProfile) {
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2015, 2016 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 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.language.constants;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyConstant;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.RaiseException;

/** Read a constant using a dynamic lexical scope: class << expr; CONST; end */
public class ReadConstantWithDynamicScopeNode extends RubyNode {

private final String name;

@Child protected LookupConstantWithDynamicScopeNode lookupConstantNode;
@Child private GetConstantNode getConstantNode;

public ReadConstantWithDynamicScopeNode(RubyContext context, SourceSection sourceSection, String name) {
super(context, sourceSection);
this.name = name;
this.lookupConstantNode = LookupConstantWithDynamicScopeNodeGen.create(name);
this.getConstantNode = GetConstantNode.create();
}

@Override
public Object execute(VirtualFrame frame) {
final RubyConstant constant = lookupConstantNode.executeLookupConstant(frame);
final DynamicObject module = lookupConstantNode.getLexicalScope(frame).getLiveModule();

return getConstantNode.executeGetConstant(frame, module, name, constant, lookupConstantNode);
}

public Object readConstant(VirtualFrame frame, Object module, String name) {
return execute(frame);
}

@Override
public Object isDefined(VirtualFrame frame) {
final RubyConstant constant;
try {
constant = lookupConstantNode.executeLookupConstant(frame);
} catch (RaiseException e) {
if (Layouts.BASIC_OBJECT.getLogicalClass(e.getException()) == coreLibrary().getNameErrorClass()) {
// private constant
return nil();
}
throw e;
}

if (constant == null) {
return nil();
} else {
return create7BitString("constant", UTF8Encoding.INSTANCE);
}
}

}
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
import com.oracle.truffle.api.source.Source;
import org.jcodings.Encoding;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.LexicalScope;
import org.jruby.truffle.language.RubyRootNode;
import org.jruby.truffle.language.Visibility;
import org.jruby.truffle.language.arguments.RubyArguments;
@@ -77,9 +78,18 @@ public DeferredCall prepareExecute(ParserContext parserContext,
} else {
declaringModule = context.getCoreLibrary().getObjectClass();
}

final LexicalScope lexicalScope;
if (parentFrame != null) {
lexicalScope = RubyArguments.getMethod(parentFrame).getLexicalScope();
} else {
lexicalScope = context.getRootLexicalScope();
}

final InternalMethod method = new InternalMethod(
context,
rootNode.getSharedMethodInfo(),
lexicalScope,
rootNode.getSharedMethodInfo().getName(),
declaringModule,
Visibility.PUBLIC,
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.LexicalScope;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.Visibility;
import org.jruby.truffle.language.objects.ObjectGraphNode;
@@ -29,6 +30,8 @@
public class InternalMethod implements ObjectGraphNode {

private final SharedMethodInfo sharedMethodInfo;
/** Contains the "dynamic" lexical scope in case this method is under a class << expr; HERE; end */
private final LexicalScope lexicalScope;
private final String name;

private final DynamicObject declaringModule;
@@ -52,6 +55,7 @@ public static InternalMethod fromProc(
return new InternalMethod(
context,
sharedMethodInfo,
Layouts.PROC.getMethod(proc).getLexicalScope(),
name,
declaringModule,
visibility,
@@ -65,28 +69,17 @@ public static InternalMethod fromProc(
public InternalMethod(
RubyContext context,
SharedMethodInfo sharedMethodInfo,
LexicalScope lexicalScope,
String name,
DynamicObject declaringModule,
Visibility visibility,
CallTarget callTarget) {
this(context, sharedMethodInfo, name, declaringModule, visibility, false, null, callTarget, null, null);
}

public InternalMethod(
RubyContext context,
SharedMethodInfo sharedMethodInfo,
String name,
DynamicObject declaringModule,
Visibility visibility,
boolean undefined,
DynamicObject proc,
CallTarget callTarget) {
this(context, sharedMethodInfo, name, declaringModule, visibility, undefined, proc, callTarget, null, null);
Visibility visibility, CallTarget callTarget) {
this(context, sharedMethodInfo, lexicalScope, name, declaringModule, visibility, false, null, callTarget, null, null);
}

public InternalMethod(
RubyContext context,
SharedMethodInfo sharedMethodInfo,
LexicalScope lexicalScope,
String name,
DynamicObject declaringModule,
Visibility visibility,
@@ -95,23 +88,25 @@ public InternalMethod(
CallTarget callTarget,
DynamicObject capturedBlock,
DynamicObject capturedDefaultDefinee) {
this(sharedMethodInfo, name, declaringModule, visibility, undefined, !context.getCoreLibrary().isLoaded(),
proc, callTarget, capturedBlock, capturedDefaultDefinee);
this(sharedMethodInfo, lexicalScope, name, declaringModule, visibility, undefined,
!context.getCoreLibrary().isLoaded(), proc, callTarget, capturedBlock, capturedDefaultDefinee);
}

public InternalMethod(
private InternalMethod(
SharedMethodInfo sharedMethodInfo,
LexicalScope lexicalScope,
String name,
DynamicObject declaringModule,
Visibility visibility,
boolean undefined,
boolean builtIn,
DynamicObject proc,
CallTarget callTarget,
DynamicObject capturedBlock,
DynamicObject capturedDefaultDefinee) {
DynamicObject capturedBlock, DynamicObject capturedDefaultDefinee) {
assert RubyGuards.isRubyModule(declaringModule);
assert lexicalScope != null;
this.sharedMethodInfo = sharedMethodInfo;
this.lexicalScope = lexicalScope;
this.declaringModule = declaringModule;
this.name = name;
this.visibility = visibility;
@@ -159,6 +154,7 @@ public InternalMethod withDeclaringModule(DynamicObject newDeclaringModule) {
} else {
return new InternalMethod(
sharedMethodInfo,
lexicalScope,
name,
newDeclaringModule,
visibility,
@@ -177,6 +173,7 @@ public InternalMethod withName(String newName) {
} else {
return new InternalMethod(
sharedMethodInfo,
lexicalScope,
newName,
declaringModule,
visibility,
@@ -195,6 +192,7 @@ public InternalMethod withVisibility(Visibility newVisibility) {
} else {
return new InternalMethod(
sharedMethodInfo,
lexicalScope,
name,
declaringModule,
newVisibility,
@@ -210,6 +208,7 @@ public InternalMethod withVisibility(Visibility newVisibility) {
public InternalMethod undefined() {
return new InternalMethod(
sharedMethodInfo,
lexicalScope,
name,
declaringModule,
visibility,
@@ -274,4 +273,9 @@ public DynamicObject getCapturedBlock() {
public DynamicObject getCapturedDefaultDefinee() {
return capturedDefaultDefinee;
}

public LexicalScope getLexicalScope() {
return lexicalScope;
}

}
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.LexicalScope;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.Visibility;
import org.jruby.truffle.language.arguments.RubyArguments;
@@ -53,8 +54,10 @@ public InternalMethod executeMethod(VirtualFrame frame) {
} else {
capturedDefaultDefinee = null;
}
return new InternalMethod(getContext(), sharedMethodInfo, name, dummyModule, dummyVisibility, false, null, callTarget, null,
capturedDefaultDefinee);

final LexicalScope lexicalScope = RubyArguments.getMethod(frame).getLexicalScope();
return new InternalMethod(getContext(), sharedMethodInfo, lexicalScope, name, dummyModule, dummyVisibility, false, null, callTarget,
null, capturedDefaultDefinee);
}

@Override
Original file line number Diff line number Diff line change
@@ -9,68 +9,85 @@
*/
package org.jruby.truffle.language.methods;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.Instrumentable;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.kernel.TraceManager;
import org.jruby.truffle.language.LexicalScope;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.RubySourceSection;
import org.jruby.truffle.language.Visibility;
import org.jruby.truffle.language.arguments.RubyArguments;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.instrumentation.Instrumentable;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;

/**
* Define a method from a module body (module/class/class << self ... end).
*/
// This is @Instrumentable because the class event for set_trace_func must fire after
// Class#inherited in RunModuleDefinitionNode.
@Instrumentable(factory = ModuleBodyDefinitionNodeWrapper.class)
public class ModuleBodyDefinitionNode extends RubyNode {

private final String name;
private final SharedMethodInfo sharedMethodInfo;
private final CallTarget callTarget;
private final boolean captureBlock;

public ModuleBodyDefinitionNode(RubyContext context, RubySourceSection sourceSection, String name, SharedMethodInfo sharedMethodInfo,
CallTarget callTarget, boolean captureBlock) {
super(context, sourceSection);
this.name = name;
this.sharedMethodInfo = sharedMethodInfo;
this.callTarget = callTarget;
this.captureBlock = captureBlock;
}
private final boolean dynamicLexicalScope;
private final Map<DynamicObject, LexicalScope> lexicalScopes;

public ModuleBodyDefinitionNode(RubyContext context, SourceSection sourceSection, String name, SharedMethodInfo sharedMethodInfo,
CallTarget callTarget, boolean captureBlock) {
CallTarget callTarget, boolean captureBlock, boolean dynamicLexicalScope) {
super(context, sourceSection);
this.name = name;
this.sharedMethodInfo = sharedMethodInfo;
this.callTarget = callTarget;
this.captureBlock = captureBlock;
this.dynamicLexicalScope = dynamicLexicalScope;
this.lexicalScopes = dynamicLexicalScope ? new ConcurrentHashMap<>() : null;
}

public ModuleBodyDefinitionNode(ModuleBodyDefinitionNode node) {
this(node.getContext(), node.getRubySourceSection(), node.name, node.sharedMethodInfo, node.callTarget, node.captureBlock);
this(node.getContext(), node.getSourceSection(), node.name, node.sharedMethodInfo, node.callTarget, node.captureBlock, node.dynamicLexicalScope);
}

public InternalMethod executeMethod(VirtualFrame frame) {
final DynamicObject dummyModule = coreLibrary().getObjectClass();
final Visibility dummyVisibility = Visibility.PUBLIC;

public InternalMethod createMethod(VirtualFrame frame, LexicalScope staticLexicalScope, DynamicObject module) {
final DynamicObject capturedBlock;

if (captureBlock) {
capturedBlock = RubyArguments.getBlock(frame);
} else {
capturedBlock = null;
}
return new InternalMethod(getContext(), sharedMethodInfo, name, dummyModule, dummyVisibility, false, null, callTarget, capturedBlock, null);

final LexicalScope parentLexicalScope = RubyArguments.getMethod(frame).getLexicalScope();
final LexicalScope lexicalScope = prepareLexicalScope(staticLexicalScope, parentLexicalScope, module);
return new InternalMethod(getContext(), sharedMethodInfo, lexicalScope, name, module, Visibility.PUBLIC, false, null, callTarget, capturedBlock, null);
}

@TruffleBoundary
private LexicalScope prepareLexicalScope(LexicalScope staticLexicalScope, LexicalScope parentLexicalScope, DynamicObject module) {
staticLexicalScope.unsafeSetLiveModule(module);
Layouts.MODULE.getFields(staticLexicalScope.getParent().getLiveModule()).addLexicalDependent(module);
if (!dynamicLexicalScope) {
return staticLexicalScope;
} else {
// Cache the scope per module in case the module body is run multiple times.
// This allows dynamic constant lookup to cache better.
return lexicalScopes.computeIfAbsent(module, m -> new LexicalScope(parentLexicalScope, module));
}
}

@Override
public Object execute(VirtualFrame frame) {
return executeMethod(frame);
// For the purpose of tracing in the right order
return nil();
}

@Override
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@ public SharedMethodInfo(
argumentDescriptors = new ArgumentDescriptor[]{};
}

assert lexicalScope != null;
this.sourceSection = sourceSection;
this.lexicalScope = lexicalScope;
this.arity = arity;
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2016 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 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.language.objects;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.arguments.RubyArguments;

public class DynamicLexicalScopeNode extends RubyNode {

public DynamicLexicalScopeNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Override
public Object execute(VirtualFrame frame) {
return RubyArguments.getMethod(frame).getLexicalScope().getLiveModule();
}

}
Original file line number Diff line number Diff line change
@@ -9,13 +9,11 @@
*/
package org.jruby.truffle.language.objects;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.IndirectCallNode;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.LexicalScope;
import org.jruby.truffle.language.RubyNode;
@@ -44,17 +42,11 @@ public RunModuleDefinitionNode(RubyContext context, SourceSection sourceSection,
@Override
public Object execute(VirtualFrame frame) {
final DynamicObject module = (DynamicObject) definingModule.execute(frame);
final InternalMethod definition = prepareLexicalScope(module, definitionMethod.executeMethod(frame));
definitionMethod.execute(frame); // for tracing
final InternalMethod definition = definitionMethod.createMethod(frame, lexicalScope, module);

return callModuleDefinitionNode.call(frame, definition.getCallTarget(), RubyArguments.pack(
null, null, definition, DeclarationContext.MODULE, null, module, null, new Object[]{}));
}

@TruffleBoundary
private InternalMethod prepareLexicalScope(DynamicObject module, InternalMethod definition) {
lexicalScope.unsafeSetLiveModule(module);
Layouts.MODULE.getFields(lexicalScope.getParent().getLiveModule()).addLexicalDependent(module);
return definition.withDeclaringModule(module);
}

}
2 changes: 2 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/options/Options.java
Original file line number Diff line number Diff line change
@@ -107,6 +107,7 @@ public class Options {
public final boolean SHARED_OBJECTS_FORCE;
public final boolean SHARED_OBJECTS_SHARE_ALL;
public final boolean CEXTS_LOG_LOAD;
public final boolean LOG_DYNAMIC_CONSTANT_LOOKUP;

Options(OptionsBuilder builder) {
HOME = builder.getOrDefault(OptionsCatalog.HOME);
@@ -198,6 +199,7 @@ public class Options {
SHARED_OBJECTS_FORCE = builder.getOrDefault(OptionsCatalog.SHARED_OBJECTS_FORCE);
SHARED_OBJECTS_SHARE_ALL = builder.getOrDefault(OptionsCatalog.SHARED_OBJECTS_SHARE_ALL);
CEXTS_LOG_LOAD = builder.getOrDefault(OptionsCatalog.CEXTS_LOG_LOAD);
LOG_DYNAMIC_CONSTANT_LOOKUP = builder.getOrDefault(OptionsCatalog.LOG_DYNAMIC_CONSTANT_LOOKUP);
}

}
Original file line number Diff line number Diff line change
@@ -105,6 +105,7 @@ public class OptionsCatalog {
public static final OptionDescription SHARED_OBJECTS_FORCE = new BooleanOptionDescription("shared.objects.force", "Force sharing of objects roots at startup", false);
public static final OptionDescription SHARED_OBJECTS_SHARE_ALL = new BooleanOptionDescription("shared.objects.share_all", "Consider all objects as shared", false);
public static final OptionDescription CEXTS_LOG_LOAD = new BooleanOptionDescription("cexts.log.load", "Log loading of cexts", false);
public static final OptionDescription LOG_DYNAMIC_CONSTANT_LOOKUP = new BooleanOptionDescription("constant.dynamic_lookup.log", "Log source code positions where dynamic constant lookup is performed", false);

public static OptionDescription fromName(String name) {
switch (name) {
@@ -286,6 +287,8 @@ public static OptionDescription fromName(String name) {
return SHARED_OBJECTS_SHARE_ALL;
case "cexts.log.load":
return CEXTS_LOG_LOAD;
case "constant.dynamic_lookup.log":
return LOG_DYNAMIC_CONSTANT_LOOKUP;
default:
return null;
}
97 changes: 68 additions & 29 deletions truffle/src/main/java/org/jruby/truffle/parser/BodyTranslator.java
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
import org.joni.NameEntry;
import org.joni.Regex;
import org.joni.Syntax;
import org.jruby.truffle.Log;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.PrimitiveNodeConstructor;
import org.jruby.truffle.core.CoreLibrary;
@@ -70,6 +71,7 @@
import org.jruby.truffle.language.arguments.ArrayIsAtLeastAsLargeAsNode;
import org.jruby.truffle.language.arguments.SingleBlockArgNode;
import org.jruby.truffle.language.constants.ReadConstantNode;
import org.jruby.truffle.language.constants.ReadConstantWithDynamicScopeNode;
import org.jruby.truffle.language.constants.ReadConstantWithLexicalScopeNode;
import org.jruby.truffle.language.constants.WriteConstantNode;
import org.jruby.truffle.language.control.AndNode;
@@ -143,6 +145,7 @@
import org.jruby.truffle.language.objects.DefineClassNode;
import org.jruby.truffle.language.objects.DefineModuleNode;
import org.jruby.truffle.language.objects.DefineModuleNodeGen;
import org.jruby.truffle.language.objects.DynamicLexicalScopeNode;
import org.jruby.truffle.language.objects.LexicalScopeNode;
import org.jruby.truffle.language.objects.ReadClassVariableNode;
import org.jruby.truffle.language.objects.ReadInstanceVariableNode;
@@ -266,6 +269,7 @@
import org.jruby.truffle.platform.graal.AssertConstantNodeGen;
import org.jruby.truffle.platform.graal.AssertNotCompiledNodeGen;
import org.jruby.truffle.tools.ChaosNodeGen;
import org.jruby.truffle.util.SourceSectionUtils;
import org.jruby.truffle.util.StringUtils;
import org.jruby.util.ByteList;

@@ -577,7 +581,7 @@ public RubyNode visitCallNode(CallParseNode node) {
}
} else if (receiver instanceof VCallParseNode // undefined.equal?(obj)
&& ((VCallParseNode) receiver).getName().equals("undefined")
&& getSourcePath(sourceSection).startsWith(buildCorePath(""))
&& getSourcePath(sourceSection).startsWith(corePath())
&& methodName.equals("equal?")) {
RubyNode argument = translateArgumentsAndBlock(sourceSection, null, node.getArgsNode(), methodName).getArguments()[0];
final RubyNode ret = new IsRubiniusUndefinedNode(context, fullSourceSection, argument);
@@ -1010,7 +1014,7 @@ private RubyNode openModule(RubySourceSection sourceSection, RubyNode defineOrGe
}

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParseEnvironment(),
returnId, true, true, sharedMethodInfo, name, 0, null);
returnId, true, true, true, sharedMethodInfo, name, 0, null);

final BodyTranslator moduleTranslator = new BodyTranslator(currentNode, context, this, newEnvironment, source, false);

@@ -1062,7 +1066,8 @@ private ModuleBodyDefinitionNode compileClassNode(RubySourceSection sourceSectio
environment.getSharedMethodInfo().getName(),
environment.getSharedMethodInfo(),
Truffle.getRuntime().createCallTarget(rootNode),
sclass);
sclass,
environment.isDynamicConstantLookup());

return definitionNode;
}
@@ -1136,7 +1141,14 @@ private RubyNode translateCPath(RubySourceSection sourceSection, Colon3ParseNode
final RubyNode ret;

if (node instanceof Colon2ImplicitParseNode) { // use current lexical scope
ret = new LexicalScopeNode(context, fullSourceSection, environment.getLexicalScope());
if (environment.getParseEnvironment().isDynamicConstantLookup()) {
if (context.getOptions().LOG_DYNAMIC_CONSTANT_LOOKUP) {
Log.info("dynamic constant lookup at " + SourceSectionUtils.fileLine(fullSourceSection));
}
ret = new DynamicLexicalScopeNode(context, fullSourceSection);
} else {
ret = new LexicalScopeNode(context, fullSourceSection, environment.getLexicalScope());
}
} else if (node instanceof Colon2ConstParseNode) { // A::B
ret = node.childNodes().get(0).accept(this);
} else { // Colon3ParseNode: on top-level (Object)
@@ -1166,7 +1178,14 @@ public RubyNode visitConstDeclNode(ConstDeclParseNode node) {
final RubyNode moduleNode;
ParseNode constNode = node.getConstNode();
if (constNode == null || constNode instanceof Colon2ImplicitParseNode) {
moduleNode = new LexicalScopeNode(context, sourceSection.toSourceSection(source), environment.getLexicalScope());
if (environment.getParseEnvironment().isDynamicConstantLookup()) {
if (context.getOptions().LOG_DYNAMIC_CONSTANT_LOOKUP) {
Log.info("set dynamic constant at " + SourceSectionUtils.fileLine(sourceSection.toSourceSection(source)));
}
moduleNode = new DynamicLexicalScopeNode(context, sourceSection.toSourceSection(source));
} else {
moduleNode = new LexicalScopeNode(context, sourceSection.toSourceSection(source), environment.getLexicalScope());
}
} else if (constNode instanceof Colon2ConstParseNode) {
constNode = ((Colon2ParseNode) constNode).getLeftNode(); // Misleading doc, we only want the defined part.
moduleNode = constNode.accept(this);
@@ -1200,16 +1219,8 @@ private String getSourcePath(RubySourceSection sourceSection) {
return path;
}

private String buildCorePath(String... components) {
final StringBuilder ret = new StringBuilder(context.getCoreLibrary().getCoreLoadPath());
ret.append(File.separatorChar).append("core");

for (String component : components) {
ret.append(File.separatorChar);
ret.append(component);
}

return ret.toString();
private String corePath() {
return environment.getParseEnvironment().getCorePath();
}

private String buildPartialPath(String... components) {
@@ -1238,7 +1249,7 @@ public RubyNode visitConstNode(ConstParseNode node) {

final String name = ConstantReplacer.replacementName(fullSourceSection, node.getName());

if (name.equals("Rubinius") && getSourcePath(sourceSection).startsWith(buildCorePath(""))) {
if (name.equals("Rubinius") && getSourcePath(sourceSection).startsWith(corePath())) {
final RubyNode ret = new Colon3ParseNode(node.getPosition(), name).accept(this);
return addNewlineIfNeeded(node, ret);
}
@@ -1249,9 +1260,18 @@ public RubyNode visitConstNode(ConstParseNode node) {
return addNewlineIfNeeded(node, ret);
}

final LexicalScope lexicalScope = environment.getLexicalScope();
final RubyNode ret = new ReadConstantWithLexicalScopeNode(context, fullSourceSection, lexicalScope, name);
final RubyNode ret;
if (environment.getParseEnvironment().isDynamicConstantLookup()) {
if (context.getOptions().LOG_DYNAMIC_CONSTANT_LOOKUP) {
Log.info("dynamic constant lookup at " + SourceSectionUtils.fileLine(fullSourceSection));
}
ret = new ReadConstantWithDynamicScopeNode(context, fullSourceSection, name);
} else {
final LexicalScope lexicalScope = environment.getLexicalScope();
ret = new ReadConstantWithLexicalScopeNode(context, fullSourceSection, lexicalScope, name);
}
return addNewlineIfNeeded(node, ret);

}

@Override
@@ -1390,7 +1410,7 @@ protected RubyNode translateMethodDefinition(RubySourceSection sourceSection, Ru

final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(
sourceSection.toSourceSection(source),
environment.getLexicalScope(),
environment.getLexicalScopeOrNull(),
arity,
null,
methodName,
@@ -1401,7 +1421,7 @@ protected RubyNode translateMethodDefinition(RubySourceSection sourceSection, Ru
false);

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(
context, environment, environment.getParseEnvironment(), environment.getParseEnvironment().allocateReturnID(), true, true, sharedMethodInfo, methodName, 0, null);
context, environment, environment.getParseEnvironment(), environment.getParseEnvironment().allocateReturnID(), true, true, false, sharedMethodInfo, methodName, 0, null);

// ownScopeForAssignments is the same for the defined method as the current one.

@@ -1707,7 +1727,7 @@ public RubyNode visitGlobalAsgnNode(GlobalAsgnParseNode node) {
return new UpdateLastBacktraceNode(context, fullSourceSection, rhs);
}

final boolean inCore = getSourcePath(translate(node.getValueNode().getPosition())).startsWith(buildCorePath(""));
final boolean inCore = getSourcePath(translate(node.getValueNode().getPosition())).startsWith(corePath());

if (!inCore && READ_ONLY_GLOBAL_VARIABLES.contains(name)) {
return addNewlineIfNeeded(node, new WriteReadOnlyGlobalNode(context, fullSourceSection, name, rhs));
@@ -1791,7 +1811,7 @@ public RubyNode visitGlobalVarNode(GlobalVarParseNode node) {
}

if (name.equals("$_")) {
if (getSourcePath(sourceSection).equals(buildCorePath("regexp.rb"))) {
if (getSourcePath(sourceSection).equals(corePath() + "regexp.rb")) {
readNode = new RubiniusLastStringReadNode(context, fullSourceSection);
} else {
readNode = new GetFromThreadLocalNode(context, fullSourceSection, readNode);
@@ -1904,7 +1924,7 @@ public RubyNode visitInstAsgnNode(InstAsgnParseNode node) {
final RubyNode self = new RaiseIfFrozenNode(context, fullSourceSection, new SelfNode(environment.getFrameDescriptor()));

final String path = getSourcePath(sourceSection);
final String corePath = buildCorePath("");
final String corePath = corePath();
final RubyNode ret;
if (path.equals(corePath + "hash.rb")) {
if (name.equals("@default")) {
@@ -1952,7 +1972,7 @@ public RubyNode visitInstVarNode(InstVarParseNode node) {
final SelfNode self = new SelfNode(environment.getFrameDescriptor());

final String path = getSourcePath(sourceSection);
final String corePath = buildCorePath("");
final String corePath = corePath();
final RubyNode ret;
if (path.equals(corePath + "regexp.rb")) {
if (name.equals("@source")) {
@@ -1995,7 +2015,7 @@ private RubyNode translateBlockLikeNode(IterParseNode node, boolean isLambda) {

final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(
sourceSection.toSourceSection(source),
environment.getLexicalScope(),
environment.getLexicalScopeOrNull(),
MethodTranslator.getArity(argsNode),
null,
null,
@@ -2012,7 +2032,7 @@ private RubyNode translateBlockLikeNode(IterParseNode node, boolean isLambda) {

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(
context, environment, parseEnvironment, returnID, hasOwnScope, false,
sharedMethodInfo, namedMethodName, environment.getBlockDepth() + 1, parseEnvironment.allocateBreakID());
false, sharedMethodInfo, namedMethodName, environment.getBlockDepth() + 1, parseEnvironment.allocateBreakID());
final MethodTranslator methodCompiler = new MethodTranslator(currentNode, context, this, newEnvironment, true, source, argsNode);

if (isProc) {
@@ -3036,10 +3056,29 @@ public RubyNode visitSClassNode(SClassParseNode node) {
final SourceSection fullSourceSection = sourceSection.toSourceSection(source);

final RubyNode receiverNode = node.getReceiverNode().accept(this);

final SingletonClassNode singletonClassNode = SingletonClassNodeGen.create(context, fullSourceSection, receiverNode);

final RubyNode ret = openModule(sourceSection, singletonClassNode, "(singleton-def)", node.getBodyNode(), true);
final boolean dynamicConstantLookup = environment.getParseEnvironment().isDynamicConstantLookup();
if (!dynamicConstantLookup) {
if (environment.isModuleBody() && node.getReceiverNode() instanceof SelfParseNode) {
// Common case of class << self in a module body, the constant lookup scope is still static
} else if (environment.parent == null && environment.isModuleBody()) {
// At the top-level of a file, opening the singleton class of a single expression
} else {
// Switch to dynamic constant lookup
environment.getParseEnvironment().setDynamicConstantLookup(true);
if (context.getOptions().LOG_DYNAMIC_CONSTANT_LOOKUP) {
Log.info("start dynamic constant lookup at " + SourceSectionUtils.fileLine(fullSourceSection));
}
}
}

final RubyNode ret;
try {
ret = openModule(sourceSection, singletonClassNode, "(singleton-def)", node.getBodyNode(), true);
} finally {
environment.getParseEnvironment().setDynamicConstantLookup(dynamicConstantLookup);
}
return addNewlineIfNeeded(node, ret);
}

@@ -3134,7 +3173,7 @@ public RubyNode visitUntilNode(UntilParseNode node) {
@Override
public RubyNode visitVCallNode(VCallParseNode node) {
final RubySourceSection sourceSection = translate(node.getPosition());
if (node.getName().equals("undefined") && getSourcePath(sourceSection).startsWith(buildCorePath(""))) {
if (node.getName().equals("undefined") && getSourcePath(sourceSection).startsWith(corePath())) {
final RubyNode ret = new ObjectLiteralNode(context, sourceSection.toSourceSection(source), context.getCoreLibrary().getRubiniusUndefined());
return addNewlineIfNeeded(node, ret);
}
Original file line number Diff line number Diff line change
@@ -9,6 +9,8 @@
*/
package org.jruby.truffle.parser;

import java.io.File;

import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.LexicalScope;
import org.jruby.truffle.language.control.BreakID;
@@ -20,24 +22,40 @@
public class ParseEnvironment {

private LexicalScope lexicalScope = null;
private boolean dynamicConstantLookup = false;
private final String corePath;

public ParseEnvironment(RubyContext context) {
this.corePath = context.getCoreLibrary().getCoreLoadPath() + File.separator + "core" + File.separator;
}

public String getCorePath() {
return corePath;
}

public void resetLexicalScope(LexicalScope lexicalScope) {
this.lexicalScope = lexicalScope;
}

public LexicalScope getLexicalScope() {
// TODO (eregon, 4 Dec. 2016): assert !dynamicConstantLookup;
return lexicalScope;
}

public LexicalScope pushLexicalScope() {
return lexicalScope = new LexicalScope(lexicalScope);
return lexicalScope = new LexicalScope(getLexicalScope());
}

public void popLexicalScope() {
lexicalScope = lexicalScope.getParent();
lexicalScope = getLexicalScope().getParent();
}

public boolean isDynamicConstantLookup() {
return dynamicConstantLookup;
}

public void setDynamicConstantLookup(boolean dynamicConstantLookup) {
this.dynamicConstantLookup = dynamicConstantLookup;
}

public ReturnID allocateReturnID() {
Original file line number Diff line number Diff line change
@@ -160,8 +160,10 @@ public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEn
false,
false);

final boolean topLevel = parserContext == ParserContext.TOP_LEVEL_FIRST || parserContext == ParserContext.TOP_LEVEL;
final boolean isModuleBody = topLevel;
final TranslatorEnvironment environment = new TranslatorEnvironment(context, parentEnvironment,
parseEnvironment, parseEnvironment.allocateReturnID(), ownScopeForAssignments, false, sharedMethodInfo, sharedMethodInfo.getName(), 0, null);
parseEnvironment, parseEnvironment.allocateReturnID(), ownScopeForAssignments, false, isModuleBody, sharedMethodInfo, sharedMethodInfo.getName(), 0, null);

// Declare arguments as local variables in the top-level environment - we'll put the values there in a prelude

@@ -173,7 +175,7 @@ public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEn

// Translate to Ruby Truffle nodes

final BodyTranslator translator = new BodyTranslator(currentNode, context, null, environment, source, parserContext == ParserContext.TOP_LEVEL_FIRST || parserContext == ParserContext.TOP_LEVEL);
final BodyTranslator translator = new BodyTranslator(currentNode, context, null, environment, source, topLevel);

RubyNode truffleNode;

@@ -260,7 +262,7 @@ private TranslatorEnvironment environmentForFrameDescriptor(RubyContext context,
false);
// TODO(CS): how do we know if the frame is a block or not?
return new TranslatorEnvironment(context, null, parseEnvironment,
parseEnvironment.allocateReturnID(), true, true, sharedMethodInfo, sharedMethodInfo.getName(), 0, null, frameDescriptor);
parseEnvironment.allocateReturnID(), true, true, false, sharedMethodInfo, sharedMethodInfo.getName(), 0, null, frameDescriptor);
}

private TranslatorEnvironment environmentForFrame(RubyContext context, MaterializedFrame frame) {
@@ -281,7 +283,7 @@ private TranslatorEnvironment environmentForFrame(RubyContext context, Materiali
final MaterializedFrame parent = RubyArguments.getDeclarationFrame(frame);
// TODO(CS): how do we know if the frame is a block or not?
return new TranslatorEnvironment(context, environmentForFrame(context, parent), parseEnvironment,
parseEnvironment.allocateReturnID(), true, true, sharedMethodInfo, sharedMethodInfo.getName(), 0, null, frame.getFrameDescriptor());
parseEnvironment.allocateReturnID(), true, true, false, sharedMethodInfo, sharedMethodInfo.getName(), 0, null, frame.getFrameDescriptor());
}
}

Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@ public class TranslatorEnvironment {

private final boolean ownScopeForAssignments;
private final boolean neverAssignInParentScope;
private final boolean isModuleBody;

protected final TranslatorEnvironment parent;
private boolean needsDeclarationFrame = false; // We keep the logic as we might do it differently one day.
@@ -56,15 +57,16 @@ public class TranslatorEnvironment {

public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, ParseEnvironment parseEnvironment,
ReturnID returnID, boolean ownScopeForAssignments, boolean neverAssignInParentScope,
SharedMethodInfo sharedMethodInfo, String namedMethodName, int blockDepth, BreakID breakID,
FrameDescriptor frameDescriptor) {
boolean isModuleBody, SharedMethodInfo sharedMethodInfo, String namedMethodName, int blockDepth,
BreakID breakID, FrameDescriptor frameDescriptor) {
this.context = context;
this.parent = parent;
this.frameDescriptor = frameDescriptor;
this.parseEnvironment = parseEnvironment;
this.returnID = returnID;
this.ownScopeForAssignments = ownScopeForAssignments;
this.neverAssignInParentScope = neverAssignInParentScope;
this.isModuleBody = isModuleBody;
this.sharedMethodInfo = sharedMethodInfo;
this.namedMethodName = namedMethodName;
this.blockDepth = blockDepth;
@@ -73,15 +75,29 @@ public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent,

public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent, ParseEnvironment parseEnvironment,
ReturnID returnID, boolean ownScopeForAssignments, boolean neverAssignInParentScope,
SharedMethodInfo methodIdentifier, String namedMethodName, int blockDepth, BreakID breakID) {
this(context, parent, parseEnvironment, returnID, ownScopeForAssignments, neverAssignInParentScope, methodIdentifier, namedMethodName, blockDepth, breakID,
new FrameDescriptor(context.getCoreLibrary().getNilObject()));
boolean isModuleBody, SharedMethodInfo sharedMethodInfo, String namedMethodName, int blockDepth, BreakID breakID) {
this(context, parent, parseEnvironment, returnID, ownScopeForAssignments, neverAssignInParentScope, isModuleBody, sharedMethodInfo, namedMethodName, blockDepth,
breakID, new FrameDescriptor(context.getCoreLibrary().getNilObject()));
}

public boolean isDynamicConstantLookup() {
return parseEnvironment.isDynamicConstantLookup();
}

public LexicalScope getLexicalScope() {
assert !isDynamicConstantLookup();
return parseEnvironment.getLexicalScope();
}

public LexicalScope getLexicalScopeOrNull() {
if (isDynamicConstantLookup()) {
// TODO (eregon, 4 Dec. 2016): we should return null here.
return parseEnvironment.getLexicalScope();
} else {
return parseEnvironment.getLexicalScope();
}
}

public LexicalScope pushLexicalScope() {
return parseEnvironment.pushLexicalScope();
}
@@ -193,6 +209,10 @@ public boolean getNeverAssignInParentScope() {
return neverAssignInParentScope;
}

public boolean isModuleBody() {
return isModuleBody;
}

public SharedMethodInfo getSharedMethodInfo() {
return sharedMethodInfo;
}