From 930a215b5c959b658471354f507ca8219ec9585d Mon Sep 17 00:00:00 2001 From: Robert Muir Date: Wed, 11 May 2016 23:56:19 -0400 Subject: [PATCH] add debugger --- modules/lang-painless/build.gradle | 1 + .../org/elasticsearch/painless/Compiler.java | 30 ++++------- .../org/elasticsearch/painless/Debugger.java | 53 +++++++++++++++++++ 3 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java diff --git a/modules/lang-painless/build.gradle b/modules/lang-painless/build.gradle index bf0694a0b73..9f617c4e436 100644 --- a/modules/lang-painless/build.gradle +++ b/modules/lang-painless/build.gradle @@ -29,6 +29,7 @@ dependencies { compile 'org.ow2.asm:asm:5.0.4' compile 'org.ow2.asm:asm-commons:5.0.4' compile 'org.ow2.asm:asm-tree:5.0.4' + testCompile 'org.ow2.asm:asm-util:5.0.4' } dependencyLicenses { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java index 4cba3cb7923..6a21b7cc877 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java @@ -90,20 +90,23 @@ final class Compiler { * @return An {@link Executable} Painless script. */ static Executable compile(final Loader loader, final String name, final String source, final CompilerSettings settings) { + final byte[] bytes = compile(name, source, Definition.INSTANCE, settings); + return createExecutable(loader, Definition.INSTANCE, name, source, bytes); + } + + /** + * Compiles the script to bytecode + */ + static byte[] compile(String name, String source, Definition definition, CompilerSettings settings) { if (source.length() > MAXIMUM_SOURCE_LENGTH) { throw new IllegalArgumentException("Scripts may be no longer than " + MAXIMUM_SOURCE_LENGTH + - " characters. The passed in script is " + source.length() + " characters. Consider using a" + - " plugin if a script longer than this length is a requirement."); + " characters. The passed in script is " + source.length() + " characters. Consider using a" + + " plugin if a script longer than this length is a requirement."); } - - final Definition definition = Definition.INSTANCE; final ParserRuleContext root = createParseTree(source); final Metadata metadata = new Metadata(definition, source, root, settings); Analyzer.analyze(metadata); - final byte[] bytes = Writer.write(metadata); - final Executable executable = createExecutable(loader, definition, name, source, bytes); - - return executable; + return Writer.write(metadata); } /** @@ -140,17 +143,6 @@ final class Compiler { private static Executable createExecutable(final Loader loader, final Definition definition, final String name, final String source, final byte[] bytes) { try { - // Used for debugging. Uncomment this code and add -Dtests.security.manager=false when running to save - // the generated Java class files. The javap tool can then be used to inspect the generated byte code. - - // try { - // FileOutputStream f = new FileOutputStream(new File(""), false); - // f.write(bytes); - // f.close(); - // } catch (Exception e) { - // throw new RuntimeException(e); - // } - final Class clazz = loader.define(WriterConstants.CLASS_NAME, bytes); final java.lang.reflect.Constructor constructor = clazz.getConstructor(Definition.class, String.class, String.class); diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java new file mode 100644 index 00000000000..949dd57ec5a --- /dev/null +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java @@ -0,0 +1,53 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.painless; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.util.TraceClassVisitor; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +/** quick and dirty tools for debugging */ +final class Debugger { + + /** compiles source to bytecode, and returns debugging output */ + static String toString(String source) { + return toString(source, new CompilerSettings()); + } + + /** compiles to bytecode, and returns debugging output */ + static String toString(String source, CompilerSettings settings) { + byte[] bytes = Compiler.compile("debugger", source, Definition.INSTANCE, settings); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + PrintWriter outputWriter = new PrintWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8)); + ClassReader reader = new ClassReader(bytes); + reader.accept(new TraceClassVisitor(outputWriter), 0); + outputWriter.flush(); + try { + return output.toString("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } +}