pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/jruby/jruby/pull/8862/files

" href="https://github.githubassets.com/assets/primer-primitives-10bf9dd67e3d70bd.css" /> respond_to?(<symbol>) => true optimization by headius · Pull Request #8862 · jruby/jruby · GitHub
Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions bench/bench_respond_to.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
require 'benchmark/ips'

class Foo
def foo; end
end

def respond_to_foo(obj)
obj.respond_to?(:foo)
end

def respond_to_bar(obj)
obj.respond_to?(:bar)
end

Benchmark.ips do |ips|
obj = Foo.new

ips.report("control") do |i|
while i > 0
i -= 1
break unless obj && obj && obj && obj && obj && obj && obj && obj && obj && obj
end
end

ips.report("10x respond_to? = true") do |i|
while i > 0
i -= 1
respond_to_foo(obj)
respond_to_foo(obj)
respond_to_foo(obj)
respond_to_foo(obj)
respond_to_foo(obj)
respond_to_foo(obj)
respond_to_foo(obj)
respond_to_foo(obj)
respond_to_foo(obj)
respond_to_foo(obj)
end
end

ips.report("10x respond_to? = false") do |i|
while i > 0
i -= 1
respond_to_bar(obj)
respond_to_bar(obj)
respond_to_bar(obj)
respond_to_bar(obj)
respond_to_bar(obj)
respond_to_bar(obj)
respond_to_bar(obj)
respond_to_bar(obj)
respond_to_bar(obj)
respond_to_bar(obj)
end
end
end
2 changes: 1 addition & 1 deletion core/pom.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
jar 'org.jruby.jcodings:jcodings:1.0.63'
jar 'org.jruby:dirgra:0.5'

jar 'com.headius:invokebinder:1.14'
jar 'com.headius:invokebinder:1.15'
jar 'com.headius:options:1.6'

jar 'org.jruby:jzlib:1.1.5'
Expand Down
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ DO NOT MODIFY - GENERATED CODE
<dependency>
<groupId>com.headius</groupId>
<artifactId>invokebinder</artifactId>
<version>1.14</version>
<version>1.15</version>
</dependency>
<dependency>
<groupId>com.headius</groupId>
Expand Down
10 changes: 10 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/InvocationCompiler.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jruby.ir.targets;

import org.jruby.RubySymbol;
import org.jruby.ir.instructions.AsStringInstr;
import org.jruby.ir.instructions.CallBase;
import org.jruby.ir.instructions.EQQInstr;
Expand Down Expand Up @@ -138,4 +139,13 @@ public interface InvocationCompiler {
* Invoke __method__ or __callee__ with awareness of any built-in methods.
*/
void invokeFrameName(String methodName, String file);

/**
* Check for a literal respond_to? result
*
* Stack required: context, caller, target
*
* @param id the method name to check respond_to?
*/
void respondTo(CallBase callBase, RubySymbol id, String scopeFieldName, String file);
}
14 changes: 14 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -1272,6 +1272,20 @@ public void CallInstr(CallInstr callInstr) {
} else if (callInstr instanceof OneFloatArgNoBlockCallInstr) {
oneFloatArgNoBlockCallInstr((OneFloatArgNoBlockCallInstr) callInstr);
return;
} else if (!callInstr.getCallType().isSuper()
&& !callInstr.isPotentiallyRefined()
&& callInstr.getId().equals("respond_to?")
&& callInstr.getArgsCount() == 1
&& callInstr.getArg1() instanceof Symbol symName) {
// we do not check for super calls here because super calls will not have a "respond_to?" name
jvmMethod().loadContext();
if (!callInstr.getCallType().isSelfCall()) {
jvmMethod().loadSelf();
}
visit(callInstr.getReceiver());
jvmMethod().getInvocationCompiler().respondTo(callInstr, symName.getSymbol(), jvm.methodData().scopeField, file);
handleCallResult(jvmMethod(), callInstr.getResult());
return;
}

compileCallCommon(jvmMethod(), callInstr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public IRubyObject invoke(ThreadContext context, IRubyObject caller, IRubyObject
// strdup for this call
args[0] = dupString(context, (RubyString) args[0]);

if (methodMissing(entry, caller)) {
if (methodMissing(method, methodName, callType, caller)) {
return callMethodMissing(entry, callType, context, self, selfClass, methodName, args, block);
}

Expand Down Expand Up @@ -130,7 +130,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s

entry = selfClass.searchWithCache(name);

if (methodMissing(entry, caller)) {
if (methodMissing(entry.method, methodName, callType, caller)) {
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, block);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.jruby.ir.targets.indy;

import org.jruby.RubyClass;
import org.jruby.RubyEncoding;
import org.jruby.RubySymbol;
import org.jruby.compiler.NotCompilableException;
import org.jruby.ir.instructions.AsStringInstr;
import org.jruby.ir.instructions.CallBase;
Expand All @@ -17,6 +19,7 @@
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.invokedynamic.MathLinker;
import org.jruby.util.ByteList;
import org.jruby.util.CodegenUtils;
import org.jruby.util.JavaNameMangler;

Expand Down Expand Up @@ -246,4 +249,14 @@ public static void invokeFrameName(IRBytecodeAdapter compiler, String methodName
compiler.loadFrameName();
compiler.adapter.invokedynamic(IndyInvocationCompiler.constructIndyCallName("callVariable", methodName), sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, String.class), FrameNameSite.FRAME_NAME_BOOTSTRAP, file, compiler.getLastLine());
}

@Override
public void respondTo(CallBase callBase, RubySymbol id, String scopeFieldName, String file) {
String sig = callBase.getCallType().isSelfCall() ?
sig(IRubyObject.class, ThreadContext.class, IRubyObject.class) :
sig(IRubyObject.class, ThreadContext.class, IRubyObject.class, IRubyObject.class);

ByteList bytes = id.getBytes();
compiler.adapter.invokedynamic("respond_to", sig, RespondToSite.RESPOND_TO_BOOTSTRAP, RubyEncoding.decodeRaw(bytes), bytes.getEncoding().toString(), file, compiler.getLastLine());
}
}
48 changes: 29 additions & 19 deletions core/src/main/java/org/jruby/ir/targets/indy/InvokeSite.java
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,7 @@ public IRubyObject invoke(ThreadContext context, IRubyObject caller, IRubyObject
MethodHandle mh;
boolean passSymbol = false;

if (methodMissing(entry, caller)) {
if (methodMissing(entry.method, methodName, callType, caller)) {
entry = methodMissingEntry(context, selfClass, methodName, entry);
// only pass symbol below if we be calling a user-defined method_missing (default ones do it for us)
passSymbol = !(entry.method instanceof RubyKernel.MethodMissingMethod ||
Expand All @@ -794,7 +794,7 @@ public IRubyObject invoke(ThreadContext context, IRubyObject self, IRubyObject[]
MethodHandle mh;
boolean passSymbol = false;

if (methodMissing(entry)) {
if (methodMissing(entry.method)) {
entry = methodMissingEntry(context, selfClass, methodName, entry);
// only pass symbol below if we be calling a user-defined method_missing (default ones do it for us)
passSymbol = !(entry.method instanceof RubyKernel.MethodMissingMethod ||
Expand Down Expand Up @@ -915,7 +915,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s

entry = selfClass.searchWithCache(name);

if (methodMissing(entry, caller)) {
if (methodMissing(entry.method, methodName, callType, caller)) {
return callMethodMissing(entry, callType, context, self, selfClass, name, args, block);
}

Expand All @@ -940,7 +940,7 @@ public IRubyObject failf(ThreadContext context, IRubyObject self, IRubyObject[]

entry = selfClass.searchWithCache(name);

if (methodMissing(entry)) {
if (methodMissing(entry.method)) {
return callMethodMissing(entry, callType, context, self, selfClass, name, args, block);
}

Expand Down Expand Up @@ -979,7 +979,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s

entry = selfClass.searchWithCache(name);

if (methodMissing(entry, caller)) {
if (methodMissing(entry.method, methodName, callType, caller)) {
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, block);
}

Expand All @@ -1004,7 +1004,7 @@ public IRubyObject failf(ThreadContext context, IRubyObject self, IRubyObject ar

entry = selfClass.searchWithCache(name);

if (methodMissing(entry)) {
if (methodMissing(entry.method)) {
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, block);
}

Expand All @@ -1029,7 +1029,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s

entry = selfClass.searchWithCache(name);

if (methodMissing(entry, caller)) {
if (methodMissing(entry.method, methodName, callType, caller)) {
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, arg1, block);
}

Expand All @@ -1054,7 +1054,7 @@ public IRubyObject failf(ThreadContext context, IRubyObject self, IRubyObject ar

entry = selfClass.searchWithCache(name);

if (methodMissing(entry)) {
if (methodMissing(entry.method)) {
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, arg1, block);
}

Expand All @@ -1079,7 +1079,7 @@ public IRubyObject fail(ThreadContext context, IRubyObject caller, IRubyObject s

entry = selfClass.searchWithCache(name);

if (methodMissing(entry, caller)) {
if (methodMissing(entry.method, methodName, callType, caller)) {
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, arg1, arg2, block);
}

Expand All @@ -1104,7 +1104,7 @@ public IRubyObject failf(ThreadContext context, IRubyObject self, IRubyObject ar

entry = selfClass.searchWithCache(name);

if (methodMissing(entry)) {
if (methodMissing(entry.method)) {
return callMethodMissing(entry, callType, context, self, selfClass, name, arg0, arg1, arg2, block);
}

Expand Down Expand Up @@ -1431,18 +1431,32 @@ protected void updateInvocationTarget(MethodHandle target, IRubyObject self, Rub

private MethodHandle wrapWithGuards(MethodHandle target, IRubyObject self, RubyModule testClass, SwitchPoint switchPoint, MethodHandle fallback) {
MethodHandle result;
SmartHandle test = testTarget(self, testClass);
result = typeCheck(target, self, testClass, fallback);
result = switchPoint(switchPoint, fallback, result);

result = MethodHandles.guardWithTest(test.handle(), target, fallback);
tracker.addType(testClass.id);
return result;
}

public static MethodHandle switchPoint(SwitchPoint switchPoint, MethodHandle fallback, MethodHandle result) {
// wrap in switchpoint for mutation invalidation
result = switchPoint.guardWithTest(result, fallback);
return result;
}

tracker.addType(testClass.id);
public MethodHandle typeCheck(MethodHandle target, IRubyObject self, RubyModule testClass, MethodHandle fallback) {
MethodHandle result;
SmartHandle test = testTarget(self, testClass);

result = MethodHandles.guardWithTest(test.handle(), target, fallback);
return result;
}

protected SmartHandle testTarget(IRubyObject self, RubyModule testClass) {
return testTarget(signature, self, testClass);
}

public static SmartHandle testTarget(Signature signature, IRubyObject self, RubyModule testClass) {
if (self instanceof RubySymbol ||
self instanceof RubyFixnum ||
self instanceof RubyFloat ||
Expand Down Expand Up @@ -1534,15 +1548,11 @@ public void setInitialTarget(MethodHandle target) {
super.setTarget(target);
}

public boolean methodMissing(CacheEntry entry, IRubyObject caller) {
DynamicMethod method = entry.method;

public static boolean methodMissing(DynamicMethod method, String methodName, CallType callType, IRubyObject caller) {
return method.isUndefined() || (!methodName.equals("method_missing") && !method.isCallableFrom(caller, callType));
}

public boolean methodMissing(CacheEntry entry) {
DynamicMethod method = entry.method;

public static boolean methodMissing(DynamicMethod method) {
return method.isUndefined();
}

Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy