Skip to content

Commit

Permalink
[GR-15990] Remove regex context usage from translator
Browse files Browse the repository at this point in the history
PullRequest: truffleruby/2505
  • Loading branch information
eregon committed Mar 23, 2021
2 parents 972a30c + aa14c79 commit 6407ccd
Show file tree
Hide file tree
Showing 15 changed files with 257 additions and 130 deletions.
2 changes: 2 additions & 0 deletions src/main/java/org/truffleruby/core/Hashing.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@

public final class Hashing {

public static final Hashing NO_SEED = new Hashing(0);

@CompilationFinal private long seed;

public Hashing(long seed) {
Expand Down
156 changes: 82 additions & 74 deletions src/main/java/org/truffleruby/core/regexp/ClassicRegexp.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.truffleruby.language.NotOptimizedWarningNode;
import org.truffleruby.language.RubyContextNode;
import org.truffleruby.language.RubyContextSourceNode;
import org.truffleruby.language.control.DeferredRaiseException;
import org.truffleruby.language.dispatch.DispatchNode;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
Expand Down Expand Up @@ -104,10 +105,15 @@ protected boolean ropesMatch(Rope[] a, Rope[] b) {
@TruffleBoundary
protected RubyRegexp createRegexp(Rope[] strings) {
final RegexpOptions options = (RegexpOptions) this.options.clone();
final RopeBuilder preprocessed = ClassicRegexp.preprocessDRegexp(getContext(), strings, options);

final Regex regexp1 = TruffleRegexpNodes
.compile(getContext(), RopeOperations.ropeFromRopeBuilder(preprocessed), options, this);
final RopeBuilder preprocessed;
final Regex regexp1;
try {
preprocessed = ClassicRegexp.preprocessDRegexp(getContext(), strings, options);
regexp1 = TruffleRegexpNodes
.compile(getLanguage(), null, RopeOperations.ropeFromRopeBuilder(preprocessed), options, this);
} catch (DeferredRaiseException dre) {
throw dre.getException(getContext());
}

// The RegexpNodes.compile operation may modify the encoding of the source rope. This modified copy is stored
// in the Regex object as the "user object". Since ropes are immutable, we need to take this updated copy when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ public RegexWarnCallback(RubyContext context) {

@Override
public void warn(String message) {
if (warnings.isVerbose()) {
warnings.warn(message);
}
warnings.warning(message);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public RegexWarnDeferredCallback(RubyDeferredWarnings warnings) {

@Override
public void warn(String message) {
warnings.warn(message);
warnings.warning(message);
}

}
31 changes: 22 additions & 9 deletions src/main/java/org/truffleruby/core/regexp/RegexpNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
import java.util.Iterator;

import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.profiles.BranchProfile;
import org.jcodings.specific.UTF8Encoding;
import org.joni.NameEntry;
import org.joni.Regex;
import org.joni.Region;
import org.truffleruby.RubyContext;
import org.truffleruby.RubyLanguage;
import org.truffleruby.builtins.CoreMethod;
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
import org.truffleruby.builtins.CoreModule;
Expand All @@ -34,6 +35,7 @@
import org.truffleruby.core.string.StringNodes;
import org.truffleruby.core.symbol.RubySymbol;
import org.truffleruby.language.Visibility;
import org.truffleruby.language.control.DeferredRaiseException;
import org.truffleruby.language.control.RaiseException;
import org.truffleruby.language.library.RubyStringLibrary;

Expand All @@ -49,10 +51,10 @@
@CoreModule(value = "Regexp", isClass = true)
public abstract class RegexpNodes {

public static void initialize(RubyContext context, RubyRegexp regexp, Rope setSource, int options,
Node currentNode) {
public static void initialize(RubyLanguage language, RubyRegexp regexp, Rope setSource, int options,
Node currentNode) throws DeferredRaiseException {
final RegexpOptions regexpOptions = RegexpOptions.fromEmbeddedOptions(options);
final Regex regex = TruffleRegexpNodes.compile(context, setSource, regexpOptions, currentNode);
final Regex regex = TruffleRegexpNodes.compile(language, null, setSource, regexpOptions, currentNode);

// The RegexpNodes.compile operation may modify the encoding of the source rope. This modified copy is stored
// in the Regex object as the "user object". Since ropes are immutable, we need to take this updated copy when
Expand Down Expand Up @@ -187,10 +189,15 @@ protected RubyString toS(RubyRegexp regexp) {

@TruffleBoundary
protected Rope createRope(RubyRegexp regexp) {
final ClassicRegexp classicRegexp = new ClassicRegexp(
getContext(),
regexp.source,
RegexpOptions.fromEmbeddedOptions(regexp.regex.getOptions()));
final ClassicRegexp classicRegexp;
try {
classicRegexp = new ClassicRegexp(
getContext(),
regexp.source,
RegexpOptions.fromEmbeddedOptions(regexp.regex.getOptions()));
} catch (DeferredRaiseException dre) {
throw dre.getException(getContext());
}
return classicRegexp.toRopeBuilder().toRope();
}
}
Expand Down Expand Up @@ -270,8 +277,14 @@ protected RubyRegexp initializeAlreadyInitialized(RubyRegexp regexp, Object patt
@Specialization(
guards = { "libPattern.isRubyString(pattern)", "!isRegexpLiteral(regexp)", "!isInitialized(regexp)" })
protected RubyRegexp initialize(RubyRegexp regexp, Object pattern, int options,
@Cached BranchProfile errorProfile,
@CachedLibrary(limit = "2") RubyStringLibrary libPattern) {
RegexpNodes.initialize(getContext(), regexp, libPattern.getRope(pattern), options, this);
try {
RegexpNodes.initialize(getLanguage(), regexp, libPattern.getRope(pattern), options, this);
} catch (DeferredRaiseException dre) {
errorProfile.enter();
throw dre.getException(getContext());
}
return regexp;
}
}
Expand Down
70 changes: 46 additions & 24 deletions src/main/java/org/truffleruby/core/regexp/TruffleRegexpNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.source.Source;
import org.jcodings.Encoding;
import org.jcodings.specific.ASCIIEncoding;
Expand All @@ -28,12 +29,14 @@
import org.joni.Regex;
import org.joni.Region;
import org.truffleruby.RubyContext;
import org.truffleruby.RubyLanguage;
import org.truffleruby.builtins.CoreMethod;
import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
import org.truffleruby.builtins.CoreModule;
import org.truffleruby.builtins.Primitive;
import org.truffleruby.builtins.PrimitiveArrayArgumentsNode;
import org.truffleruby.collections.ConcurrentOperations;
import org.truffleruby.core.Hashing;
import org.truffleruby.core.array.ArrayBuilderNode;
import org.truffleruby.core.array.ArrayBuilderNode.BuilderState;
import org.truffleruby.core.array.RubyArray;
Expand All @@ -54,6 +57,7 @@
import org.truffleruby.core.string.StringOperations;
import org.truffleruby.language.Nil;
import org.truffleruby.language.RubyContextNode;
import org.truffleruby.language.control.DeferredRaiseException;
import org.truffleruby.language.dispatch.DispatchNode;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
Expand All @@ -66,6 +70,7 @@
import com.oracle.truffle.api.profiles.ConditionProfile;
import org.truffleruby.language.library.RubyStringLibrary;
import org.truffleruby.language.objects.AllocationTracing;
import org.truffleruby.parser.RubyDeferredWarnings;

@CoreModule("Truffle::RegexpOperations")
public class TruffleRegexpNodes {
Expand Down Expand Up @@ -101,10 +106,14 @@ public static Encoding checkEncoding(RubyRegexp regexp, Encoding strEnc, CodeRan
private static Regex makeRegexpForEncoding(RubyContext context, RubyRegexp regexp, Encoding enc, Node currentNode) {
final Encoding[] fixedEnc = new Encoding[]{ null };
final Rope sourceRope = regexp.source;
final RopeBuilder preprocessed = ClassicRegexp
.preprocess(context, sourceRope, enc, fixedEnc, RegexpSupport.ErrorMode.RAISE);
final RegexpOptions options = regexp.options;
return ClassicRegexp.makeRegexp(context, preprocessed, options, enc, sourceRope, currentNode);
try {
final RopeBuilder preprocessed = ClassicRegexp
.preprocess(sourceRope, enc, fixedEnc, RegexpSupport.ErrorMode.RAISE);
final RegexpOptions options = regexp.options;
return ClassicRegexp.makeRegexp(context, null, preprocessed, options, enc, sourceRope, currentNode);
} catch (DeferredRaiseException dre) {
throw dre.getException(context);
}
}

@CoreMethod(names = "union", onSingleton = true, required = 2, rest = true)
Expand All @@ -122,16 +131,18 @@ public abstract static class RegexpUnionNode extends CoreMethodArrayArgumentsNod
limit = "getDefaultCacheLimit()")
protected Object executeFastUnion(VirtualFrame frame, RubyString str, Object sep, Object[] args,
@Cached(value = "args", dimensions = 1) Object[] cachedArgs,
@Cached("buildUnion(str, sep, args)") RubyRegexp union) {
@Cached BranchProfile errorProfile,
@Cached("buildUnion(str, sep, args, errorProfile)") RubyRegexp union) {
return copyNode.call(union, "clone");
}

@Specialization(replaces = "executeFastUnion")
protected Object executeSlowUnion(RubyString str, Object sep, Object[] args) {
return buildUnion(str, sep, args);
protected Object executeSlowUnion(RubyString str, Object sep, Object[] args,
@Cached BranchProfile errorProfile) {
return buildUnion(str, sep, args, errorProfile);
}

public RubyRegexp buildUnion(RubyString str, Object sep, Object[] args) {
public RubyRegexp buildUnion(RubyString str, Object sep, Object[] args, BranchProfile errorProfile) {
RubyString regexpString = null;
for (int i = 0; i < args.length; i++) {
if (regexpString == null) {
Expand All @@ -141,7 +152,12 @@ public RubyRegexp buildUnion(RubyString str, Object sep, Object[] args) {
regexpString = appendNode.executeStringAppend(regexpString, string(args[i]));
}
}
return createRegexp(regexpString.rope);
try {
return createRegexp(regexpString.rope);
} catch (DeferredRaiseException dre) {
errorProfile.enter();
throw dre.getException(getContext());
}
}

public Object string(Object obj) {
Expand All @@ -168,9 +184,9 @@ protected boolean argsMatch(VirtualFrame frame, Object[] cachedArgs, Object[] ar
}

@TruffleBoundary
public RubyRegexp createRegexp(Rope pattern) {
public RubyRegexp createRegexp(Rope pattern) throws DeferredRaiseException {
final RegexpOptions regexpOptions = RegexpOptions.fromEmbeddedOptions(0);
final Regex regex = compile(getContext(), pattern, regexpOptions, this);
final Regex regex = compile(getLanguage(), null, pattern, regexpOptions, this);

return new RubyRegexp(
regex,
Expand Down Expand Up @@ -214,13 +230,17 @@ protected Object tRegexCompile(RubyRegexp re, boolean atStart, RubyEncoding enco
return re.tregexCache.getOrCreate(atStart, encoding.encoding, (sticky, enc) -> {
String processedRegexpSource;
Encoding[] fixedEnc = new Encoding[]{ null };
RopeBuilder ropeBuilder = ClassicRegexp
.preprocess(
getContext(),
re.source,
enc,
fixedEnc,
RegexpSupport.ErrorMode.RAISE);
RopeBuilder ropeBuilder = null;
try {
ropeBuilder = ClassicRegexp
.preprocess(
re.source,
enc,
fixedEnc,
RegexpSupport.ErrorMode.RAISE);
} catch (DeferredRaiseException dre) {
throw dre.getException(getContext());
}
Rope rope = ropeBuilder.toRope();
try {
processedRegexpSource = RopeOperations.decodeRope(rope);
Expand Down Expand Up @@ -522,25 +542,27 @@ public String toString() {

/** WARNING: computeRegexpEncoding() mutates options, so the caller should make sure it's a copy */
@TruffleBoundary
public static Regex compile(RubyContext context, Rope bytes, RegexpOptions options, Node currentNode) {
public static Regex compile(RubyLanguage language, RubyDeferredWarnings rubyDeferredWarnings, Rope bytes,
RegexpOptions options, Node currentNode) throws DeferredRaiseException {
if (options.isEncodingNone()) {
bytes = RopeOperations.withEncoding(bytes, ASCIIEncoding.INSTANCE);
}
Encoding enc = bytes.getEncoding();
Encoding[] fixedEnc = new Encoding[]{ null };
RopeBuilder unescaped = ClassicRegexp
.preprocess(context, bytes, enc, fixedEnc, RegexpSupport.ErrorMode.RAISE);
enc = ClassicRegexp.computeRegexpEncoding(options, enc, fixedEnc, context);
.preprocess(bytes, enc, fixedEnc, RegexpSupport.ErrorMode.RAISE);
enc = ClassicRegexp.computeRegexpEncoding(options, enc, fixedEnc);

Regex regexp = ClassicRegexp.makeRegexp(context, unescaped, options, enc, bytes, currentNode);
Regex regexp = ClassicRegexp
.makeRegexp(null, rubyDeferredWarnings, unescaped, options, enc, bytes, currentNode);
regexp.setUserObject(RopeOperations.withEncoding(bytes, enc));

if (context.getOptions().REGEXP_INSTRUMENT_CREATION) {
if (language.options.REGEXP_INSTRUMENT_CREATION) {
final RegexpCacheKey key = new RegexpCacheKey(
bytes,
enc,
options.toJoniOptions(),
context.getHashing(REHASH_COMPILED_REGEXPS));
Hashing.NO_SEED);
ConcurrentOperations.getOrCompute(compiledRegexps, key, x -> new AtomicInteger()).incrementAndGet();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2021, 2021 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.language.control;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import org.truffleruby.RubyContext;
import org.truffleruby.core.exception.RubyException;

public class DeferredRaiseException extends Exception {

private static final long serialVersionUID = -9202513314613691124L;

public final ExceptionGetter exceptionGetter;

public DeferredRaiseException(ExceptionGetter exceptionGetter) {
this.exceptionGetter = exceptionGetter;
}

@TruffleBoundary
public RaiseException getException(RubyContext context) {
return new RaiseException(context, exceptionGetter.getException(context));
}

public interface ExceptionGetter {
RubyException getException(RubyContext context);
}

public Throwable fillInStackTrace() {
return this;
}

}
13 changes: 13 additions & 0 deletions src/main/java/org/truffleruby/options/LanguageOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ public class LanguageOptions {
public final int ARRAY_STRATEGY_CACHE;
/** --hash-packed-array-max=3 */
public final int HASH_PACKED_ARRAY_MAX;
/** --regexp-instrument-creation=false */
public final boolean REGEXP_INSTRUMENT_CREATION;
/** --shared-objects=true */
public final boolean SHARED_OBJECTS_ENABLED;
/** --shared-objects-debug=false */
Expand Down Expand Up @@ -153,6 +155,7 @@ public LanguageOptions(Env env, OptionValues options) {
ARRAY_DUP_CACHE = options.get(OptionsCatalog.ARRAY_DUP_CACHE_KEY);
ARRAY_STRATEGY_CACHE = options.get(OptionsCatalog.ARRAY_STRATEGY_CACHE_KEY);
HASH_PACKED_ARRAY_MAX = options.get(OptionsCatalog.HASH_PACKED_ARRAY_MAX_KEY);
REGEXP_INSTRUMENT_CREATION = options.get(OptionsCatalog.REGEXP_INSTRUMENT_CREATION_KEY);
SHARED_OBJECTS_ENABLED = options.get(OptionsCatalog.SHARED_OBJECTS_ENABLED_KEY);
SHARED_OBJECTS_DEBUG = options.get(OptionsCatalog.SHARED_OBJECTS_DEBUG_KEY);
SHARED_OBJECTS_FORCE = options.get(OptionsCatalog.SHARED_OBJECTS_FORCE_KEY);
Expand Down Expand Up @@ -242,6 +245,8 @@ public Object fromDescriptor(OptionDescriptor descriptor) {
return ARRAY_STRATEGY_CACHE;
case "ruby.hash-packed-array-max":
return HASH_PACKED_ARRAY_MAX;
case "ruby.regexp-instrument-creation":
return REGEXP_INSTRUMENT_CREATION;
case "ruby.shared-objects":
return SHARED_OBJECTS_ENABLED;
case "ruby.shared-objects-debug":
Expand Down Expand Up @@ -295,6 +300,7 @@ public static boolean areOptionsCompatible(OptionValues one, OptionValues two) {
one.get(OptionsCatalog.ARRAY_DUP_CACHE_KEY).equals(two.get(OptionsCatalog.ARRAY_DUP_CACHE_KEY)) &&
one.get(OptionsCatalog.ARRAY_STRATEGY_CACHE_KEY).equals(two.get(OptionsCatalog.ARRAY_STRATEGY_CACHE_KEY)) &&
one.get(OptionsCatalog.HASH_PACKED_ARRAY_MAX_KEY).equals(two.get(OptionsCatalog.HASH_PACKED_ARRAY_MAX_KEY)) &&
one.get(OptionsCatalog.REGEXP_INSTRUMENT_CREATION_KEY).equals(two.get(OptionsCatalog.REGEXP_INSTRUMENT_CREATION_KEY)) &&
one.get(OptionsCatalog.SHARED_OBJECTS_ENABLED_KEY).equals(two.get(OptionsCatalog.SHARED_OBJECTS_ENABLED_KEY)) &&
one.get(OptionsCatalog.SHARED_OBJECTS_DEBUG_KEY).equals(two.get(OptionsCatalog.SHARED_OBJECTS_DEBUG_KEY)) &&
one.get(OptionsCatalog.SHARED_OBJECTS_FORCE_KEY).equals(two.get(OptionsCatalog.SHARED_OBJECTS_FORCE_KEY));
Expand Down Expand Up @@ -591,6 +597,13 @@ public static boolean areOptionsCompatibleOrLog(TruffleLogger logger, LanguageOp
return false;
}

oldValue = oldOptions.REGEXP_INSTRUMENT_CREATION;
newValue = newOptions.REGEXP_INSTRUMENT_CREATION;
if (!newValue.equals(oldValue)) {
logger.fine("not reusing pre-initialized context: --regexp-instrument-creation differs, was: " + oldValue + " and is now: " + newValue);
return false;
}

oldValue = oldOptions.SHARED_OBJECTS_ENABLED;
newValue = newOptions.SHARED_OBJECTS_ENABLED;
if (!newValue.equals(oldValue)) {
Expand Down
Loading

0 comments on commit 6407ccd

Please sign in to comment.