From 0a23e687868e9d3702e0f3666e99ac491e071712 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Mon, 5 Feb 2024 12:57:18 +0100 Subject: [PATCH] ParserCache does not always have a RubyLanguage * There seems to be a language instance for the case of pre-initialization, but it is not the case for no pre-initialization, e.g. for libpolyglot or embedding as native image. --- .../java/org/truffleruby/RubyLanguage.java | 11 ++++++ .../java/org/truffleruby/aot/ParserCache.java | 13 +++---- .../truffleruby/debug/TruffleDebugNodes.java | 9 ++--- .../parser/YARPTranslatorDriver.java | 37 +++++++------------ 4 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/truffleruby/RubyLanguage.java b/src/main/java/org/truffleruby/RubyLanguage.java index 75bdb6974aae..8bfcec4a5787 100644 --- a/src/main/java/org/truffleruby/RubyLanguage.java +++ b/src/main/java/org/truffleruby/RubyLanguage.java @@ -913,6 +913,17 @@ public String getSourcePath(Source source) { } } + @TruffleBoundary + public static String getCorePath(Source source) { + final String path = getPath(source); + String coreLoadPath = OptionsCatalog.CORE_LOAD_PATH_KEY.getDefaultValue(); + if (path.startsWith(coreLoadPath)) { + return " " + path.substring(coreLoadPath.length() + 1); + } else { + throw CompilerDirectives.shouldNotReachHere(path + " is not a core path starting with " + coreLoadPath); + } + } + /** Only use when no language/context is available (e.g. Node#toString). Prefer * {@link RubyContext#fileLine(SourceSection)} as it accounts for coreLoadPath and line offsets. */ @TruffleBoundary diff --git a/src/main/java/org/truffleruby/aot/ParserCache.java b/src/main/java/org/truffleruby/aot/ParserCache.java index 6a0b5da97e94..8f44e4d851a9 100644 --- a/src/main/java/org/truffleruby/aot/ParserCache.java +++ b/src/main/java/org/truffleruby/aot/ParserCache.java @@ -21,8 +21,6 @@ import org.truffleruby.RubyLanguage; import org.truffleruby.core.CoreLibrary; import org.truffleruby.language.loader.ResourceLoader; -import org.truffleruby.parser.ParseEnvironment; -import org.truffleruby.parser.ParserContext; import org.truffleruby.parser.RubySource; import org.truffleruby.parser.YARPTranslatorDriver; import org.truffleruby.shared.options.OptionsCatalog; @@ -39,7 +37,7 @@ public final class ParserCache { final Map> cache = new HashMap<>(); for (String coreFile : CoreLibrary.CORE_FILES) { - //intern() to improve footprint + // intern() to improve footprint final String path = (defaultCoreLibraryPath + coreFile).intern(); final RubySource source = loadSource(path); cache.put(path, parse(source)); @@ -62,14 +60,13 @@ private static RubySource loadSource(String feature) { } private static Pair parse(RubySource source) { - var language = RubyLanguage.getCurrentLanguage(); var yarpSource = YARPTranslatorDriver.createYARPSource(source.getBytes()); - var parseEnvironment = new ParseEnvironment(language, source, yarpSource, ParserContext.TOP_LEVEL, null); + var sourcePath = RubyLanguage.getCorePath(source.getSource()).intern(); - var parseResult = YARPTranslatorDriver.parseToYARPAST(language, source, Collections.emptyList(), - parseEnvironment); + var parseResult = YARPTranslatorDriver.parseToYARPAST(source, sourcePath, yarpSource, Collections.emptyList(), + false); - YARPTranslatorDriver.handleWarningsErrorsNoContext(language, parseResult, source, yarpSource); + YARPTranslatorDriver.handleWarningsErrorsNoContext(parseResult, sourcePath, yarpSource); return Pair.create(parseResult, source.getSource()); } diff --git a/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java b/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java index 3ecb7443772a..9078fa70fdeb 100644 --- a/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java +++ b/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java @@ -106,7 +106,6 @@ import com.oracle.truffle.api.nodes.NodeUtil; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.utilities.TriState; -import org.truffleruby.parser.ParseEnvironment; import org.truffleruby.parser.ParserContext; import org.truffleruby.parser.RubySource; import org.truffleruby.parser.TranslatorEnvironment; @@ -261,12 +260,12 @@ Object ast(Object code, var source = Source.newBuilder("ruby", new ByteBasedCharSequence(codeString), name).build(); var rubySource = new RubySource(source, name); + var language = getLanguage(); var yarpSource = YARPTranslatorDriver.createYARPSource(rubySource.getBytes()); - var parseEnvironment = new ParseEnvironment(getLanguage(), rubySource, yarpSource, ParserContext.TOP_LEVEL, - this); + String sourcePath = rubySource.getSourcePath(language).intern(); - var parseResult = YARPTranslatorDriver.parseToYARPAST(getLanguage(), rubySource, Collections.emptyList(), - parseEnvironment); + var parseResult = YARPTranslatorDriver.parseToYARPAST(rubySource, sourcePath, yarpSource, + Collections.emptyList(), language.options.FROZEN_STRING_LITERALS); var ast = parseResult.value; return createString(fromJavaStringNode, ast.toString(), Encodings.UTF_8); diff --git a/src/main/java/org/truffleruby/parser/YARPTranslatorDriver.java b/src/main/java/org/truffleruby/parser/YARPTranslatorDriver.java index 9432a759803e..29dfcfa932ac 100644 --- a/src/main/java/org/truffleruby/parser/YARPTranslatorDriver.java +++ b/src/main/java/org/truffleruby/parser/YARPTranslatorDriver.java @@ -156,6 +156,8 @@ public RootCallTarget parse(RubySource rubySource, ParserContext parserContext, // Parse to the YARP AST final RubyDeferredWarnings rubyWarnings = new RubyDeferredWarnings(); + final String sourcePath = rubySource.getSourcePath(language).intern(); + // Only use the cache while loading top-level core library files, as eval() later could use // the same Source name but should not use the cache. For instance, // TOPLEVEL_BINDING.eval("self") would use the cache which is wrong. @@ -168,12 +170,12 @@ public RootCallTarget parse(RubySource rubySource, ParserContext parserContext, parseResult = context.getMetricsProfiler().callWithMetrics( "parsing", source.getName(), - () -> parseToYARPAST(language, rubySource, localsInScopes, - parseEnvironment)); + () -> parseToYARPAST(rubySource, sourcePath, yarpSource, localsInScopes, + language.options.FROZEN_STRING_LITERALS)); printParseTranslateExecuteMetric("after-parsing", context, source); } - handleWarningsErrorsPrimitives(context, language, parseResult, rubySource, parseEnvironment, rubyWarnings); + handleWarningsErrorsPrimitives(context, parseResult, rubySource, sourcePath, parseEnvironment, rubyWarnings); var node = parseResult.value; @@ -355,18 +357,14 @@ private String getMethodName(ParserContext parserContext, MaterializedFrame pare } } - public static ParseResult parseToYARPAST(RubyLanguage language, RubySource rubySource, - List> localsInScopes, ParseEnvironment parseEnvironment) { + public static ParseResult parseToYARPAST(RubySource rubySource, String sourcePath, Nodes.Source yarpSource, + List> localsInScopes, boolean frozenStringLiteral) { TruffleSafepoint.poll(DummyNode.INSTANCE); - // intern() to improve footprint - String sourcePath = rubySource.getSourcePath(language).intern(); - byte[] sourceBytes = rubySource.getBytes(); final byte[] filepath = sourcePath.getBytes(Encodings.FILESYSTEM_CHARSET); int line = rubySource.getLineOffset() + 1; byte[] encoding = StringOperations.encodeAsciiBytes(rubySource.getEncoding().toString()); // encoding name is supposed to contain only ASCII characters - boolean frozenStringLiteral = language.options.FROZEN_STRING_LITERALS; var version = ParsingOptions.SyntaxVersion.V3_3_0; byte[][][] scopes; @@ -400,17 +398,13 @@ public static ParseResult parseToYARPAST(RubyLanguage language, RubySource rubyS scopes); byte[] serializedBytes = Parser.parseAndSerialize(sourceBytes, parsingOptions); - Nodes.Source yarpSource = parseEnvironment.yarpSource; return YARPLoader.load(serializedBytes, yarpSource, rubySource); } - public static void handleWarningsErrorsPrimitives(RubyContext context, RubyLanguage language, - ParseResult parseResult, RubySource rubySource, ParseEnvironment parseEnvironment, + public static void handleWarningsErrorsPrimitives(RubyContext context, ParseResult parseResult, + RubySource rubySource, String sourcePath, ParseEnvironment parseEnvironment, RubyDeferredWarnings rubyWarnings) { - // intern() to improve footprint - String sourcePath = rubySource.getSourcePath(language).intern(); - final ParseResult.Error[] errors = parseResult.errors; // collect warnings generated by the parser @@ -464,25 +458,20 @@ public static void handleWarningsErrorsPrimitives(RubyContext context, RubyLangu parseEnvironment.allowTruffleRubyPrimitives = allowTruffleRubyPrimitives; } - public static void handleWarningsErrorsNoContext(RubyLanguage language, ParseResult parseResult, - RubySource rubySource, Nodes.Source yarpSource) { + public static void handleWarningsErrorsNoContext(ParseResult parseResult, String sourcePath, + Nodes.Source yarpSource) { if (parseResult.errors.length > 0) { var error = parseResult.errors[0]; throw CompilerDirectives.shouldNotReachHere("Parse error in " + - fileLineYARPSource(error.location, language, rubySource, yarpSource) + ": " + error.message); + sourcePath + ":" + yarpSource.line(error.location.startOffset) + ": " + error.message); } for (var warning : parseResult.warnings) { throw CompilerDirectives.shouldNotReachHere("Warning in " + - fileLineYARPSource(warning.location, language, rubySource, yarpSource) + ": " + warning.message); + sourcePath + ":" + yarpSource.line(warning.location.startOffset) + ": " + warning.message); } } - private static String fileLineYARPSource(Nodes.Location location, RubyLanguage language, RubySource rubySource, - Nodes.Source yarpSource) { - return rubySource.getSourcePath(language) + ":" + yarpSource.line(location.startOffset); - } - public static Nodes.Source createYARPSource(byte[] sourceBytes) { return new Nodes.Source(sourceBytes); }