Skip to content

Commit 66059ef

Browse files
committed
Don't use ReadCallerFrameNode in ModuleNodes.ClassEvalNode class
1 parent 1d1953c commit 66059ef

File tree

4 files changed

+72
-86
lines changed

4 files changed

+72
-86
lines changed

spec/ruby/core/module/shared/class_eval.rb

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,40 +55,49 @@ def foo
5555
it "converts a non-string filename to a string using to_str" do
5656
(file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
5757
ModuleSpecs.send(@method, "1+1", file)
58+
59+
(file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
60+
ModuleSpecs.send(@method, "1+1", file, 15)
5861
end
5962

6063
it "raises a TypeError when the given filename can't be converted to string using to_str" do
6164
(file = mock('123')).should_receive(:to_str).and_return(123)
62-
-> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError)
65+
-> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError, /can't convert MockObject to String/)
6366
end
6467

6568
it "converts non string eval-string to string using to_str" do
6669
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
6770
ModuleSpecs.send(@method, o).should == 2
71+
72+
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
73+
ModuleSpecs.send(@method, o, "file.rb").should == 2
74+
75+
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
76+
ModuleSpecs.send(@method, o, "file.rb", 15).should == 2
6877
end
6978

7079
it "raises a TypeError when the given eval-string can't be converted to string using to_str" do
7180
o = mock('x')
72-
-> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError)
81+
-> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
7382

7483
(o = mock('123')).should_receive(:to_str).and_return(123)
75-
-> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError)
84+
-> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, /can't convert MockObject to String/)
7685
end
7786

7887
it "raises an ArgumentError when no arguments and no block are given" do
79-
-> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError)
88+
-> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
8089
end
8190

8291
it "raises an ArgumentError when more than 3 arguments are given" do
8392
-> {
8493
ModuleSpecs.send(@method, "1 + 1", "some file", 0, "bogus")
85-
}.should raise_error(ArgumentError)
94+
}.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
8695
end
8796

8897
it "raises an ArgumentError when a block and normal arguments are given" do
8998
-> {
9099
ModuleSpecs.send(@method, "1 + 1") { 1 + 1 }
91-
}.should raise_error(ArgumentError)
100+
}.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)")
92101
end
93102

94103
# This case was found because Rubinius was caching the compiled
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
fails:Module#class_eval activates refinements from the eval scope
22
fails:Module#class_eval activates refinements from the eval scope with block
3+
fails:Module#class_eval raises an ArgumentError when more than 3 arguments are given
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
fails:Module#module_eval activates refinements from the eval scope
22
fails:Module#module_eval activates refinements from the eval scope with block
3+
fails:Module#module_eval raises an ArgumentError when more than 3 arguments are given

src/main/java/org/truffleruby/core/module/ModuleNodes.java

Lines changed: 55 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.truffleruby.core.array.RubyArray;
4747
import org.truffleruby.core.cast.BooleanCastWithDefaultNode;
4848
import org.truffleruby.core.cast.NameToJavaStringNode;
49+
import org.truffleruby.core.cast.ToIntNode;
4950
import org.truffleruby.core.cast.ToPathNodeGen;
5051
import org.truffleruby.core.cast.ToStrNode;
5152
import org.truffleruby.core.cast.ToStringOrSymbolNodeGen;
@@ -662,89 +663,78 @@ protected Object isAutoload(RubyModule module, String name, boolean inherit) {
662663
}
663664
}
664665

665-
@CoreMethod(names = { "class_eval", "module_eval" }, optional = 3, lowerFixnum = 3, needsBlock = true)
666-
public abstract static class ClassEvalNode extends CoreMethodArrayArgumentsNode {
666+
@GenerateUncached
667+
@CoreMethod(names = { "class_eval", "module_eval" }, optional = 3, needsBlock = true, alwaysInlined = true)
668+
public abstract static class ClassEvalNode extends AlwaysInlinedMethodNode {
667669

668-
@Child private ReadCallerFrameNode readCallerFrameNode = ReadCallerFrameNode.create();
670+
@Specialization(guards = "isBlockProvided(rubyArgs)")
671+
protected Object evalWithBlock(Frame callerFrame, RubyModule self, Object[] rubyArgs, RootCallTarget target,
672+
@Cached BranchProfile errorProfile,
673+
@Cached(allowUncached = true) ClassExecNode classExecNode) {
674+
final int count = RubyArguments.getPositionalArgumentsCount(rubyArgs, false);
669675

670-
@Specialization(guards = "libCode.isRubyString(code)", limit = "1")
671-
protected Object classEval(
672-
VirtualFrame frame, RubyModule module, Object code, NotProvided file, NotProvided line, Nil block,
673-
@Cached IndirectCallNode callNode,
674-
@Cached RubyStringLibrary libCode) {
675-
return classEvalSource(frame, module, code, "(eval)", callNode);
676-
}
676+
if (count > 0) {
677+
errorProfile.enter();
678+
throw new RaiseException(getContext(), coreExceptions().argumentError(count, 0, this));
679+
}
677680

678-
@Specialization(guards = { "libCode.isRubyString(code)", "libFile.isRubyString(file)" }, limit = "1")
679-
protected Object classEval(
680-
VirtualFrame frame, RubyModule module, Object code, Object file, NotProvided line, Nil block,
681-
@Cached IndirectCallNode callNode,
682-
@Cached RubyStringLibrary libCode,
683-
@Cached RubyStringLibrary libFile,
684-
@Cached ToJavaStringNode toJavaStringNode) {
685-
return classEvalSource(frame, module, code, toJavaStringNode.executeToJavaString(file), callNode);
681+
final Object block = RubyArguments.getBlock(rubyArgs);
682+
return classExecNode.classExec(EmptyArgumentsDescriptor.INSTANCE, self, new Object[]{ self },
683+
(RubyProc) block);
686684
}
687685

688-
@Specialization(guards = { "libCode.isRubyString(code)", "wasProvided(file)" }, limit = "1")
689-
protected Object classEval(VirtualFrame frame, RubyModule module, Object code, Object file, int line, Nil block,
690-
@Cached IndirectCallNode callNode,
691-
@Cached RubyStringLibrary libCode,
692-
@Cached RubyStringLibrary libFile,
693-
@Cached ToJavaStringNode toJavaStringNode) {
694-
final CodeLoader.DeferredCall deferredCall = classEvalSource(
695-
frame,
696-
module,
697-
code,
698-
toJavaStringNode.executeToJavaString(file),
699-
line);
700-
return deferredCall.call(callNode);
701-
}
686+
@Specialization(guards = "!isBlockProvided(rubyArgs)")
687+
protected Object evalWithString(Frame callerFrame, RubyModule self, Object[] rubyArgs, RootCallTarget target,
688+
@Cached BranchProfile errorProfile,
689+
@Cached ToJavaStringNode toJavaStringNode,
690+
@Cached ToStrNode toStrNode,
691+
@Cached ToIntNode toIntNode,
692+
@Cached IndirectCallNode callNode) {
693+
final Object sourceCode;
694+
String fileName = coreStrings().EVAL_FILENAME_STRING.toString();
695+
int line = 1;
702696

703-
@Specialization(guards = "wasProvided(code)")
704-
protected Object classEval(
705-
VirtualFrame frame, RubyModule module, Object code, NotProvided file, NotProvided line, Nil block,
706-
@Cached IndirectCallNode callNode,
707-
@Cached ToStrNode toStrNode) {
708-
return classEvalSource(frame, module, toStrNode.execute(code), "(eval)", callNode);
709-
}
697+
int count = RubyArguments.getPositionalArgumentsCount(rubyArgs, false);
710698

711-
@Specialization(guards = { "libCode.isRubyString(code)", "wasProvided(file)" }, limit = "1")
712-
protected Object classEval(
713-
VirtualFrame frame, RubyModule module, Object code, Object file, NotProvided line, Nil block,
714-
@Cached RubyStringLibrary stringLibrary,
715-
@Cached ToJavaStringNode toJavaStringNode,
716-
@Cached IndirectCallNode callNode,
717-
@Cached RubyStringLibrary libCode,
718-
@Cached ToStrNode toStrNode) {
719-
final String javaString = toJavaStringNode.executeToJavaString(toStrNode.execute(file));
720-
return classEvalSource(frame, module, code, javaString, callNode);
721-
}
699+
if (count == 0) {
700+
errorProfile.enter();
701+
throw new RaiseException(getContext(), coreExceptions().argumentError(0, 1, 2, this));
702+
}
722703

723-
private Object classEvalSource(VirtualFrame frame, RubyModule module, Object code, String file,
724-
@Cached IndirectCallNode callNode) {
725-
final CodeLoader.DeferredCall deferredCall = classEvalSource(frame, module, code, file, 1);
726-
return deferredCall.call(callNode);
727-
}
704+
sourceCode = toStrNode.execute(RubyArguments.getArgument(rubyArgs, 0));
728705

729-
private CodeLoader.DeferredCall classEvalSource(VirtualFrame frame, RubyModule module,
730-
Object rubySource, String file, int line) {
706+
if (count >= 2) {
707+
fileName = toJavaStringNode
708+
.executeToJavaString(toStrNode.execute(RubyArguments.getArgument(rubyArgs, 1)));
709+
}
731710

732-
final MaterializedFrame callerFrame = readCallerFrameNode.execute(frame);
711+
if (count >= 3) {
712+
line = toIntNode.execute(RubyArguments.getArgument(rubyArgs, 2));
713+
}
733714

734-
return classEvalSourceInternal(module, rubySource, file, line, callerFrame);
715+
needCallerFrame(callerFrame, target);
716+
return classEvalSource(
717+
callerFrame.materialize(),
718+
self,
719+
sourceCode,
720+
fileName,
721+
line,
722+
callNode);
735723
}
736724

737725
@TruffleBoundary
738-
private CodeLoader.DeferredCall classEvalSourceInternal(RubyModule module, Object rubySource,
739-
String file, int line, MaterializedFrame callerFrame) {
726+
private Object classEvalSource(MaterializedFrame callerFrame, RubyModule module, Object sourceCode, String file,
727+
int line,
728+
IndirectCallNode callNode) {
740729
final RubySource source = EvalLoader.createEvalSource(
741730
getContext(),
742-
RubyStringLibrary.getUncached().getTString(rubySource),
743-
RubyStringLibrary.getUncached().getEncoding(rubySource),
731+
RubyStringLibrary.getUncached().getTString(sourceCode),
732+
RubyStringLibrary.getUncached().getEncoding(sourceCode),
744733
"class/module_eval",
745734
file,
746735
line,
747736
this);
737+
748738
final LexicalScope lexicalScope = new LexicalScope(
749739
RubyArguments.getMethod(callerFrame).getLexicalScope(),
750740
module);
@@ -756,7 +746,7 @@ private CodeLoader.DeferredCall classEvalSourceInternal(RubyModule module, Objec
756746
lexicalScope,
757747
this);
758748

759-
return getContext().getCodeLoader().prepareExecute(
749+
final CodeLoader.DeferredCall deferredCall = getContext().getCodeLoader().prepareExecute(
760750
callTarget,
761751
ParserContext.MODULE,
762752
new DeclarationContext(
@@ -766,23 +756,8 @@ private CodeLoader.DeferredCall classEvalSourceInternal(RubyModule module, Objec
766756
callerFrame,
767757
module,
768758
lexicalScope);
769-
}
770-
771-
@Specialization
772-
protected Object classEval(
773-
RubyModule self, NotProvided code, NotProvided file, NotProvided line, RubyProc block,
774-
@Cached ClassExecNode classExecNode) {
775-
return classExecNode.classExec(EmptyArgumentsDescriptor.INSTANCE, self, new Object[]{ self }, block);
776-
}
777759

778-
@Specialization
779-
protected Object classEval(RubyModule self, NotProvided code, NotProvided file, NotProvided line, Nil block) {
780-
throw new RaiseException(getContext(), coreExceptions().argumentError(0, 1, 2, this));
781-
}
782-
783-
@Specialization(guards = "wasProvided(code)")
784-
protected Object classEval(RubyModule self, Object code, NotProvided file, NotProvided line, RubyProc block) {
785-
throw new RaiseException(getContext(), coreExceptions().argumentError(1, 0, this));
760+
return deferredCall.call(callNode);
786761
}
787762

788763
}

0 commit comments

Comments
 (0)