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,
Loading