/* **** BEGIN LICENSE BLOCK ***** * Version: EPL 2.0/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Eclipse Public * 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.eclipse.org/legal/epl-v20.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) 2001 Chad Fowler * Copyright (C) 2001 Alan Moore * Copyright (C) 2001-2002 Benoit Cerrina * Copyright (C) 2001-2004 Jan Arne Petersen * Copyright (C) 2002-2004 Anders Bengtsson * Copyright (C) 2004 Thomas E Enebo * Copyright (C) 2004-2005 Charles O Nutter * Copyright (C) 2004 Stefan Matthias Aust * Copyright (C) 2006 Miguel Covarrubias * Copyright (C) 2006 Michael Studman * Copyright (C) 2006 Ola Bini * Copyright (C) 2007 Nick Sieger * * 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 EPL, 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 EPL, the GPL or the LGPL. ***** END LICENSE BLOCK *****/ package org.jruby; import org.jcodings.specific.UTF8Encoding; import org.jruby.anno.TypePopulator; import org.jruby.api.Access; import org.jruby.api.Create; import org.jruby.api.Define; import org.jruby.compiler.Constantizable; import org.jruby.compiler.NotCompilableException; import org.jruby.exceptions.LocalJumpError; import org.jruby.exceptions.SystemExit; import org.jruby.ext.jruby.JRubyUtilLibrary; import org.jruby.ext.set.RubySet; import org.jruby.ext.thread.ConditionVariable; import org.jruby.ext.thread.Mutex; import org.jruby.ext.thread.Queue; import org.jruby.ext.thread.SizedQueue; import org.jruby.ir.IRScope; import org.jruby.ir.IRScriptBody; import org.jruby.ir.runtime.IRReturnJump; import org.jruby.java.util.ClassUtils; import org.jruby.javasupport.Java; import org.jruby.javasupport.JavaPackage; import org.jruby.javasupport.JavaSupport; import org.jruby.javasupport.JavaSupportImpl; import org.jruby.management.Caches; import org.jruby.management.InlineStats; import org.jruby.parser.ParserManager; import org.jruby.parser.StaticScope; import org.jruby.runtime.Builtins; import org.jruby.runtime.JavaSites; import org.jruby.runtime.TraceEventManager; import org.jruby.runtime.backtrace.RubyStackTraceElement; import org.jruby.runtime.invokedynamic.InvokeDynamicSupport; import org.jruby.specialized.RubyObjectSpecializer; import org.jruby.util.JavaNameMangler; import org.jruby.util.StrptimeParser; import org.jruby.util.StrptimeToken; import org.jruby.util.WeakIdentityHashMap; import org.jruby.util.collections.ConcurrentWeakHashMap; import org.jruby.util.collections.IntHashMap; import org.jruby.util.io.EncodingUtils; import org.objectweb.asm.util.TraceClassVisitor; import jnr.constants.Constant; import jnr.constants.ConstantSet; import jnr.constants.platform.Errno; import jnr.posix.POSIX; import jnr.posix.POSIXFactory; import org.jcodings.Encoding; import org.joda.time.DateTimeZone; import org.joni.WarnCallback; import org.jruby.ast.Node; import org.jruby.ast.RootNode; import org.jruby.ast.executable.RuntimeCache; import org.jruby.ast.executable.Script; import org.jruby.ast.executable.ScriptAndCode; import org.jruby.common.RubyWarnings; import org.jruby.compiler.JITCompiler; import org.jruby.embed.Extension; import org.jruby.exceptions.MainExitException; import org.jruby.exceptions.RaiseException; import org.jruby.ext.JRubyPOSIXHandler; import org.jruby.ext.coverage.CoverageData; import org.jruby.ext.ffi.FFI; import org.jruby.ext.fiber.ThreadFiber; import org.jruby.ext.fiber.ThreadFiberLibrary; import org.jruby.ext.tracepoint.TracePoint; import org.jruby.internal.runtime.GlobalVariables; import org.jruby.internal.runtime.ThreadService; import org.jruby.internal.runtime.ValueAccessor; import org.jruby.internal.runtime.methods.DynamicMethod; import org.jruby.ir.Compiler; import org.jruby.ir.IRManager; import org.jruby.ir.interpreter.Interpreter; import org.jruby.management.BeanManager; import org.jruby.management.BeanManagerFactory; import org.jruby.management.Config; import org.jruby.parser.Parser; import org.jruby.parser.StaticScopeFactory; import org.jruby.platform.Platform; import org.jruby.runtime.Binding; import org.jruby.runtime.Block; import org.jruby.runtime.CallSite; import org.jruby.runtime.ClassIndex; import org.jruby.runtime.DynamicScope; import org.jruby.runtime.EventHook; import org.jruby.runtime.GlobalVariable; import org.jruby.runtime.Helpers; import org.jruby.runtime.IAccessor; import org.jruby.runtime.ObjectAllocator; import org.jruby.runtime.ObjectSpace; import org.jruby.runtime.RubyEvent; import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.encoding.EncodingService; import org.jruby.runtime.invokedynamic.MethodNames; import org.jruby.runtime.load.BasicLibraryService; import org.jruby.runtime.load.CompiledScriptLoader; import org.jruby.runtime.load.LoadService; import org.jruby.runtime.opto.Invalidator; import org.jruby.runtime.opto.OptoFactory; import org.jruby.runtime.profile.ProfileCollection; import org.jruby.runtime.profile.ProfilingService; import org.jruby.runtime.profile.ProfilingServiceLookup; import org.jruby.runtime.scope.ManyVarsDynamicScope; import org.jruby.threading.DaemonThreadFactory; import org.jruby.util.ByteList; import org.jruby.util.ClassDefiningClassLoader; import org.jruby.util.DefinedMessage; import org.jruby.util.JRubyClassLoader; import org.jruby.util.SecurityHelper; import org.jruby.util.SelfFirstJRubyClassLoader; import org.jruby.util.IOInputStream; import org.jruby.util.IOOutputStream; import org.jruby.util.ClassDefiningJRubyClassLoader; import org.jruby.util.KCode; import org.jruby.util.SafePropertyAccessor; import org.jruby.util.cli.Options; import org.jruby.util.io.FilenoUtil; import org.jruby.util.io.SelectorPool; import org.jruby.util.log.Logger; import org.jruby.util.log.LoggerFactory; import org.objectweb.asm.ClassReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Writer; import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; import java.lang.ref.WeakReference; import java.net.BindException; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.WritableByteChannel; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collections; import java.util.EnumMap; import java.util.Enumeration; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.ToIntFunction; import java.util.regex.Pattern; import static java.lang.invoke.MethodHandles.explicitCastArguments; import static java.lang.invoke.MethodHandles.insertArguments; import static java.lang.invoke.MethodHandles.lookup; import static java.lang.invoke.MethodType.methodType; import static org.jruby.RubyBoolean.FALSE_BYTES; import static org.jruby.RubyBoolean.TRUE_BYTES; import static org.jruby.RubyRandom.newRandom; import static org.jruby.RubyRandom.randomSeed; import static org.jruby.api.Access.errnoModule; import static org.jruby.api.Access.loadService; import static org.jruby.api.Convert.asFixnum; import static org.jruby.api.Convert.toInt; import static org.jruby.api.Create.newEmptyString; import static org.jruby.api.Create.newFrozenString; import static org.jruby.api.Error.*; import static org.jruby.api.Warn.warn; import static org.jruby.parser.ParserType.*; import static org.jruby.util.RubyStringBuilder.str; import static org.jruby.util.RubyStringBuilder.ids; import static org.jruby.util.RubyStringBuilder.types; import static org.jruby.runtime.Arity.UNLIMITED_ARGUMENTS; /** * The Ruby object represents the top-level of a JRuby "instance" in a given VM. * JRuby supports spawning multiple instances in the same JVM. Generally, objects * created under these instances are tied to a given runtime, for such details * as identity and type, because multiple Ruby instances means there are * multiple instances of each class. This means that in multi-runtime mode * (or really, multi-VM mode, where each JRuby instance is a ruby "VM"), objects * generally can't be transported across runtimes without marshaling. * * This class roots everything that makes the JRuby runtime function, and * provides a number of utility methods for constructing global types and * accessing global runtime structures. */ public final class Ruby implements Constantizable { /** * The logger used to log relevant bits. */ private static final Logger LOG = LoggerFactory.getLogger(Ruby.class); /** * Create and initialize a new JRuby runtime. The properties of the * specified RubyInstanceConfig will be used to determine various JRuby * runtime characteristics. * * @param config The configuration to use for the new instance * @see org.jruby.RubyInstanceConfig */ private Ruby(RubyInstanceConfig config) { this.config = config; this.threadService = new ThreadService(this); profilingServiceLookup = config.isProfiling() ? new ProfilingServiceLookup(this) : null; constant = OptoFactory.newConstantWrapper(Ruby.class, this); this.jrubyClassLoader = initJRubyClassLoader(config); this.staticScopeFactory = new StaticScopeFactory(this); this.beanManager = BeanManagerFactory.create(this, config.isManagementEnabled()); this.jitCompiler = new JITCompiler(this); this.irManager = new IRManager(this, config); this.parserManager = new ParserManager(this); this.inlineStats = new InlineStats(); this.caches = new Caches(); this.random = initRandom(); this.configBean = new Config(this); this.runtimeBean = new org.jruby.management.Runtime(this); registerMBeans(); this.runtimeCache = new RuntimeCache(); runtimeCache.initMethodCache(ClassIndex.MAX_CLASSES.ordinal() * MethodNames.values().length - 1); checkpointInvalidator = OptoFactory.newConstantInvalidator(this); this.objectSpacer = initObjectSpacer(config); posix = POSIXFactory.getPOSIX(new JRubyPOSIXHandler(this), config.isNativeEnabled()); filenoUtil = new FilenoUtil(posix); reinitialize(false); // Construct key services loadService = this.config.createLoadService(this); javaSupport = loadJavaSupport(); executor = new ThreadPoolExecutor( RubyInstanceConfig.POOL_MIN, RubyInstanceConfig.POOL_MAX, RubyInstanceConfig.POOL_TTL, TimeUnit.SECONDS, new SynchronousQueue<>(), new DaemonThreadFactory("Ruby-" + getRuntimeNumber() + "-Worker")); fiberExecutor = new ThreadPoolExecutor( 0, Integer.MAX_VALUE, RubyInstanceConfig.FIBER_POOL_TTL, TimeUnit.SECONDS, new SynchronousQueue<>(), new DaemonThreadFactory("Ruby-" + getRuntimeNumber() + "-Fiber")); // initialize the root of the class hierarchy completely // Bootstrap the top of the hierarchy basicObjectClass = RubyClass.createBootstrapClass(this, "BasicObject", null, RubyBasicObject.BASICOBJECT_ALLOCATOR); objectClass = RubyClass.createBootstrapClass(this, "Object", basicObjectClass, RubyObject.OBJECT_ALLOCATOR); moduleClass = RubyClass.createBootstrapClass(this, "Module", objectClass, RubyModule.MODULE_ALLOCATOR); classClass = RubyClass.createBootstrapClass(this, "Class", moduleClass, RubyClass.CLASS_ALLOCATOR); refinementClass = RubyClass.createBootstrapClass(this, "Refinement", moduleClass, RubyModule.MODULE_ALLOCATOR); basicObjectClass.setMetaClass(classClass); objectClass.setMetaClass(basicObjectClass); moduleClass.setMetaClass(classClass); classClass.setMetaClass(classClass); refinementClass.setMetaClass(classClass); var metaClass = basicObjectClass.makeMetaClassBootstrap(this, classClass, classClass); metaClass = objectClass.makeMetaClassBootstrap(this, metaClass, classClass); metaClass = moduleClass.makeMetaClassBootstrap(this, metaClass, classClass); classClass.makeMetaClassBootstrap(this, metaClass, classClass); refinementClass.makeMetaClassBootstrap(this, metaClass, classClass); RubyObject.finishObjectClass(objectClass); RubyModule.finishModuleClass(moduleClass); RubyClass.finishClassClass(this, classClass); // set constants now that they're initialized basicObjectClass.defineConstantBootstrap("BasicObject", basicObjectClass); objectClass.defineConstantBootstrap("BasicObject", basicObjectClass); objectClass.defineConstantBootstrap("Object", objectClass); objectClass.defineConstantBootstrap("Class", classClass); objectClass.defineConstantBootstrap("Module", moduleClass); objectClass.defineConstantBootstrap("Refinement", refinementClass); // specializer for RubyObject subclasses objectSpecializer = new RubyObjectSpecializer(this); kernelModule = defineModuleBootstrap("Kernel"); // Initialize Kernel and include into Object topSelf = new RubyObject(this, objectClass); // Object is ready, create top self // nil, true, and false all are set in TC so they need to be created above (both class and instances). // their methods are added afterward since no dispatch happens until after first TC is defined. nilClass = RubyClass.newClassBootstrap(this, objectClass, classClass, "NilClass"); falseClass = RubyClass.newClassBootstrap(this, objectClass, classClass, "FalseClass"); trueClass = RubyClass.newClassBootstrap(this, objectClass, classClass, "TrueClass"); nilObject = new RubyNil(this, nilClass); nilPrefilledArray = new IRubyObject[NIL_PREFILLED_ARRAY_SIZE]; for (int i=0; iJRuby.runtime.use_as_global_runtime * from Ruby code to activate the current runtime as the global one. */ public void useAsGlobalRuntime() { synchronized(Ruby.class) { globalRuntime = this; } } /** * Clear the global runtime. */ public static void clearGlobalRuntime() { globalRuntime = null; } /** * Get the thread-local runtime for the current thread, or null if unset. * * @return the thread-local runtime, or null if unset */ public static Ruby getThreadLocalRuntime() { return threadLocalRuntime.get(); } /** * Set the thread-local runtime to the given runtime. * * Note that static threadlocals like this one can leak resources across * (for example) application redeploys. If you use this, it is your * responsibility to clean it up appropriately. * * @param ruby the new runtime for thread-local */ public static void setThreadLocalRuntime(Ruby ruby) { threadLocalRuntime.set(ruby); } /** * Evaluates a script under the current scope (perhaps the top-level * scope) and returns the result (generally the last value calculated). * This version goes straight into the interpreter, bypassing compilation * and runtime preparation typical to normal script runs. * * @param script The scriptlet to run * @return The result of the eval */ public IRubyObject evalScriptlet(String script) { DynamicScope currentScope = getCurrentContext().getCurrentScope(); DynamicScope newScope = new ManyVarsDynamicScope(getStaticScopeFactory().newEvalScope(currentScope.getStaticScope()), currentScope); return evalScriptlet(script, newScope); } /** * Evaluates a script under the current scope (perhaps the top-level * scope) and returns the result (generally the last value calculated). * This version goes straight into the interpreter, bypassing compilation * and runtime preparation typical to normal script runs. * * This version accepts a scope to use, so you can eval many times against * the same scope. * * @param script The scriptlet to run * @param scope The scope to execute against (ManyVarsDynamicScope is * recommended, so it can grow as needed) * @return The result of the eval */ public IRubyObject evalScriptlet(String script, DynamicScope scope) { ThreadContext context = getCurrentContext(); ParseResult rootNode = getParserManager().parseEval("