/***** BEGIN LICENSE BLOCK *****
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Common Public
* License Version 1.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.eclipse.org/legal/cpl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2007-2011 Nick Sieger <nicksieger@gmail.com>
* Copyright (C) 2009 Joseph LaFata <joe@quibb.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the CPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the CPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby;
import org.jruby.util.cli.ArgumentProcessor;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.NumberFormatException;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;
import org.jruby.ast.executable.Script;
import org.jruby.compiler.ASTCompiler;
import org.jruby.compiler.ASTCompiler19;
import org.jruby.exceptions.MainExitException;
import org.jruby.embed.util.SystemPropertyCatcher;
import org.jruby.runtime.Constants;
import org.jruby.runtime.backtrace.TraceType;
import org.jruby.runtime.load.LoadService;
import org.jruby.runtime.load.LoadService19;
import org.jruby.runtime.profile.ProfileOutput;
import org.jruby.util.ClassCache;
import org.jruby.util.InputStreamMarkCursor;
import org.jruby.util.JRubyFile;
import org.jruby.util.KCode;
import org.jruby.util.NormalizedFile;
import org.jruby.util.SafePropertyAccessor;
import org.jruby.util.cli.OutputStrings;
import org.jruby.util.cli.Options;
import org.objectweb.asm.Opcodes;
/**
* A structure used to configure new JRuby instances. All publicly-tweakable
* aspects of Ruby can be modified here, including those settable by command-
* line options, those available through JVM properties, and those suitable for
* embedding.
*/
public class RubyInstanceConfig {
public RubyInstanceConfig() {
currentDirectory = Ruby.isSecurityRestricted() ? "/" : JRubyFile.getFileProperty("user.dir");
samplingEnabled = SafePropertyAccessor.getBoolean("jruby.sampling.enabled", false);
String compatString = Options.COMPAT_VERSION.load();
compatVersion = CompatVersion.getVersionFromString(compatString);
if (compatVersion == null) {
error.println("Compatibility version `" + compatString + "' invalid; use 1.8, 1.9, or 2.0. Using 1.8.");
compatVersion = CompatVersion.RUBY1_8;
}
if (Ruby.isSecurityRestricted()) {
compileMode = CompileMode.OFF;
jitLogging = false;
jitDumping = false;
jitLoggingVerbose = false;
jitLogEvery = 0;
jitThreshold = -1;
jitMax = 0;
jitMaxSize = -1;
managementEnabled = false;
} else {
if (COMPILE_EXCLUDE != null) {
String[] elements = COMPILE_EXCLUDE.split(",");
excludedMethods.addAll(Arrays.asList(elements));
}
managementEnabled = Options.MANAGEMENT_ENABLED.load();
runRubyInProcess = Options.LAUNCH_INPROC.load();
String jitModeProperty = Options.COMPILE_MODE.load();
if (jitModeProperty.equals("OFF")) {
compileMode = CompileMode.OFF;
} else if (jitModeProperty.equals("OFFIR")) {
compileMode = CompileMode.OFFIR;
} else if (jitModeProperty.equals("JIT")) {
compileMode = CompileMode.JIT;
} else if (jitModeProperty.equals("FORCE")) {
compileMode = CompileMode.FORCE;
} else {
error.print(Options.COMPILE_MODE + " property must be OFF, JIT, FORCE, or unset; defaulting to JIT");
compileMode = CompileMode.JIT;
}
jitLogging = Options.JIT_LOGGING.load();
jitDumping = Options.JIT_DUMPING.load();
jitLoggingVerbose = Options.JIT_LOGGING_VERBOSE.load();
jitLogEvery = Options.JIT_LOGEVERY.load();
jitThreshold = Options.JIT_THRESHOLD.load();
jitMax = Options.JIT_MAX.load();
jitMaxSize = Options.JIT_MAXSIZE.load();
}
// default ClassCache using jitMax as a soft upper bound
classCache = new ClassCache<Script>(loader, jitMax);
threadDumpSignal = Options.THREAD_DUMP_SIGNAL.load();
try {
environment = System.getenv();
} catch (SecurityException se) {
environment = new HashMap();
}
}
public RubyInstanceConfig(RubyInstanceConfig parentConfig) {
currentDirectory = parentConfig.getCurrentDirectory();
samplingEnabled = parentConfig.samplingEnabled;
compatVersion = parentConfig.compatVersion;
compileMode = parentConfig.getCompileMode();
jitLogging = parentConfig.jitLogging;
jitDumping = parentConfig.jitDumping;
jitLoggingVerbose = parentConfig.jitLoggingVerbose;
jitLogEvery = parentConfig.jitLogEvery;
jitThreshold = parentConfig.jitThreshold;
jitMax = parentConfig.jitMax;
jitMaxSize = parentConfig.jitMaxSize;
managementEnabled = parentConfig.managementEnabled;
runRubyInProcess = parentConfig.runRubyInProcess;
excludedMethods = parentConfig.excludedMethods;
threadDumpSignal = parentConfig.threadDumpSignal;
updateNativeENVEnabled = parentConfig.updateNativeENVEnabled;
classCache = new ClassCache<Script>(loader, jitMax);
try {
environment = System.getenv();
} catch (SecurityException se) {
environment = new HashMap();
}
}
public LoadService createLoadService(Ruby runtime) {
return creator.create(runtime);
}
@Deprecated
public String getBasicUsageHelp() {
return OutputStrings.getBasicUsageHelp();
}
@Deprecated
public String getExtendedHelp() {
return OutputStrings.getExtendedHelp();
}
@Deprecated
public String getPropertyHelp() {
return OutputStrings.getPropertyHelp();
}
@Deprecated
public String getVersionString() {
return OutputStrings.getVersionString(compatVersion);
}
@Deprecated
public String getCopyrightString() {
return OutputStrings.getCopyrightString();
}
public void processArguments(String[] arguments) {
new ArgumentProcessor(arguments, this).processArguments();
tryProcessArgumentsWithRubyopts();
}
public void tryProcessArgumentsWithRubyopts() {
try {
// environment defaults to System.getenv normally
Object rubyoptObj = environment.get("RUBYOPT");
String rubyopt = rubyoptObj == null ? null : rubyoptObj.toString();
if (rubyopt == null || "".equals(rubyopt)) return;
if (rubyopt.split("\\s").length != 0) {
String[] rubyoptArgs = rubyopt.split("\\s+");
new ArgumentProcessor(rubyoptArgs, false, true, this).processArguments();
}
} catch (SecurityException se) {
// ignore and do nothing
}
}
// This method does not work like previous version in verifying it is
// a Ruby shebang line. Looking for ruby before \n is possible to add,
// but I wanted to keep this short.
private boolean isShebang(InputStreamMarkCursor cursor) throws IOException {
if (cursor.read() == '#') {
int c = cursor.read();
if (c == '!') {
cursor.endPoint(-2);
return true;
} else if (c == '\n') {
cursor.rewind();
}
} else {
cursor.rewind();
}
return false;
}
private boolean skipToNextLine(InputStreamMarkCursor cursor) throws IOException {
int c = cursor.read();
do {
if (c == '\n') return true;
} while ((c = cursor.read()) != -1);
return false;
}
private void eatToShebang(InputStream in) {
InputStreamMarkCursor cursor = new InputStreamMarkCursor(in, 8192);
try {
do {
if (isShebang(cursor)) break;
} while (skipToNextLine(cursor));
} catch (IOException e) {
} finally {
try { cursor.finish(); } catch (IOException e) {}
}
}
/**
* The intent here is to gather up any options that might have
* been specified in the shebang line and return them so they can
* be merged into the ones specified on the command-line. This is
* kind of a hopeless task because it's impossible to figure out
* where the command invocation stops and the parameters start.
* We try to work with the common scenarios where /usr/bin/env is
* used to invoke the JRuby shell script, and skip any parameters
* it might have. Then we look for the interpreter invocation and
* assume that the binary will have the word "ruby" in the name.
* This is error prone but should cover more cases than the
* previous code.
*/
public String[] parseShebangOptions(InputStream in) {
BufferedReader reader = null;
String[] result = new String[0];
if (in == null) return result;
if (isXFlag()) eatToShebang(in);
try {
InputStreamMarkCursor cursor = new InputStreamMarkCursor(in, 8192);
try {
if (!isShebang(cursor)) return result;
} finally {
cursor.finish();
}
in.mark(8192);
reader = new BufferedReader(new InputStreamReader(in, "iso-8859-1"), 8192);
String firstLine = reader.readLine();
boolean usesEnv = false;
if (firstLine.length() > 2 && firstLine.charAt(0) == '#' && firstLine.charAt(1) == '!') {
String[] options = firstLine.substring(2).split("\\s+");
int i;
for (i = 0; i < options.length; i++) {
// Skip /usr/bin/env if it's first
if (i == 0 && options[i].endsWith("/env")) {
usesEnv = true;
continue;
}
// Skip any assignments if /usr/bin/env is in play
if (usesEnv && options[i].indexOf('=') > 0) continue;
// Skip any commandline args if /usr/bin/env is in play
if (usesEnv && options[i].startsWith("-")) continue;
String basename = (new File(options[i])).getName();
if (basename.indexOf("ruby") > 0) break;
}
setHasShebangLine(true);
System.arraycopy(options, i, result, 0, options.length - i);
} else {
// No shebang line found
setHasShebangLine(false);
}
} catch (Exception ex) {
// ignore error
} finally {
try {
in.reset();
} catch (IOException ex) {}
}
return result;
}
private static final Pattern RUBY_SHEBANG = Pattern.compile("#!.*ruby.*");
protected static boolean isRubyShebangLine(String line) {
return RUBY_SHEBANG.matcher(line).matches();
}
private String calculateJRubyHome() {
String newJRubyHome = null;
// try the normal property first
if (!Ruby.isSecurityRestricted()) {
newJRubyHome = SafePropertyAccessor.getProperty("jruby.home");
}
if (newJRubyHome != null) {
// verify it if it's there
newJRubyHome = verifyHome(newJRubyHome, error);
} else {
try {
newJRubyHome = SystemPropertyCatcher.findFromJar(this);
} catch (Exception e) {}
if (newJRubyHome != null) {
// verify it if it's there
newJRubyHome = verifyHome(newJRubyHome, error);
} else {
// otherwise fall back on system temp location
newJRubyHome = SafePropertyAccessor.getProperty("java.io.tmpdir");
}
}
return newJRubyHome;
}
// We require the home directory to be absolute
private static String verifyHome(String home, PrintStream error) {
if (home.equals(".")) {
home = SafePropertyAccessor.getProperty("user.dir");
}
if (home.startsWith("cp:")) {
home = home.substring(3);
} else if (!home.startsWith("file:") && !home.startsWith("classpath:")) {
NormalizedFile f = new NormalizedFile(home);
if (!f.isAbsolute()) {
home = f.getAbsolutePath();
}
if (!f.exists()) {
error.println("Warning: JRuby home \"" + f + "\" does not exist, using " + SafePropertyAccessor.getProperty("java.io.tmpdir"));
return System.getProperty("java.io.tmpdir");
}
}
return home;
}
/** Indicates whether the JVM process' native environment will be updated when ENV[...] is set from Ruby. */
public boolean isUpdateNativeENVEnabled() {
return updateNativeENVEnabled;
}
/** Ensure that the JVM process' native environment will be updated when ENV is modified .*/
public void setUpdateNativeENVEnabled(boolean updateNativeENVEnabled) {
this.updateNativeENVEnabled = updateNativeENVEnabled;
}
public byte[] inlineScript() {
return inlineScript.toString().getBytes();
}
public InputStream getScriptSource() {
try {
// KCode.NONE is used because KCODE does not affect parse in Ruby 1.8
// if Ruby 2.0 encoding pragmas are implemented, this will need to change
if (hasInlineScript) {
return new ByteArrayInputStream(inlineScript());
} else if (isSourceFromStdin()) {
// can't use -v and stdin
if (isShowVersion()) {
return null;
}
return getInput();
} else {
String script = getScriptFileName();
InputStream stream = null;
if (script.startsWith("file:") && script.indexOf(".jar!/") != -1) {
stream = new URL("jar:" + script).openStream();
} else if (script.startsWith("classpath:")) {
stream = Ruby.getClassLoader().getResourceAsStream(script.substring("classpath:".length()));
} else {
File file = JRubyFile.create(getCurrentDirectory(), getScriptFileName());
if (isXFlag()) {
// search for a shebang line and
// return the script between shebang and __END__ or CTRL-Z (0x1A)
return findScript(file);
}
stream = new FileInputStream(file);
}
return new BufferedInputStream(stream, 8192);
}
} catch (IOException e) {
// We haven't found any file directly on the file system,
// now check for files inside the JARs.
InputStream is = getJarScriptSource(scriptFileName);
if (is != null) {
return new BufferedInputStream(is, 8129);
}
throw new MainExitException(1, "Error opening script file: " + e.getMessage());
}
}
private static InputStream findScript(File file) throws IOException {
StringBuffer buf = new StringBuffer();
BufferedReader br = new BufferedReader(new FileReader(file));
String currentLine = br.readLine();
while (currentLine != null && !isRubyShebangLine(currentLine)) {
currentLine = br.readLine();
}
buf.append(currentLine);
buf.append("\n");
do {
currentLine = br.readLine();
if (currentLine != null) {
buf.append(currentLine);
buf.append("\n");
}
} while (!(currentLine == null || currentLine.contains("__END__") || currentLine.contains("\026")));
return new BufferedInputStream(new ByteArrayInputStream(buf.toString().getBytes()), 8192);
}
private static InputStream getJarScriptSource(String scriptFileName) {
boolean looksLikeJarURL = scriptFileName.startsWith("file:") && scriptFileName.indexOf("!/") != -1;
if (!looksLikeJarURL) {
return null;
}
String before = scriptFileName.substring("file:".length(), scriptFileName.indexOf("!/"));
String after = scriptFileName.substring(scriptFileName.indexOf("!/") + 2);
try {
JarFile jFile = new JarFile(before);
JarEntry entry = jFile.getJarEntry(after);
if (entry != null && !entry.isDirectory()) {
return jFile.getInputStream(entry);
}
} catch (IOException ignored) {
}
return null;
}
public String displayedFileName() {
if (hasInlineScript) {
if (scriptFileName != null) {
return scriptFileName;
} else {
return "-e";
}
} else if (isSourceFromStdin()) {
return "-";
} else {
return getScriptFileName();
}
}
public ASTCompiler newCompiler() {
if (getCompatVersion() == CompatVersion.RUBY1_8) {
return new ASTCompiler();
} else {
return new ASTCompiler19();
}
}
////////////////////////////////////////////////////////////////////////////
// Static utilities and global state management methods.
////////////////////////////////////////////////////////////////////////////
public static boolean hasLoadedNativeExtensions() {
return loadedNativeExtensions;
}
public static void setLoadedNativeExtensions(boolean loadedNativeExtensions) {
RubyInstanceConfig.loadedNativeExtensions = loadedNativeExtensions;
}
////////////////////////////////////////////////////////////////////////////
// Getters and setters for config settings.
////////////////////////////////////////////////////////////////////////////
public LoadServiceCreator getLoadServiceCreator() {
return creator;
}
public void setLoadServiceCreator(LoadServiceCreator creator) {
this.creator = creator;
}
public String getJRubyHome() {
if (jrubyHome == null) {
jrubyHome = calculateJRubyHome();
}
return jrubyHome;
}
public void setJRubyHome(String home) {
jrubyHome = verifyHome(home, error);
}
public CompileMode getCompileMode() {
return compileMode;
}
public void setCompileMode(CompileMode compileMode) {
this.compileMode = compileMode;
}
public boolean isJitLogging() {
return jitLogging;
}
public boolean isJitDumping() {
return jitDumping;
}
public boolean isJitLoggingVerbose() {
return jitLoggingVerbose;
}
public int getJitLogEvery() {
return jitLogEvery;
}
public void setJitLogEvery(int jitLogEvery) {
this.jitLogEvery = jitLogEvery;
}
public boolean isSamplingEnabled() {
return samplingEnabled;
}
public int getJitThreshold() {
return jitThreshold;
}
public void setJitThreshold(int jitThreshold) {
this.jitThreshold = jitThreshold;
}
public int getJitMax() {
return jitMax;
}
public void setJitMax(int jitMax) {
this.jitMax = jitMax;
}
public int getJitMaxSize() {
return jitMaxSize;
}
public void setJitMaxSize(int jitMaxSize) {
this.jitMaxSize = jitMaxSize;
}
public boolean isRunRubyInProcess() {
return runRubyInProcess;
}
public void setRunRubyInProcess(boolean flag) {
this.runRubyInProcess = flag;
}
public void setInput(InputStream newInput) {
input = newInput;
}
public InputStream getInput() {
return input;
}
public CompatVersion getCompatVersion() {
return compatVersion;
}
public void setCompatVersion(CompatVersion compatVersion) {
if (compatVersion == null) compatVersion = CompatVersion.RUBY1_8;
this.compatVersion = compatVersion;
}
public void setOutput(PrintStream newOutput) {
output = newOutput;
}
public PrintStream getOutput() {
return output;
}
public void setError(PrintStream newError) {
error = newError;
}
public PrintStream getError() {
return error;
}
public void setCurrentDirectory(String newCurrentDirectory) {
currentDirectory = newCurrentDirectory;
}
public String getCurrentDirectory() {
return currentDirectory;
}
public void setProfile(Profile newProfile) {
profile = newProfile;
}
public Profile getProfile() {
return profile;
}
public void setObjectSpaceEnabled(boolean newObjectSpaceEnabled) {
objectSpaceEnabled = newObjectSpaceEnabled;
}
public boolean isObjectSpaceEnabled() {
return objectSpaceEnabled;
}
public void setSiphashEnabled(boolean newSiphashEnabled) {
siphashEnabled = newSiphashEnabled;
}
public boolean isSiphashEnabled() {
return siphashEnabled;
}
public void setEnvironment(Map newEnvironment) {
if (newEnvironment == null) newEnvironment = new HashMap();
environment = newEnvironment;
}
public Map getEnvironment() {
return environment;
}
public ClassLoader getLoader() {
return loader;
}
public void setLoader(ClassLoader loader) {
// Setting the loader needs to reset the class cache
if(this.loader != loader) {
this.classCache = new ClassCache<Script>(loader, this.classCache.getMax());
}
this.loader = loader;
}
public String[] getArgv() {
return argv;
}
public void setArgv(String[] argv) {
this.argv = argv;
}
public StringBuffer getInlineScript() {
return inlineScript;
}
public void setHasInlineScript(boolean hasInlineScript) {
this.hasInlineScript = hasInlineScript;
}
public boolean hasInlineScript() {
return hasInlineScript;
}
public Collection<String> getRequiredLibraries() {
return requiredLibraries;
}
@Deprecated
public Collection<String> requiredLibraries() {
return requiredLibraries;
}
public List<String> getLoadPaths() {
return loadPaths;
}
@Deprecated
public List<String> loadPaths() {
return loadPaths;
}
public void setLoadPaths(List<String> loadPaths) {
this.loadPaths = loadPaths;
}
public void setShouldPrintUsage(boolean shouldPrintUsage) {
this.shouldPrintUsage = shouldPrintUsage;
}
public boolean getShouldPrintUsage() {
return shouldPrintUsage;
}
@Deprecated
public boolean shouldPrintUsage() {
return shouldPrintUsage;
}
public void setShouldPrintProperties(boolean shouldPrintProperties) {
this.shouldPrintProperties = shouldPrintProperties;
}
public boolean getShouldPrintProperties() {
return shouldPrintProperties;
}
@Deprecated
public boolean shouldPrintProperties() {
return shouldPrintProperties;
}
public boolean isInlineScript() {
return hasInlineScript;
}
private boolean isSourceFromStdin() {
return getScriptFileName() == null;
}
public void setScriptFileName(String scriptFileName) {
this.scriptFileName = scriptFileName;
}
public String getScriptFileName() {
return scriptFileName;
}
public void setBenchmarking(boolean benchmarking) {
this.benchmarking = benchmarking;
}
public boolean isBenchmarking() {
return benchmarking;
}
public void setAssumeLoop(boolean assumeLoop) {
this.assumeLoop = assumeLoop;
}
public boolean isAssumeLoop() {
return assumeLoop;
}
public void setAssumePrinting(boolean assumePrinting) {
this.assumePrinting = assumePrinting;
}
public boolean isAssumePrinting() {
return assumePrinting;
}
public void setProcessLineEnds(boolean processLineEnds) {
this.processLineEnds = processLineEnds;
}
public boolean isProcessLineEnds() {
return processLineEnds;
}
public void setSplit(boolean split) {
this.split = split;
}
public boolean isSplit() {
return split;
}
public Verbosity getVerbosity() {
return verbosity;
}
public void setVerbosity(Verbosity verbosity) {
this.verbosity = verbosity;
}
public boolean isVerbose() {
return verbosity == Verbosity.TRUE;
}
@Deprecated
public Boolean getVerbose() {
return isVerbose();
}
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
public boolean isParserDebug() {
return parserDebug;
}
public boolean isShowVersion() {
return showVersion;
}
public boolean isShowBytecode() {
return showBytecode;
}
public boolean isShowCopyright() {
return showCopyright;
}
public void setShowVersion(boolean showVersion) {
this.showVersion = showVersion;
}
public void setShowBytecode(boolean showBytecode) {
this.showBytecode = showBytecode;
}
public void setShowCopyright(boolean showCopyright) {
this.showCopyright = showCopyright;
}
public void setShouldRunInterpreter(boolean shouldRunInterpreter) {
this.shouldRunInterpreter = shouldRunInterpreter;
}
public boolean getShouldRunInterpreter() {
return shouldRunInterpreter;
}
@Deprecated
public boolean shouldRunInterpreter() {
return isShouldRunInterpreter();
}
@Deprecated
public boolean isShouldRunInterpreter() {
return shouldRunInterpreter;
}
public void setShouldCheckSyntax(boolean shouldSetSyntax) {
this.shouldCheckSyntax = shouldSetSyntax;
}
public boolean getShouldCheckSyntax() {
return shouldCheckSyntax;
}
public void setInputFieldSeparator(String inputFieldSeparator) {
this.inputFieldSeparator = inputFieldSeparator;
}
public String getInputFieldSeparator() {
return inputFieldSeparator;
}
public KCode getKCode() {
return kcode;
}
public void setKCode(KCode kcode) {
this.kcode = kcode;
}
public void setInternalEncoding(String internalEncoding) {
this.internalEncoding = internalEncoding;
}
public String getInternalEncoding() {
return internalEncoding;
}
public void setExternalEncoding(String externalEncoding) {
this.externalEncoding = externalEncoding;
}
public String getExternalEncoding() {
return externalEncoding;
}
public void setRecordSeparator(String recordSeparator) {
this.recordSeparator = recordSeparator;
}
public String getRecordSeparator() {
return recordSeparator;
}
public int getSafeLevel() {
return 0;
}
public ClassCache getClassCache() {
return classCache;
}
public void setInPlaceBackupExtension(String inPlaceBackupExtension) {
this.inPlaceBackupExtension = inPlaceBackupExtension;
}
public String getInPlaceBackupExtension() {
return inPlaceBackupExtension;
}
public void setClassCache(ClassCache classCache) {
this.classCache = classCache;
}
public Map getOptionGlobals() {
return optionGlobals;
}
public boolean isManagementEnabled() {
return managementEnabled;
}
public Set getExcludedMethods() {
return excludedMethods;
}
public void setParserDebug(boolean parserDebug) {
this.parserDebug = parserDebug;
}
public boolean getParserDebug() {
return parserDebug;
}
public boolean isArgvGlobalsOn() {
return argvGlobalsOn;
}
public void setArgvGlobalsOn(boolean argvGlobalsOn) {
this.argvGlobalsOn = argvGlobalsOn;
}
public String getThreadDumpSignal() {
return threadDumpSignal;
}
public boolean isHardExit() {
return hardExit;
}
public void setHardExit(boolean hardExit) {
this.hardExit = hardExit;
}
public boolean isProfiling() {
return profilingMode != ProfilingMode.OFF;
}
public boolean isProfilingEntireRun() {
return profilingMode != ProfilingMode.OFF && profilingMode != ProfilingMode.API;
}
public void setProfilingMode(ProfilingMode profilingMode) {
this.profilingMode = profilingMode;
}
public ProfilingMode getProfilingMode() {
return profilingMode;
}
public void setProfileOutput(ProfileOutput output) {
this.profileOutput = output;
}
public ProfileOutput getProfileOutput() {
return profileOutput;
}
public boolean hasShebangLine() {
return hasShebangLine;
}
public void setHasShebangLine(boolean hasShebangLine) {
this.hasShebangLine = hasShebangLine;
}
public boolean isDisableGems() {
return disableGems;
}
public void setDisableGems(boolean dg) {
this.disableGems = dg;
}
public TraceType getTraceType() {
return traceType;
}
public void setTraceType(TraceType traceType) {
this.traceType = traceType;
}
/**
* Whether to mask .java lines in the Ruby backtrace, as MRI does for C calls.
*
* @return true if masking; false otherwise
*/
public boolean getBacktraceMask() {
return backtraceMask;
}
/**
* Set whether to mask .java lines in the Ruby backtrace.
*
* @param backtraceMask true to mask; false otherwise
*/
public void setBacktraceMask(boolean backtraceMask) {
this.backtraceMask = backtraceMask;
}
/**
* Set whether native code is enabled for this config. Disabling it also
* disables C extensions (@see RubyInstanceConfig#setCextEnabled).
*
* @param b new value indicating whether native code is enabled
*/
public void setNativeEnabled(boolean b) {
_nativeEnabled = false;
}
/**
* Get whether native code is enabled for this config.
*
* @return true if native code is enabled; false otherwise.
*/
public boolean isNativeEnabled() {
return _nativeEnabled;
}
/**
* Set whether C extensions are enabled for this config.
*
* @param b new value indicating whether native code is enabled
*/
public void setCextEnabled(boolean b) {
_cextEnabled = b;
}
/**
* Get whether C extensions are enabled for this config.
*
* @return true if C extensions are enabled; false otherwise.
*/
public boolean isCextEnabled() {
return _cextEnabled;
}
public void setXFlag(boolean xFlag) {
this.xFlag = xFlag;
}
public boolean isXFlag() {
return xFlag;
}
@Deprecated
public boolean isxFlag() {
return xFlag;
}
/**
* True if colorized backtraces are enabled. False otherwise.
*/
public boolean getBacktraceColor() {
return backtraceColor;
}
/**
* Set to true to enable colorized backtraces.
*/
public void setBacktraceColor(boolean backtraceColor) {
this.backtraceColor = backtraceColor;
}
/**
* Whether to use a single global lock for requires.
* @see Options.GLOBAL_REQUIRE_LOCK
*/
public boolean isGlobalRequireLock() {
return globalRequireLock;
}
/**
* Set whether to use a single global lock for requires.
*/
public void setGlobalRequireLock(boolean globalRequireLock) {
this.globalRequireLock = globalRequireLock;
}
/**
* Set whether the JIT compiler should run in a background thread (Executor-based).
*
* @param jitBackground whether to run the JIT compiler in a background thread
*/
public void setJitBackground(boolean jitBackground) {
this.jitBackground = jitBackground;
}
/**
* Get whether the JIT compiler will run in a background thread.
*
* @return whether the JIT compiler will run in a background thread
*/
public boolean getJitBackground() {
return jitBackground;
}
/**
* Set whether to load and setup bundler on startup.
*/
public void setLoadGemfile(boolean loadGemfile) {
this.loadGemfile = loadGemfile;
}
/**
* Whether to load and setup bundler on startup.
*/
public boolean getLoadGemfile() {
return loadGemfile;
}
/**
* Set the maximum number of methods to consider when profiling.
*/
public void setProfileMaxMethods(int profileMaxMethods) {
this.profileMaxMethods = profileMaxMethods;
}
/**
* Get the maximum number of methods to consider when profiling.
*/
public int getProfileMaxMethods() {
return profileMaxMethods;
}
////////////////////////////////////////////////////////////////////////////
// Configuration fields.
////////////////////////////////////////////////////////////////////////////
/**
* Indicates whether the script must be extracted from script source
*/
private boolean xFlag;
/**
* Indicates whether the script has a shebang line or not
*/
private boolean hasShebangLine;
private InputStream input = System.in;
private PrintStream output = System.out;
private PrintStream error = System.err;
private Profile profile = Profile.DEFAULT;
private boolean objectSpaceEnabled = Options.OBJECTSPACE_ENABLED.load();
private boolean siphashEnabled = Options.SIPHASH_ENABLED.load();
private CompileMode compileMode = CompileMode.JIT;
private boolean runRubyInProcess = true;
private String currentDirectory;
/** Environment variables; defaults to System.getenv() in constructor */
private Map environment;
private String[] argv = {};
private final boolean jitLogging;
private final boolean jitDumping;
private final boolean jitLoggingVerbose;
private int jitLogEvery;
private int jitThreshold;
private int jitMax;
private int jitMaxSize;
private final boolean samplingEnabled;
private CompatVersion compatVersion;
private String internalEncoding = null;
private String externalEncoding = null;
private ProfilingMode profilingMode = ProfilingMode.OFF;
private ProfileOutput profileOutput = new ProfileOutput(System.err);
private ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
private ClassLoader loader = contextLoader == null ? RubyInstanceConfig.class.getClassLoader() : contextLoader;
private ClassCache<Script> classCache;
// from CommandlineParser
private List<String> loadPaths = new ArrayList<String>();
private Set<String> excludedMethods = new HashSet<String>();
private StringBuffer inlineScript = new StringBuffer();
private boolean hasInlineScript = false;
private String scriptFileName = null;
private Collection<String> requiredLibraries = new LinkedHashSet<String>();
private boolean benchmarking = false;
private boolean argvGlobalsOn = false;
private boolean assumeLoop = false;
private boolean assumePrinting = false;
private Map optionGlobals = new HashMap();
private boolean processLineEnds = false;
private boolean split = false;
private Verbosity verbosity = Verbosity.FALSE;
private boolean debug = false;
private boolean showVersion = false;
private boolean showBytecode = false;
private boolean showCopyright = false;
private boolean shouldRunInterpreter = true;
private boolean shouldPrintUsage = false;
private boolean shouldPrintProperties=false;
private boolean dumpConfig=false;
private KCode kcode = KCode.NONE;
private String recordSeparator = "\n";
private boolean shouldCheckSyntax = false;
private String inputFieldSeparator = null;
private boolean managementEnabled = false;
private String inPlaceBackupExtension = null;
private boolean parserDebug = false;
private String threadDumpSignal = null;
private boolean hardExit = false;
private boolean disableGems = false;
private boolean updateNativeENVEnabled = true;
private String jrubyHome;
/**
* Whether native code is enabled for this configuration.
*/
private boolean _nativeEnabled = NATIVE_ENABLED;
/**
* Whether C extensions are enabled for this configuration.
*/
private boolean _cextEnabled = CEXT_ENABLED;
private TraceType traceType =
TraceType.traceTypeFor(Options.BACKTRACE_STYLE.load());
private boolean backtraceMask = Options.BACKTRACE_MASK.load();
private boolean backtraceColor = Options.BACKTRACE_COLOR.load();
private LoadServiceCreator creator = LoadServiceCreator.DEFAULT;
private boolean globalRequireLock = Options.GLOBAL_REQUIRE_LOCK.load();
private boolean jitBackground = Options.JIT_BACKGROUND.load();
private boolean loadGemfile = false;
private int profileMaxMethods = Options.PROFILE_MAX_METHODS.load();
////////////////////////////////////////////////////////////////////////////
// Support classes, etc.
////////////////////////////////////////////////////////////////////////////
public enum Verbosity { NIL, FALSE, TRUE }
public static interface LoadServiceCreator {
LoadService create(Ruby runtime);
LoadServiceCreator DEFAULT = new LoadServiceCreator() {
public LoadService create(Ruby runtime) {
if (runtime.is1_9()) {
return new LoadService19(runtime);
}
return new LoadService(runtime);
}
};
}
public enum ProfilingMode {
OFF, API, FLAT, GRAPH, HTML, JSON
}
public enum CompileMode {
JIT, FORCE, FORCEIR, OFF, OFFIR;
public boolean shouldPrecompileCLI() {
switch (this) {
case JIT: case FORCE: case FORCEIR:
return true;
}
return false;
}
public boolean shouldJIT() {
switch (this) {
case JIT: case FORCE: case FORCEIR:
return true;
}
return false;
}
public boolean shouldPrecompileAll() {
return this == FORCE;
}
}
////////////////////////////////////////////////////////////////////////////
// Static configuration fields, used as defaults for new JRuby instances.
////////////////////////////////////////////////////////////////////////////
/**
* The max count of active methods eligible for JIT-compilation.
*/
@Deprecated
public static final int JIT_MAX_METHODS_LIMIT = Constants.JIT_MAX_METHODS_LIMIT;
/**
* The max size of JIT-compiled methods (full class size) allowed.
*/
@Deprecated
public static final int JIT_MAX_SIZE_LIMIT = Constants.JIT_MAX_SIZE_LIMIT;
/**
* The JIT threshold to the specified method invocation count.
*/
@Deprecated
public static final int JIT_THRESHOLD = Constants.JIT_THRESHOLD;
/**
* The version to use for generated classes. Set to current JVM version by default
*/
public static final int JAVA_VERSION = initGlobalJavaVersion();
/**
* Default size for chained compilation.
*/
@Deprecated
public static final int CHAINED_COMPILE_LINE_COUNT_DEFAULT = Constants.CHAINED_COMPILE_LINE_COUNT_DEFAULT;
/**
* The number of lines at which a method, class, or block body is split into
* chained methods (to dodge 64k method-size limit in JVM).
*/
public static final int CHAINED_COMPILE_LINE_COUNT = Options.COMPILE_CHAINSIZE.load();
/**
* Enable compiler peephole optimizations.
*
* Set with the <tt>jruby.compile.peephole</tt> system property.
*/
public static final boolean PEEPHOLE_OPTZ = Options.COMPILE_PEEPHOLE.load();
/**
* Enable compiler "noguards" optimizations.
*
* Set with the <tt>jruby.compile.noguards</tt> system property.
*/
public static boolean NOGUARDS_COMPILE_ENABLED = Options.COMPILE_NOGUARDS.load();
/**
* Enable compiler "fastest" set of optimizations.
*
* Set with the <tt>jruby.compile.fastest</tt> system property.
*/
public static boolean FASTEST_COMPILE_ENABLED = Options.COMPILE_FASTEST.load();
/**
* Enable fast operator compiler optimizations.
*
* Set with the <tt>jruby.compile.fastops</tt> system property.
*/
public static boolean FASTOPS_COMPILE_ENABLED
= FASTEST_COMPILE_ENABLED || Options.COMPILE_FASTOPS.load();
/**
* Enable "threadless" compile.
*
* Set with the <tt>jruby.compile.threadless</tt> system property.
*/
public static boolean THREADLESS_COMPILE_ENABLED
= FASTEST_COMPILE_ENABLED || Options.COMPILE_THREADLESS.load();
/**
* Enable "fast send" compiler optimizations.
*
* Set with the <tt>jruby.compile.fastsend</tt> system property.
*/
public static boolean FASTSEND_COMPILE_ENABLED
= FASTEST_COMPILE_ENABLED || Options.COMPILE_FASTSEND.load();
/**
* Enable lazy handles optimizations.
*
* Set with the <tt>jruby.compile.lazyHandles</tt> system property.
*/
public static boolean LAZYHANDLES_COMPILE = Options.COMPILE_LAZYHANDLES.load();
/**
* Enable fast multiple assignment optimization.
*
* Set with the <tt>jruby.compile.fastMasgn</tt> system property.
*/
public static boolean FAST_MULTIPLE_ASSIGNMENT = Options.COMPILE_FASTMASGN.load();
/**
* Enable a thread pool. Each Ruby thread will be mapped onto a thread from this pool.
*
* Set with the <tt>jruby.thread.pool.enabled</tt> system property.
*/
public static final boolean POOLING_ENABLED = Options.THREADPOOL_ENABLED.load();
/**
* Maximum thread pool size (integer, default Integer.MAX_VALUE).
*
* Set with the <tt>jruby.thread.pool.max</tt> system property.
*/
public static final int POOL_MAX = Options.THREADPOOL_MAX.load();
/**
* Minimum thread pool size (integer, default 0).
*
* Set with the <tt>jruby.thread.pool.min</tt> system property.
*/
public static final int POOL_MIN = Options.THREADPOOL_MIN.load();
/**
* Thread pool time-to-live in seconds.
*
* Set with the <tt>jruby.thread.pool.max</tt> system property.
*/
public static final int POOL_TTL = Options.THREADPOOL_TTL.load();
/**
* Enable use of the native Java version of the 'net/protocol' library.
*
* Set with the <tt>jruby.thread.pool.max</tt> system property.
*/
public static final boolean NATIVE_NET_PROTOCOL = Options.NATIVE_NET_PROTOCOL.load();
/**
* Enable tracing of method calls.
*
* Set with the <tt>jruby.debug.fullTrace</tt> system property.
*/
public static boolean FULL_TRACE_ENABLED = Options.DEBUG_FULLTRACE.load();
/**
* Comma-separated list of methods to exclude from JIT compilation.
* Specify as "Module", "Module#method" or "method".
*
* Set with the <tt>jruby.jit.exclude</tt> system property.
*/
public static final String COMPILE_EXCLUDE = Options.JIT_EXCLUDE.load();
/**
* Indicates the global default for whether native code is enabled. Default
* is true. This value is used to default new runtime configurations.
*
* Set with the <tt>jruby.native.enabled</tt> system property.
*/
public static final boolean NATIVE_ENABLED = Options.NATIVE_ENABLED.load();
@Deprecated
public static final boolean nativeEnabled = NATIVE_ENABLED;
/**
* Indicates the global default for whether C extensions are enabled.
* Default is the value of RubyInstanceConfig.NATIVE_ENABLED. This value
* is used to default new runtime configurations.
*
* Set with the <tt>jruby.cext.enabled</tt> system property.
*/
public final static boolean CEXT_ENABLED = Options.CEXT_ENABLED.load();
/**
* Whether to reify (pre-compile and generate) a Java class per Ruby class.
*
* Set with the <tt>jruby.reify.classes</tt> system property.
*/
public static final boolean REIFY_RUBY_CLASSES = Options.REIFY_CLASSES.load();
/**
* Log errors that occur during reification.
*
* Set with the <tt>jruby.reify.logErrors</tt> system property.
*/
public static final boolean REIFY_LOG_ERRORS = Options.REIFY_LOGERRORS.load();
/**
* Whether to use a custom-generated handle for Java methods instead of
* reflection.
*
* Set with the <tt>jruby.java.handles</tt> system property.
*/
public static final boolean USE_GENERATED_HANDLES = Options.JAVA_HANDLES.load();
/**
* Turn on debugging of the load service (requires and loads).
*
* Set with the <tt>jruby.debug.loadService</tt> system property.
*/
public static final boolean DEBUG_LOAD_SERVICE = Options.DEBUG_LOADSERVICE.load();
/**
* Turn on timings of the load service (requires and loads).
*
* Set with the <tt>jruby.debug.loadService.timing</tt> system property.
*/
public static final boolean DEBUG_LOAD_TIMINGS = Options.DEBUG_LOADSERVICE_TIMING.load();
/**
* Turn on debugging of subprocess launching.
*
* Set with the <tt>jruby.debug.launch</tt> system property.
*/
public static final boolean DEBUG_LAUNCHING = Options.DEBUG_LAUNCH.load();
/**
* Turn on debugging of script resolution with "-S".
*
* Set with the <tt>jruby.debug.scriptResolution</tt> system property.
*/
public static final boolean DEBUG_SCRIPT_RESOLUTION = Options.DEBUG_SCRIPTRESOLUTION.load();
public static final boolean DEBUG_PARSER = Options.DEBUG_PARSER.load();
public static final boolean JUMPS_HAVE_BACKTRACE = Options.JUMP_BACKTRACE.load();
public static final boolean JIT_CACHE_ENABLED = Options.JIT_CACHE.load();
public static final String JIT_CODE_CACHE = Options.JIT_CODECACHE.load();
public static final boolean REFLECTED_HANDLES = Options.REFLECTED_HANDLES.load();
public static final boolean NO_UNWRAP_PROCESS_STREAMS = Options.PROCESS_NOUNWRAP.load();
public static final boolean INTERFACES_USE_PROXY = Options.INTERFACES_USEPROXY.load();
public static final boolean JIT_LOADING_DEBUG = Options.JIT_DEBUG.load();
public static final boolean CAN_SET_ACCESSIBLE = Options.JI_SETACCESSIBLE.load();
/**
* In Java integration, allow upper case name for a Java package;
* e.g., com.example.UpperCase.Class
*/
public static final boolean UPPER_CASE_PACKAGE_NAME_ALLOWED = Options.JI_UPPER_CASE_PACKAGE_NAME_ALLOWED.load();
public static final boolean USE_INVOKEDYNAMIC = Options.COMPILE_INVOKEDYNAMIC.load();
// max times an indy call site can fail before it goes to simple IC
public static final int MAX_FAIL_COUNT = Options.INVOKEDYNAMIC_MAXFAIL.load();
// max polymorphism at a call site to build a chained method handle PIC
public static final int MAX_POLY_COUNT = Options.INVOKEDYNAMIC_MAXPOLY.load();
// logging of various indy aspects
public static final boolean LOG_INDY_BINDINGS = Options.INVOKEDYNAMIC_LOG_BINDING.load();
public static final boolean LOG_INDY_CONSTANTS = Options.INVOKEDYNAMIC_LOG_CONSTANTS.load();
// properties enabling or disabling certain uses of invokedynamic
public static final boolean INVOKEDYNAMIC_ALL = USE_INVOKEDYNAMIC && Options.INVOKEDYNAMIC_ALL.load();
public static final boolean INVOKEDYNAMIC_SAFE = USE_INVOKEDYNAMIC && Options.INVOKEDYNAMIC_SAFE.load();
public static final boolean INVOKEDYNAMIC_INVOCATION = INVOKEDYNAMIC_ALL || INVOKEDYNAMIC_SAFE ||
USE_INVOKEDYNAMIC && Options.INVOKEDYNAMIC_INVOCATION.load();
public static final boolean INVOKEDYNAMIC_INVOCATION_SWITCHPOINT = INVOKEDYNAMIC_ALL || INVOKEDYNAMIC_SAFE ||
USE_INVOKEDYNAMIC && Options.INVOKEDYNAMIC_INVOCATION_SWITCHPOINT.load();
public static final boolean INVOKEDYNAMIC_INDIRECT = INVOKEDYNAMIC_ALL || INVOKEDYNAMIC_SAFE ||
USE_INVOKEDYNAMIC && INVOKEDYNAMIC_INVOCATION && Options.INVOKEDYNAMIC_INVOCATION_INDIRECT.load();
public static final boolean INVOKEDYNAMIC_JAVA = INVOKEDYNAMIC_ALL ||
USE_INVOKEDYNAMIC && INVOKEDYNAMIC_INVOCATION && Options.INVOKEDYNAMIC_INVOCATION_JAVA.load();
public static final boolean INVOKEDYNAMIC_ATTR = INVOKEDYNAMIC_ALL || INVOKEDYNAMIC_SAFE ||
USE_INVOKEDYNAMIC && INVOKEDYNAMIC_INVOCATION && Options.INVOKEDYNAMIC_INVOCATION_ATTR.load();
public static final boolean INVOKEDYNAMIC_FASTOPS = INVOKEDYNAMIC_ALL || INVOKEDYNAMIC_SAFE ||
USE_INVOKEDYNAMIC && INVOKEDYNAMIC_INVOCATION && Options.INVOKEDYNAMIC_INVOCATION_FASTOPS.load();
public static final boolean INVOKEDYNAMIC_CACHE = INVOKEDYNAMIC_ALL || INVOKEDYNAMIC_SAFE ||
USE_INVOKEDYNAMIC && Options.INVOKEDYNAMIC_CACHE.load();
public static final boolean INVOKEDYNAMIC_CONSTANTS = INVOKEDYNAMIC_ALL || INVOKEDYNAMIC_SAFE ||
USE_INVOKEDYNAMIC && INVOKEDYNAMIC_CACHE && Options.INVOKEDYNAMIC_CACHE_CONSTANTS.load();
public static final boolean INVOKEDYNAMIC_LITERALS = INVOKEDYNAMIC_ALL || INVOKEDYNAMIC_SAFE ||
USE_INVOKEDYNAMIC && INVOKEDYNAMIC_CACHE && Options.INVOKEDYNAMIC_CACHE_LITERALS.load();
public static final boolean INVOKEDYNAMIC_IVARS = INVOKEDYNAMIC_ALL || INVOKEDYNAMIC_SAFE ||
USE_INVOKEDYNAMIC && INVOKEDYNAMIC_CACHE && Options.INVOKEDYNAMIC_CACHE_IVARS.load();
// properties for logging exceptions, backtraces, and caller invocations
public static final boolean LOG_EXCEPTIONS = Options.LOG_EXCEPTIONS.load();
public static final boolean LOG_BACKTRACES = Options.LOG_BACKTRACES.load();
public static final boolean LOG_CALLERS = Options.LOG_CALLERS.load();
public static final boolean LOG_WARNINGS = Options.LOG_WARNINGS.load();
public static final boolean ERRNO_BACKTRACE = Options.ERRNO_BACKTRACE.load();
public static boolean IR_DEBUG = Options.IR_DEBUG.load();
public static boolean IR_PROFILE = Options.IR_PROFILE.load();
public static boolean IR_COMPILER_DEBUG = Options.IR_COMPILER_DEBUG.load();
public static String IR_COMPILER_PASSES = Options.IR_COMPILER_PASSES.load();
public static String IR_INLINE_COMPILER_PASSES = Options.IR_INLINE_COMPILER_PASSES.load();
public static final boolean COROUTINE_FIBERS = Options.FIBER_COROUTINES.load();
private static volatile boolean loadedNativeExtensions = false;
////////////////////////////////////////////////////////////////////////////
// Static initializers
////////////////////////////////////////////////////////////////////////////
private static int initGlobalJavaVersion() {
String specVersion = specVersion = Options.BYTECODE_VERSION.load();
// stack map calculation is failing for some compilation scenarios, so
// forcing both 1.5 and 1.6 to use 1.5 bytecode for the moment.
if (specVersion.equals("1.5")) {// || specVersion.equals("1.6")) {
return Opcodes.V1_5;
} else if (specVersion.equals("1.6")) {
return Opcodes.V1_6;
} else if (specVersion.equals("1.7") || specVersion.equals("1.8")) {
return Opcodes.V1_7;
} else {
throw new RuntimeException("unsupported Java version: " + specVersion);
}
}
@Deprecated
public void setSafeLevel(int safeLevel) {
}
@Deprecated
public String getInPlaceBackupExtention() {
return inPlaceBackupExtension;
}
}