New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPE while dup-ing guava's ImmutableList #4721

Closed
trejkaz opened this Issue Jul 21, 2017 · 17 comments

Comments

Projects
None yet
2 participants
@trejkaz

trejkaz commented Jul 21, 2017

Environment

JRuby 9.1.12.0
Java 1.8.0_92
Mac OS X

rspec 3.6.0

Expected Behavior

It's complicated. The spec should probably fail, but in a different way which is more our fault.

I was still in the process of figuring out why this only happened for one spec file, because it doesn't look any stranger than any other spec file.

Actual Behavior

(Java::JavaLang::NullPointerException)
Java::JavaLang::NullPointerException:

org.jruby.javasupport.ext.JavaUtil.tryNewEqualInstance(JavaUtil.java:611)
org.jruby.javasupport.ext.JavaUtil.access$000(JavaUtil.java:58)
org.jruby.javasupport.ext.JavaUtil$Collection.dup(JavaUtil.java:231)
org.jruby.javasupport.ext.JavaUtil$Collection$INVOKER$s$0$0$dup.call(JavaUtil$Collection$INVOKER$s$0$0$dup.gen)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:129)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:339)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:77)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:144)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:130)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:192)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:129)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:339)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:338)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:163)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:314)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:348)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:173)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:177)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:332)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:186)
org.jruby.runtime.BlockBody.yield(BlockBody.java:116)
org.jruby.runtime.Block.yield(Block.java:165)
org.jruby.ir.runtime.IRRuntimeHelpers.yield(IRRuntimeHelpers.java:415)
org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:83)
org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:187)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:111)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.ir.runtime.IRRuntimeHelpers.instanceSuper(IRRuntimeHelpers.java:983)
org.jruby.ir.instructions.InstanceSuperInstr.interpret(InstanceSuperInstr.java:69)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:338)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:163)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:314)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:193)
org.jruby.runtime.BlockBody.yield(BlockBody.java:125)
org.jruby.runtime.Block.yieldNonArray(Block.java:169)
org.jruby.RubyBasicObject.yieldUnder(RubyBasicObject.java:1751)
org.jruby.RubyBasicObject.instance_exec19(RubyBasicObject.java:1728)
org.jruby.RubyBasicObject$INVOKER$i$0$3$instance_exec19.call(RubyBasicObject$INVOKER$i$0$3$instance_exec19.gen)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:204)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:348)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:173)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:177)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:332)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:84)
org.jruby.runtime.Block.yieldSpecific(Block.java:134)
org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:419)
org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:74)
org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:187)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:111)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:84)
org.jruby.runtime.Block.yieldSpecific(Block.java:134)
org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:419)
org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:74)
org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:187)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:111)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:84)
org.jruby.runtime.Block.yieldSpecific(Block.java:134)
org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:419)
org.jruby.ir.targets.YieldSite.yieldSpecific(YieldSite.java:114)
Users.tester.Data.master_minus_checkout_minus_trunk.functional_minus_tests.vendor.bundle.jruby.$2_dot_3_dot_0.gems.rspec_minus_core_minus_3_dot_6_dot_0.lib.rspec.core.hooks.RUBY$block$run$1(/Users/tester/Data/master-checkout-trunk/functional-tests/vendor/bundle/jruby/2.3.0/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb:464)
org.jruby.runtime.CompiledIRBlockBody.yieldDirect(CompiledIRBlockBody.java:156)
org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:80)
org.jruby.runtime.Block.yieldSpecific(Block.java:134)
org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:419)
org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:74)
org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:187)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:111)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:73)
org.jruby.runtime.Block.call(Block.java:124)
org.jruby.RubyProc.call(RubyProc.java:289)
org.jruby.RubyProc.call19(RubyProc.java:273)
org.jruby.RubyProc$INVOKER$i$0$0$call19.call(RubyProc$INVOKER$i$0$0$call19.gen)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.runtime.MethodBlockBody.doYield(MethodBlockBody.java:66)
org.jruby.runtime.BlockBody.yield(BlockBody.java:116)
org.jruby.runtime.BlockBody.yieldSpecific(BlockBody.java:174)
org.jruby.runtime.Block.yieldSpecific(Block.java:134)
org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:419)
org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:74)
org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:187)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:111)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:84)
org.jruby.runtime.Block.yieldSpecific(Block.java:134)
org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:419)
org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:74)
org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:187)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:111)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:171)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:177)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:332)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:298)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:79)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:193)
org.jruby.runtime.BlockBody.yield(BlockBody.java:125)
org.jruby.runtime.Block.yieldNonArray(Block.java:169)
org.jruby.RubyBasicObject.yieldUnder(RubyBasicObject.java:1751)
org.jruby.RubyBasicObject.instance_exec19(RubyBasicObject.java:1728)
org.jruby.RubyBasicObject$INVOKER$i$0$3$instance_exec19.call(RubyBasicObject$INVOKER$i$0$3$instance_exec19.gen)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:298)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:79)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:171)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:177)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:332)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:89)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:214)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:200)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:208)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:193)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:323)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.call(IRBlockBody.java:73)
org.jruby.runtime.Block.call(Block.java:124)
org.jruby.RubyProc.call(RubyProc.java:289)
org.jruby.RubyProc.call19(RubyProc.java:273)
org.jruby.RubyProc$INVOKER$i$0$0$call19.call(RubyProc$INVOKER$i$0$0$call19.gen)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:77)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:144)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:130)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:192)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:129)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:339)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:348)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:173)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:177)
Users.tester.Data.master_minus_checkout_minus_trunk.functional_minus_tests.vendor.bundle.jruby.$2_dot_3_dot_0.gems.rspec_minus_core_minus_3_dot_6_dot_0.lib.rspec.core.hooks.invokeOther16:run_around_example_hooks_for(/Users/tester/Data/master-checkout-trunk/functional-tests/vendor/bundle/jruby/2.3.0/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb:464)
Users.tester.Data.master_minus_checkout_minus_trunk.functional_minus_tests.vendor.bundle.jruby.$2_dot_3_dot_0.gems.rspec_minus_core_minus_3_dot_6_dot_0.lib.rspec.core.hooks.RUBY$method$run$0(/Users/tester/Data/master-checkout-trunk/functional-tests/vendor/bundle/jruby/2.3.0/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb:464)
Users.tester.Data.master_minus_checkout_minus_trunk.functional_minus_tests.vendor.bundle.jruby.$2_dot_3_dot_0.gems.rspec_minus_core_minus_3_dot_6_dot_0.lib.rspec.core.hooks.RUBY$method$run$0$__VARARGS__(/Users/tester/Data/master-checkout-trunk/functional-tests/vendor/bundle/jruby/2.3.0/gems/rspec-core-3.6.0/lib/rspec/core/hooks.rb)
org.jruby.internal.runtime.methods.CompiledIRMethod.call(CompiledIRMethod.java:77)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:93)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:298)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:79)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:89)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:214)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:200)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:208)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:193)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:323)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:186)
org.jruby.runtime.BlockBody.yield(BlockBody.java:116)
org.jruby.runtime.Block.yield(Block.java:165)
org.jruby.RubyArray.collect(RubyArray.java:2472)
org.jruby.RubyArray.map19(RubyArray.java:2486)
org.jruby.RubyArray$INVOKER$i$0$0$map19.call(RubyArray$INVOKER$i$0$0$map19.gen)
org.jruby.internal.runtime.methods.JavaMethod$JavaMethodZeroBlock.call(JavaMethod.java:498)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:338)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:163)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:314)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:338)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:163)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:314)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:186)
org.jruby.runtime.BlockBody.yield(BlockBody.java:116)
org.jruby.runtime.Block.yield(Block.java:165)
org.jruby.RubyArray.collect(RubyArray.java:2472)
org.jruby.RubyArray.map19(RubyArray.java:2486)
org.jruby.RubyArray$INVOKER$i$0$0$map19.call(RubyArray$INVOKER$i$0$0$map19.gen)
org.jruby.internal.runtime.methods.JavaMethod$JavaMethodZeroBlock.call(JavaMethod.java:498)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:77)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:338)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:163)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:314)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:186)
org.jruby.runtime.BlockBody.yield(BlockBody.java:116)
org.jruby.runtime.Block.yield(Block.java:165)
org.jruby.RubyArray.collect(RubyArray.java:2472)
org.jruby.RubyArray.map19(RubyArray.java:2486)
org.jruby.RubyArray$INVOKER$i$0$0$map19.call(RubyArray$INVOKER$i$0$0$map19.gen)
org.jruby.internal.runtime.methods.JavaMethod$JavaMethodZeroBlock.call(JavaMethod.java:498)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:298)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:79)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:338)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:163)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:314)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:186)
org.jruby.runtime.BlockBody.yield(BlockBody.java:116)
org.jruby.runtime.Block.yield(Block.java:165)
org.jruby.RubyArray.collect(RubyArray.java:2472)
org.jruby.RubyArray.map19(RubyArray.java:2486)
org.jruby.RubyArray$INVOKER$i$0$0$map19.call(RubyArray$INVOKER$i$0$0$map19.gen)
org.jruby.internal.runtime.methods.JavaMethod$JavaMethodZeroBlock.call(JavaMethod.java:498)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:298)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:79)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.yieldSpecific(IRBlockBody.java:84)
org.jruby.runtime.Block.yieldSpecific(Block.java:134)
org.jruby.ir.runtime.IRRuntimeHelpers.yieldSpecific(IRRuntimeHelpers.java:419)
org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:74)
org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:187)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:111)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:298)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:79)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_BLOCK(Interpreter.java:132)
org.jruby.runtime.MixedModeIRBlockBody.commonYieldPath(MixedModeIRBlockBody.java:148)
org.jruby.runtime.IRBlockBody.doYield(IRBlockBody.java:186)
org.jruby.runtime.BlockBody.yield(BlockBody.java:116)
org.jruby.runtime.Block.yield(Block.java:165)
org.jruby.ir.runtime.IRRuntimeHelpers.yield(IRRuntimeHelpers.java:415)
org.jruby.ir.instructions.YieldInstr.interpret(YieldInstr.java:83)
org.jruby.ir.interpreter.StartupInterpreterEngine.processOtherOp(StartupInterpreterEngine.java:187)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:111)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:348)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:173)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:177)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:332)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:83)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:338)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:163)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:314)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:89)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:214)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:200)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:208)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:358)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:195)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:323)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:298)
org.jruby.runtime.callsite.CachingCallSite.callBlock(CachingCallSite.java:79)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:83)
org.jruby.ir.instructions.CallBase.interpret(CallBase.java:428)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:355)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:77)
org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:144)
org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:130)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:192)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:318)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:131)
org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:339)
org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:73)
org.jruby.ir.interpreter.Interpreter.INTERPRET_ROOT(Interpreter.java:112)
org.jruby.ir.interpreter.Interpreter.execute(Interpreter.java:99)
org.jruby.ir.interpreter.Interpreter.execute(Interpreter.java:35)
org.jruby.ir.IRTranslator.execute(IRTranslator.java:42)
org.jruby.Ruby.runInterpreter(Ruby.java:839)
org.jruby.Ruby.loadFile(Ruby.java:2876)
org.jruby.runtime.load.LibrarySearcher$ResourceLibrary.load(LibrarySearcher.java:243)
org.jruby.runtime.load.LibrarySearcher$FoundLibrary.load(LibrarySearcher.java:34)
org.jruby.runtime.load.LoadService.load(LoadService.java:343)
org.jruby.RubyKernel.loadCommon(RubyKernel.java:987)
org.jruby.RubyKernel.load19(RubyKernel.java:979)
org.jruby.RubyKernel$INVOKER$s$0$1$load19.call(RubyKernel$INVOKER$s$0$1$load19.gen)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:204)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:338)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:163)
Users.tester.Data.master_minus_checkout_minus_trunk.functional_minus_tests.bin.rspec.invokeOther16:load(/Users/tester/Data/master-checkout-trunk/functional-tests/bin/rspec:17)
Users.tester.Data.master_minus_checkout_minus_trunk.functional_minus_tests.bin.rspec.RUBY$script(/Users/tester/Data/master-checkout-trunk/functional-tests/bin/rspec:17)
java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627)
org.jruby.ir.Compiler$1.load(Compiler.java:95)
org.jruby.Ruby.runScript(Ruby.java:827)
org.jruby.Ruby.runNormally(Ruby.java:746)
org.jruby.Ruby.runNormally(Ruby.java:764)
org.jruby.Ruby.runFromMain(Ruby.java:577)
org.jruby.Main.doRunFromMain(Main.java:417)
org.jruby.Main.internalRun(Main.java:305)
org.jruby.Main.run(Main.java:232)
org.jruby.Main.main(Main.java:204)    

hooks.rb line 464 is where it's running the "around example" hooks.

            when :around then run_around_example_hooks_for(example_or_group) { yield }

@trejkaz trejkaz changed the title from NPE from JavaUtils.tryNewEqualInstance when running rspec hooks (yield issue?) to NPE from JavaUtil.tryNewEqualInstance when running rspec hooks (yield issue?) Jul 21, 2017

@trejkaz

This comment has been minimized.

Show comment
Hide comment
@trejkaz

trejkaz Jul 21, 2017

After about half a day, I figured out what is going on here, and it's kind of awful. :D

Seemingly, Collection#dup now tries to construct a new instance of the collection inside it. We were using Guava's ImmutableList in this particular case, so the call failed. The NPE probably could have said something like "no constructors found in {classname}" to make it easier to figure out what's going on.

require_relative '../../spec_helper'

describe 'ImmutableList' do
  let(:set) { Java::com.google.common.collect.ImmutableList.builder.add(1).add(2).add(3).build }

  it 'does something' do
    set.dup
  end
end

Our own test doesn't call #dup but I guess something inside RSpec must be doing it.

trejkaz commented Jul 21, 2017

After about half a day, I figured out what is going on here, and it's kind of awful. :D

Seemingly, Collection#dup now tries to construct a new instance of the collection inside it. We were using Guava's ImmutableList in this particular case, so the call failed. The NPE probably could have said something like "no constructors found in {classname}" to make it easier to figure out what's going on.

require_relative '../../spec_helper'

describe 'ImmutableList' do
  let(:set) { Java::com.google.common.collect.ImmutableList.builder.add(1).add(2).add(3).build }

  it 'does something' do
    set.dup
  end
end

Our own test doesn't call #dup but I guess something inside RSpec must be doing it.

@trejkaz trejkaz changed the title from NPE from JavaUtil.tryNewEqualInstance when running rspec hooks (yield issue?) to NPE from JavaUtil.tryNewEqualInstance when #dup called on ImmutableList Jul 21, 2017

trejkaz referenced this issue Jul 21, 2017

[ji] also support dup/clone-ing collections that do not provide a Jav…
…a clone method

... we can do so if we're able to allocate a new instance of the same class
@trejkaz

This comment has been minimized.

Show comment
Hide comment
@trejkaz

trejkaz Jul 21, 2017

And then on digging a bit further in our own code, it turns out that the actual class being returned isn't ImmutableList for some other cases where we saw this, but some other list implementation which also didn't have a public constructor.

So perhaps the best fix is, continue to do the public constructor search - if none are found, fall back to the old logic (where presumably it returned the original list?)

trejkaz commented Jul 21, 2017

And then on digging a bit further in our own code, it turns out that the actual class being returned isn't ImmutableList for some other cases where we saw this, but some other list implementation which also didn't have a public constructor.

So perhaps the best fix is, continue to do the public constructor search - if none are found, fall back to the old logic (where presumably it returned the original list?)

@kares

This comment has been minimized.

Show comment
Hide comment
@kares

kares Jul 21, 2017

Member

we're following general Java collection "conventions" here, implementing Cloneable and than not really being just sounds wrong, in the first place, right?

perhaps the best fix is, continue to do the public constructor search - if none are found, fall back to the old logic (where presumably it returned the original list?)

not sure, there's almost no stuff in Ruby (only Symbols?) where it would return the very same on dup ...

on the other hand maybe we can assume a coll to be immutable if it returned itself on clone, although we should look around for more immutable collections e.g. Scala on their details, so that we decide "safely" (hopefully we can not make it break - not dup-ing a mutable collections by chance)

there's still the potential to do the dup in weird cases using hacks such as serialization but I believe it wouldn't do much good.

the exception message could get improved thought although we do not want logic too specific to one impl.

Member

kares commented Jul 21, 2017

we're following general Java collection "conventions" here, implementing Cloneable and than not really being just sounds wrong, in the first place, right?

perhaps the best fix is, continue to do the public constructor search - if none are found, fall back to the old logic (where presumably it returned the original list?)

not sure, there's almost no stuff in Ruby (only Symbols?) where it would return the very same on dup ...

on the other hand maybe we can assume a coll to be immutable if it returned itself on clone, although we should look around for more immutable collections e.g. Scala on their details, so that we decide "safely" (hopefully we can not make it break - not dup-ing a mutable collections by chance)

there's still the potential to do the dup in weird cases using hacks such as serialization but I believe it wouldn't do much good.

the exception message could get improved thought although we do not want logic too specific to one impl.

@kares kares self-assigned this Jul 21, 2017

@kares kares added this to the JRuby 9.2.0.0 milestone Jul 21, 2017

@trejkaz

This comment has been minimized.

Show comment
Hide comment
@trejkaz

trejkaz Jul 21, 2017

I think it's fair to say that if a collection class implements Cloneable, it can be assumed that clone() will do the right thing, and if it returns this then it must be because it's an immutable collection. The current logic in JRuby must not be checking for the interface, and doing so would fix the issue for ImmutableList at least.

For our own list class I found, we don't implement Cloneable yet, but I guess if we had to, it wouldn't be too hard.

But this call to #dup isn't happening because I asked for it. So it seems like RSpec might call #dup on all kinds of things, and we can hardly be expected to make sure that every object we ever return from an API is sensibly cloneable, so having some kind of fallback for objects which aren't cloneable would be nice. I mean, what if they call it on an InputStream? What is #dup supposed to do when the object cannot be duplicated?

trejkaz commented Jul 21, 2017

I think it's fair to say that if a collection class implements Cloneable, it can be assumed that clone() will do the right thing, and if it returns this then it must be because it's an immutable collection. The current logic in JRuby must not be checking for the interface, and doing so would fix the issue for ImmutableList at least.

For our own list class I found, we don't implement Cloneable yet, but I guess if we had to, it wouldn't be too hard.

But this call to #dup isn't happening because I asked for it. So it seems like RSpec might call #dup on all kinds of things, and we can hardly be expected to make sure that every object we ever return from an API is sensibly cloneable, so having some kind of fallback for objects which aren't cloneable would be nice. I mean, what if they call it on an InputStream? What is #dup supposed to do when the object cannot be duplicated?

@kares

This comment has been minimized.

Show comment
Hide comment
@kares

kares Jul 21, 2017

Member

Cloneable is a marker interface (and clone isn't public but get inherited from Java's Object - we would need to be checking whether its re-defined which isn't good) ... so I am still not sure we can assume much.

Member

kares commented Jul 21, 2017

Cloneable is a marker interface (and clone isn't public but get inherited from Java's Object - we would need to be checking whether its re-defined which isn't good) ... so I am still not sure we can assume much.

@kares

This comment has been minimized.

Show comment
Hide comment
@kares

kares Jul 21, 2017

Member

So it seems like RSpec might call #dup on all kinds of things, and we can hardly be expected to make sure that every object we ever return from an API is sensibly cloneable

could we understand why it needs to be doing that so we can decide if we could maybe raise a concern?

Member

kares commented Jul 21, 2017

So it seems like RSpec might call #dup on all kinds of things, and we can hardly be expected to make sure that every object we ever return from an API is sensibly cloneable

could we understand why it needs to be doing that so we can decide if we could maybe raise a concern?

@trejkaz

This comment has been minimized.

Show comment
Hide comment
@trejkaz

trejkaz Jul 21, 2017

Not sure about RSpec, really. I'd assume they're working around people returning mutable objects or something.

But as for Cloneable being a marker interface... sure, it is, but it's nonetheless a marker interface which means the object is cloneable. The docs also say that such classes must override clone() with a public method. So really, if a class doesn't conform to that, I'd call that a bug in the class, rather than something we have to assume might not be the case.

(Likewise, just because it's possible to implement Comparable backwards doesn't mean that my code has to account for that possibility.)

trejkaz commented Jul 21, 2017

Not sure about RSpec, really. I'd assume they're working around people returning mutable objects or something.

But as for Cloneable being a marker interface... sure, it is, but it's nonetheless a marker interface which means the object is cloneable. The docs also say that such classes must override clone() with a public method. So really, if a class doesn't conform to that, I'd call that a bug in the class, rather than something we have to assume might not be the case.

(Likewise, just because it's possible to implement Comparable backwards doesn't mean that my code has to account for that possibility.)

@kares

This comment has been minimized.

Show comment
Hide comment
@kares

kares Jul 21, 2017

Member

OK, let's see your proposal including a stubbed test for the case you describe - so we have a place to start

Member

kares commented Jul 21, 2017

OK, let's see your proposal including a stubbed test for the case you describe - so we have a place to start

@trejkaz

This comment has been minimized.

Show comment
Hide comment
@trejkaz

trejkaz Jul 24, 2017

To answer my unanswered question above - what are we supposed to do if a Ruby type cannot be duped? Well, apparently some types are already doing this:

irb(main):001:0> 42.dup
TypeError: can't dup Fixnum
	from (irb):1:in `dup'
	from (irb):1
	from /usr/bin/irb:12:in `<main>'

So what I'm leaning towards writing in my specs:

  • If the thing implements Cloneable, expect it to call clone()
  • If it doesn't implement Cloneable, use the current fallback logic which looks for a constructor
  • If there is no usable constructor, expect TypeError

I'll probably still have to go to RSpec to tell them that some collection types might not support #dup.

trejkaz commented Jul 24, 2017

To answer my unanswered question above - what are we supposed to do if a Ruby type cannot be duped? Well, apparently some types are already doing this:

irb(main):001:0> 42.dup
TypeError: can't dup Fixnum
	from (irb):1:in `dup'
	from (irb):1
	from /usr/bin/irb:12:in `<main>'

So what I'm leaning towards writing in my specs:

  • If the thing implements Cloneable, expect it to call clone()
  • If it doesn't implement Cloneable, use the current fallback logic which looks for a constructor
  • If there is no usable constructor, expect TypeError

I'll probably still have to go to RSpec to tell them that some collection types might not support #dup.

@trejkaz

This comment has been minimized.

Show comment
Hide comment
@trejkaz

trejkaz Jul 24, 2017

Could you point me towards where the existing specs live for this method? I can't seem to find them in spec/java_integration...

trejkaz commented Jul 24, 2017

Could you point me towards where the existing specs live for this method? I can't seem to find them in spec/java_integration...

@kares

This comment has been minimized.

Show comment
Hide comment
@kares

kares Jul 24, 2017

Member

... just check-out the commit you commented 😉 (put new collection impls under java_integration/fixtures)

Member

kares commented Jul 24, 2017

... just check-out the commit you commented 😉 (put new collection impls under java_integration/fixtures)

@kares kares changed the title from NPE from JavaUtil.tryNewEqualInstance when #dup called on ImmutableList to NPE while dup-ing guava's ImmutableList Jul 24, 2017

@trejkaz

This comment has been minimized.

Show comment
Hide comment
@trejkaz

trejkaz Jul 24, 2017

Ah, indeed... I see what was wrong now, my local copy was out of date. >_>

I have two examples for #dup and two for #clone now, but haven't quite figured out the target to actually run the specs. I'm just waiting for a giant sync to go through first though, because my master was apparently very out of date.

Something I did notice while looking at the code though. IDEA shows some NPE warnings on the same place where I get the NPE, and when I tried adding the null check there to fix the warnings, I realised that it would fall through to the lower fallback where it looks for the no-arg constructor. And then, lo and behold, that lower fallback is already returning the collection itself as a last resort fallback.

So at the moment, the least-resistance fix seems to be to simply put in the missing null check (while maybe also replacing the call to Class#newInstance and adding a catch for UnsupportedOperationException on that addAll) and add the additional specs, without throwing a TypeError at all. And in that situation I wouldn't have to have RSpec catch anything.

trejkaz commented Jul 24, 2017

Ah, indeed... I see what was wrong now, my local copy was out of date. >_>

I have two examples for #dup and two for #clone now, but haven't quite figured out the target to actually run the specs. I'm just waiting for a giant sync to go through first though, because my master was apparently very out of date.

Something I did notice while looking at the code though. IDEA shows some NPE warnings on the same place where I get the NPE, and when I tried adding the null check there to fix the warnings, I realised that it would fall through to the lower fallback where it looks for the no-arg constructor. And then, lo and behold, that lower fallback is already returning the collection itself as a last resort fallback.

So at the moment, the least-resistance fix seems to be to simply put in the missing null check (while maybe also replacing the call to Class#newInstance and adding a catch for UnsupportedOperationException on that addAll) and add the additional specs, without throwing a TypeError at all. And in that situation I wouldn't have to have RSpec catch anything.

@kares

This comment has been minimized.

Show comment
Hide comment
@kares

kares Jul 24, 2017

Member

@trejkaz was mostly interested in showcasing the issue - a failure spec with a stub-ed j.u.Collection impl similar to Guava's to start with. would have helped understand your previous comments and what to do next, I'm really too busy do get into details/understanding your newest proposal from GH comments - but it sounds to me like something we might not need to do in the end ...

Member

kares commented Jul 24, 2017

@trejkaz was mostly interested in showcasing the issue - a failure spec with a stub-ed j.u.Collection impl similar to Guava's to start with. would have helped understand your previous comments and what to do next, I'm really too busy do get into details/understanding your newest proposal from GH comments - but it sounds to me like something we might not need to do in the end ...

@trejkaz

This comment has been minimized.

Show comment
Hide comment
@trejkaz

trejkaz Jul 27, 2017

The sync finished overnight the previous night (it really was that slow...) and then for a day I couldn't do anything, so...

trejkaz@c3db300

Should capture the spirit of it, but I'd feel better if maven had listed the task to run the specs so that I could check whether the error these get would be the same.

trejkaz commented Jul 27, 2017

The sync finished overnight the previous night (it really was that slow...) and then for a day I couldn't do anything, so...

trejkaz@c3db300

Should capture the spirit of it, but I'd feel better if maven had listed the task to run the specs so that I could check whether the error these get would be the same.

@kares

This comment has been minimized.

Show comment
Hide comment
@kares

kares Jul 30, 2017

Member

o.k. thanks ... will look around (e.g. how Scala's collections are setup).
the NonCloneableImmutableList.new.dup part seems a bit scary but if it needs to happen so be it ;(

Member

kares commented Jul 30, 2017

o.k. thanks ... will look around (e.g. how Scala's collections are setup).
the NonCloneableImmutableList.new.dup part seems a bit scary but if it needs to happen so be it ;(

@kares

This comment has been minimized.

Show comment
Hide comment
@kares

kares Feb 5, 2018

Member

have pushed a fix for this issue - there's actually two parts 7307dea and 1ea71f4
first, the NPE is avoided to behave as spec-ed (specs based on @trejkaz's commit did reproduce the same stack-trace on JRuby's end as reported - with Guava). the first part will likely get back-ported for 9.1.
while the second part is for 9.2 only as it changes behaviour slightly in edge cases, please note that an "immutable" non-cloneable collection with a public() constructor will now fail - this is likely the desired behaviour but since it was un-speced territory it will only land in JRuby > 9.1

Member

kares commented Feb 5, 2018

have pushed a fix for this issue - there's actually two parts 7307dea and 1ea71f4
first, the NPE is avoided to behave as spec-ed (specs based on @trejkaz's commit did reproduce the same stack-trace on JRuby's end as reported - with Guava). the first part will likely get back-ported for 9.1.
while the second part is for 9.2 only as it changes behaviour slightly in edge cases, please note that an "immutable" non-cloneable collection with a public() constructor will now fail - this is likely the desired behaviour but since it was un-speced territory it will only land in JRuby > 9.1

@kares

This comment has been minimized.

Show comment
Hide comment
@kares

kares Feb 8, 2018

Member

pushed the first commit to jruby-9.1 ... edd18dd

Member

kares commented Feb 8, 2018

pushed the first commit to jruby-9.1 ... edd18dd

@kares kares closed this Feb 8, 2018

@kares kares modified the milestones: JRuby 9.2.0.0, JRuby 9.1.16.0 Feb 8, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment