diff --git a/core/src/main/java/org/jruby/ir/targets/indy/Bootstrap.java b/core/src/main/java/org/jruby/ir/targets/indy/Bootstrap.java index 937a9d57416..dc463c4330e 100644 --- a/core/src/main/java/org/jruby/ir/targets/indy/Bootstrap.java +++ b/core/src/main/java/org/jruby/ir/targets/indy/Bootstrap.java @@ -30,14 +30,12 @@ import com.headius.invokebinder.Signature; import com.headius.invokebinder.SmartBinder; import com.headius.invokebinder.SmartHandle; -import org.jcodings.Encoding; import org.jruby.Ruby; import org.jruby.RubyArray; import org.jruby.RubyBasicObject; import org.jruby.RubyBignum; import org.jruby.RubyBoolean; import org.jruby.RubyClass; -import org.jruby.RubyEncoding; import org.jruby.RubyFixnum; import org.jruby.RubyFloat; import org.jruby.RubyGlobal; @@ -80,7 +78,6 @@ import org.jruby.runtime.ivars.FieldVariableAccessor; import org.jruby.runtime.ivars.VariableAccessor; import org.jruby.runtime.opto.Invalidator; -import org.jruby.runtime.opto.OptoFactory; import org.jruby.runtime.scope.DynamicScopeGenerator; import org.jruby.specialized.RubyArraySpecialized; import org.jruby.util.ByteList; @@ -423,171 +420,12 @@ public static RubyArray array(ThreadContext context, IRubyObject[] ary) { return RubyArray.newArrayNoCopy(context.runtime, ary); } - public static Handle contextValue() { - return new Handle( - Opcodes.H_INVOKESTATIC, - p(Bootstrap.class), - "contextValue", - sig(CallSite.class, Lookup.class, String.class, MethodType.class), - false); - } - - public static Handle contextValueString() { - return new Handle( - Opcodes.H_INVOKESTATIC, - p(Bootstrap.class), - "contextValueString", - sig(CallSite.class, Lookup.class, String.class, MethodType.class, String.class), - false); - } - - public static CallSite contextValue(Lookup lookup, String name, MethodType type) { - MutableCallSite site = new MutableCallSite(type); - - MethodHandle dmh; - switch (name) { - case "runtime": - dmh = RUNTIME_HANDLE; - break; - case "nil": - dmh = NIL_HANDLE; - break; - case "True": - dmh = TRUE_HANDLE; - break; - case "False": - dmh = FALSE_HANDLE; - break; - case "rubyEncoding": - dmh = RUBY_ENCODING_HANDLE; - break; - case "encoding": - dmh = ENCODING_HANDLE; - break; - default: - throw new RuntimeException("BUG: invalid context value " + name); - } - - site.setTarget(Binder.from(type).append(site).invoke(dmh)); - - return site; - } - - public static CallSite contextValueString(Lookup lookup, String name, MethodType type, String str) { - MutableCallSite site = new MutableCallSite(type); - - MethodHandle dmh; - switch (name) { - case "rubyEncoding": - dmh = RUBY_ENCODING_HANDLE; - break; - case "encoding": - dmh = ENCODING_HANDLE; - break; - default: - throw new RuntimeException("BUG: invalid context value " + name); - } - - site.setTarget(Binder.from(type).append(site, str).invoke(dmh)); - return site; - } - - private static final MethodHandle RUNTIME_HANDLE = - Binder - .from(Ruby.class, ThreadContext.class, MutableCallSite.class) - .invokeStaticQuiet(LOOKUP, Bootstrap.class, "runtime"); - // We use LOOKUP here to have a full-featured MethodHandles.Lookup, avoiding jruby/jruby#7911 private static final MethodHandle RUNTIME_FROM_CONTEXT_HANDLE = Binder .from(LOOKUP, Ruby.class, ThreadContext.class) .getFieldQuiet("runtime"); - private static final MethodHandle NIL_HANDLE = - Binder - .from(IRubyObject.class, ThreadContext.class, MutableCallSite.class) - .invokeStaticQuiet(LOOKUP, Bootstrap.class, "nil"); - - private static final MethodHandle TRUE_HANDLE = - Binder - .from(IRubyObject.class, ThreadContext.class, MutableCallSite.class) - .invokeStaticQuiet(LOOKUP, Bootstrap.class, "True"); - - private static final MethodHandle FALSE_HANDLE = - Binder - .from(IRubyObject.class, ThreadContext.class, MutableCallSite.class) - .invokeStaticQuiet(LOOKUP, Bootstrap.class, "False"); - - private static final MethodHandle RUBY_ENCODING_HANDLE = - Binder - .from(RubyEncoding.class, ThreadContext.class, MutableCallSite.class, String.class) - .invokeStaticQuiet(LOOKUP, Bootstrap.class, "rubyEncoding"); - - private static final MethodHandle ENCODING_HANDLE = - Binder - .from(Encoding.class, ThreadContext.class, MutableCallSite.class, String.class) - .invokeStaticQuiet(LOOKUP, Bootstrap.class, "encoding"); - - public static IRubyObject nil(ThreadContext context, MutableCallSite site) { - RubyNil nil = (RubyNil) context.nil; - - MethodHandle constant = (MethodHandle) nil.constant(); - if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(IRubyObject.class, context.nil); - - site.setTarget(constant); - - return nil; - } - - public static IRubyObject True(ThreadContext context, MutableCallSite site) { - MethodHandle constant = (MethodHandle)context.tru.constant(); - if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(IRubyObject.class, context.tru); - - site.setTarget(constant); - - return context.tru; - } - - public static IRubyObject False(ThreadContext context, MutableCallSite site) { - MethodHandle constant = (MethodHandle)context.fals.constant(); - if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(IRubyObject.class, context.fals); - - site.setTarget(constant); - - return context.fals; - } - - public static Ruby runtime(ThreadContext context, MutableCallSite site) { - MethodHandle constant = (MethodHandle)context.runtime.constant(); - if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(Ruby.class, context.runtime); - - site.setTarget(constant); - - return context.runtime; - } - - public static RubyEncoding rubyEncoding(ThreadContext context, MutableCallSite site, String name) { - RubyEncoding rubyEncoding = IRRuntimeHelpers.retrieveEncoding(context, name); - - MethodHandle constant = (MethodHandle)rubyEncoding.constant(); - if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(RubyEncoding.class, rubyEncoding); - - site.setTarget(constant); - - return rubyEncoding; - } - - public static Encoding encoding(ThreadContext context, MutableCallSite site, String name) { - Encoding encoding = IRRuntimeHelpers.retrieveJCodingsEncoding(context, name); - - MethodHandle constant = MethodHandles.constant(Encoding.class, encoding); - if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(Encoding.class, encoding); - - site.setTarget(constant); - - return encoding; - } - public static RubyHash hash(ThreadContext context, IRubyObject[] pairs) { Ruby runtime = context.runtime; RubyHash hash = new RubyHash(runtime, pairs.length / 2 + 1); @@ -1455,7 +1293,7 @@ public static CallSite getHeapLocalOrNilBootstrap(Lookup lookup, String name, Me MethodHandle getter; Binder binder = Binder .from(type) - .filter(1, contextValue(lookup, "nil", methodType(IRubyObject.class, ThreadContext.class)).dynamicInvoker()); + .filter(1, LiteralValueBootstrap.contextValue(lookup, "nil", methodType(IRubyObject.class, ThreadContext.class)).dynamicInvoker()); if (depth == 0) { if (location < DynamicScopeGenerator.SPECIALIZED_GETS_OR_NIL.size()) { diff --git a/core/src/main/java/org/jruby/ir/targets/indy/IndyValueCompiler.java b/core/src/main/java/org/jruby/ir/targets/indy/IndyValueCompiler.java index 75f86caa99f..014076e9641 100644 --- a/core/src/main/java/org/jruby/ir/targets/indy/IndyValueCompiler.java +++ b/core/src/main/java/org/jruby/ir/targets/indy/IndyValueCompiler.java @@ -40,7 +40,7 @@ public IndyValueCompiler(IRBytecodeAdapter compiler) { public void pushRuntime() { compiler.loadContext(); - compiler.adapter.invokedynamic("runtime", sig(Ruby.class, ThreadContext.class), Bootstrap.contextValue()); + compiler.adapter.invokedynamic("runtime", sig(Ruby.class, ThreadContext.class), LiteralValueBootstrap.CONTEXT_VALUE_HANDLE); } public void pushArrayClass() { compiler.loadContext(); @@ -119,22 +119,22 @@ public void pushSymbolProc(final ByteList bytes) { public void pushRubyEncoding(Encoding encoding) { compiler.loadContext(); - compiler.adapter.invokedynamic("rubyEncoding", sig(RubyEncoding.class, ThreadContext.class), Bootstrap.contextValueString(), new String(encoding.getName())); + compiler.adapter.invokedynamic("rubyEncoding", sig(RubyEncoding.class, ThreadContext.class), LiteralValueBootstrap.CONTEXT_VALUE_STRING_HANDLE, new String(encoding.getName())); } public void pushEncoding(Encoding encoding) { compiler.loadContext(); - compiler.adapter.invokedynamic("encoding", sig(RubyEncoding.class, ThreadContext.class), Bootstrap.contextValueString(), new String(encoding.getName())); + compiler.adapter.invokedynamic("encoding", sig(RubyEncoding.class, ThreadContext.class), LiteralValueBootstrap.CONTEXT_VALUE_STRING_HANDLE, new String(encoding.getName())); } public void pushNil() { compiler.loadContext(); - compiler.adapter.invokedynamic("nil", sig(IRubyObject.class, ThreadContext.class), Bootstrap.contextValue()); + compiler.adapter.invokedynamic("nil", sig(IRubyObject.class, ThreadContext.class), LiteralValueBootstrap.CONTEXT_VALUE_HANDLE); } public void pushBoolean(boolean b) { compiler.loadContext(); - compiler.adapter.invokedynamic(b ? "True" : "False", sig(IRubyObject.class, ThreadContext.class), Bootstrap.contextValue()); + compiler.adapter.invokedynamic(b ? "True" : "False", sig(IRubyObject.class, ThreadContext.class), LiteralValueBootstrap.CONTEXT_VALUE_HANDLE); } public void pushBignum(BigInteger bigint) { diff --git a/core/src/main/java/org/jruby/ir/targets/indy/LiteralValueBootstrap.java b/core/src/main/java/org/jruby/ir/targets/indy/LiteralValueBootstrap.java new file mode 100644 index 00000000000..781fc15611c --- /dev/null +++ b/core/src/main/java/org/jruby/ir/targets/indy/LiteralValueBootstrap.java @@ -0,0 +1,175 @@ +package org.jruby.ir.targets.indy; + +import com.headius.invokebinder.Binder; +import org.jcodings.Encoding; +import org.jruby.Ruby; +import org.jruby.RubyEncoding; +import org.jruby.RubyNil; +import org.jruby.ir.runtime.IRRuntimeHelpers; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.opto.OptoFactory; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Opcodes; + +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.MutableCallSite; + +import static org.jruby.util.CodegenUtils.p; +import static org.jruby.util.CodegenUtils.sig; + +public class LiteralValueBootstrap { + private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + public static final Handle CONTEXT_VALUE_HANDLE = new Handle( + Opcodes.H_INVOKESTATIC, + p(LiteralValueBootstrap.class), + "contextValue", + sig(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class), + false); + public static final Handle CONTEXT_VALUE_STRING_HANDLE = new Handle( + Opcodes.H_INVOKESTATIC, + p(LiteralValueBootstrap.class), + "contextValueString", + sig(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, String.class), + false); + + private static final MethodHandle RUNTIME_HANDLE = + Binder + .from(Ruby.class, ThreadContext.class, MutableCallSite.class) + .invokeStaticQuiet(LOOKUP, LiteralValueBootstrap.class, "runtime"); + private static final MethodHandle NIL_HANDLE = + Binder + .from(IRubyObject.class, ThreadContext.class, MutableCallSite.class) + .invokeStaticQuiet(LOOKUP, LiteralValueBootstrap.class, "nil"); + private static final MethodHandle TRUE_HANDLE = + Binder + .from(IRubyObject.class, ThreadContext.class, MutableCallSite.class) + .invokeStaticQuiet(LOOKUP, LiteralValueBootstrap.class, "True"); + private static final MethodHandle FALSE_HANDLE = + Binder + .from(IRubyObject.class, ThreadContext.class, MutableCallSite.class) + .invokeStaticQuiet(LOOKUP, LiteralValueBootstrap.class, "False"); + private static final MethodHandle RUBY_ENCODING_HANDLE = + Binder + .from(RubyEncoding.class, ThreadContext.class, MutableCallSite.class, String.class) + .invokeStaticQuiet(LOOKUP, LiteralValueBootstrap.class, "rubyEncoding"); + private static final MethodHandle ENCODING_HANDLE = + Binder + .from(Encoding.class, ThreadContext.class, MutableCallSite.class, String.class) + .invokeStaticQuiet(LOOKUP, LiteralValueBootstrap.class, "encoding"); + + public static CallSite contextValue(MethodHandles.Lookup lookup, String name, MethodType type) { + MutableCallSite site = new MutableCallSite(type); + + MethodHandle dmh; + switch (name) { + case "runtime": + dmh = RUNTIME_HANDLE; + break; + case "nil": + dmh = NIL_HANDLE; + break; + case "True": + dmh = TRUE_HANDLE; + break; + case "False": + dmh = FALSE_HANDLE; + break; + case "rubyEncoding": + dmh = RUBY_ENCODING_HANDLE; + break; + case "encoding": + dmh = ENCODING_HANDLE; + break; + default: + throw new RuntimeException("BUG: invalid context value " + name); + } + + site.setTarget(Binder.from(type).append(site).invoke(dmh)); + + return site; + } + + public static CallSite contextValueString(MethodHandles.Lookup lookup, String name, MethodType type, String str) { + MutableCallSite site = new MutableCallSite(type); + + MethodHandle dmh; + switch (name) { + case "rubyEncoding": + dmh = RUBY_ENCODING_HANDLE; + break; + case "encoding": + dmh = ENCODING_HANDLE; + break; + default: + throw new RuntimeException("BUG: invalid context value " + name); + } + + site.setTarget(Binder.from(type).append(site, str).invoke(dmh)); + return site; + } + + public static IRubyObject nil(ThreadContext context, MutableCallSite site) { + RubyNil nil = (RubyNil) context.nil; + + MethodHandle constant = (MethodHandle) nil.constant(); + if (constant == null) constant = (MethodHandle) OptoFactory.newConstantWrapper(IRubyObject.class, context.nil); + + site.setTarget(constant); + + return nil; + } + + public static IRubyObject True(ThreadContext context, MutableCallSite site) { + MethodHandle constant = (MethodHandle)context.tru.constant(); + if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(IRubyObject.class, context.tru); + + site.setTarget(constant); + + return context.tru; + } + + public static IRubyObject False(ThreadContext context, MutableCallSite site) { + MethodHandle constant = (MethodHandle)context.fals.constant(); + if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(IRubyObject.class, context.fals); + + site.setTarget(constant); + + return context.fals; + } + + public static Ruby runtime(ThreadContext context, MutableCallSite site) { + MethodHandle constant = (MethodHandle)context.runtime.constant(); + if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(Ruby.class, context.runtime); + + site.setTarget(constant); + + return context.runtime; + } + + public static RubyEncoding rubyEncoding(ThreadContext context, MutableCallSite site, String name) { + RubyEncoding rubyEncoding = IRRuntimeHelpers.retrieveEncoding(context, name); + + MethodHandle constant = (MethodHandle)rubyEncoding.constant(); + if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(RubyEncoding.class, rubyEncoding); + + site.setTarget(constant); + + return rubyEncoding; + } + + public static Encoding encoding(ThreadContext context, MutableCallSite site, String name) { + Encoding encoding = IRRuntimeHelpers.retrieveJCodingsEncoding(context, name); + + MethodHandle constant = MethodHandles.constant(Encoding.class, encoding); + if (constant == null) constant = (MethodHandle)OptoFactory.newConstantWrapper(Encoding.class, encoding); + + site.setTarget(constant); + + return encoding; + } +}