Skip to content

Commit 0e654fd

Browse files
committed
first steps at singleClass(context) vs getSingletonClass()
1 parent dabd447 commit 0e654fd

38 files changed

+171
-105
lines changed

core/src/main/java/org/jruby/RubyBasicObject.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,14 @@ public RubyClass getSingletonClass() {
477477
return klass;
478478
}
479479

480+
public RubyClass singletonClass(ThreadContext context) {
481+
RubyClass klass = metaClass.toSingletonClass(this);
482+
483+
if (isFrozen()) klass.setFrozen(true);
484+
485+
return klass;
486+
}
487+
480488
/** rb_make_metaclass
481489
*
482490
* Will create a new meta class, insert this in the chain of
@@ -2597,13 +2605,8 @@ public IRubyObject instance_exec(ThreadContext context, IRubyObject[] args, Bloc
25972605
throw context.runtime.newLocalJumpErrorNoBlock();
25982606
}
25992607

2600-
RubyModule klazz;
2601-
if (isImmediate()) {
2602-
// Ruby uses Qnil here, we use "dummy" because we need a class
2603-
klazz = context.runtime.getDummy();
2604-
} else {
2605-
klazz = getSingletonClass();
2606-
}
2608+
RubyModule klazz = isImmediate() ? // MRI uses Qnil here, we use "dummy" because we need a class
2609+
context.runtime.getDummy() : singletonClass(context);
26072610

26082611
return yieldUnder(context, klazz, args, block, EvalType.INSTANCE_EVAL);
26092612
}

core/src/main/java/org/jruby/RubyBignum.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,15 @@ public BigInteger getBigIntegerValue() {
158158

159159
@Override
160160
public RubyClass getSingletonClass() {
161-
throw typeError(getRuntime().getCurrentContext(), "can't define singleton");
161+
return singletonClass(getRuntime().getCurrentContext());
162162
}
163163

164+
@Override
165+
public RubyClass singletonClass(ThreadContext context) {
166+
throw typeError(context, "can't define singleton");
167+
}
168+
169+
164170
/** Getter for property value.
165171
* @return Value of property value.
166172
*/

core/src/main/java/org/jruby/RubyBinding.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public static RubyClass createBindingClass(ThreadContext context, RubyClass Obje
7575
reifiedClass(RubyBinding.class).
7676
classIndex(ClassIndex.BINDING).
7777
defineMethods(context, RubyBinding.class).
78-
tap(c -> c.getSingletonClass().undefMethods(context, "new"));
78+
tap(c -> c.singletonClass(context).undefMethods(context, "new"));
7979
}
8080

8181
public Binding getBinding() {

core/src/main/java/org/jruby/RubyBoolean.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ public RubyClass getSingletonClass() {
9393
return metaClass;
9494
}
9595

96+
public RubyClass singletonClass(ThreadContext context) {
97+
return metaClass;
98+
}
99+
96100
@Override
97101
public Class<?> getJavaClass() {
98102
return boolean.class;

core/src/main/java/org/jruby/RubyClass.java

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,31 +2893,27 @@ public IRubyObject smartLoadNewUser(IRubyObject target, IRubyObject data) {
28932893
*/
28942894
public IRubyObject smartLoadOldUser(IRubyObject data) {
28952895
ThreadContext context = runtime.getCurrentContext();
2896-
CacheEntry cache;
2897-
if ((cache = getSingletonClass().cachedLoad).token == getSingletonClass().generation) {
2898-
return cache.method.call(context, this, cache.sourceModule, "_load", data);
2899-
} else {
2900-
cache = getSingletonClass().searchWithCache("respond_to?");
2901-
DynamicMethod method = cache.method;
2902-
if (!method.equals(runtime.getRespondToMethod()) && !method.isUndefined()) {
2903-
2904-
// custom respond_to?, cache nothing and use slow path
2905-
if (method.call(context, this, cache.sourceModule, "respond_to?", asSymbol(context, "_load")).isTrue()) {
2906-
return callMethod(context, "_load", data);
2907-
} else {
2908-
throw typeError(context, "class ", this, " needs to have method `_load'");
2909-
}
2910-
2911-
} else if (!(cache = getSingletonClass().searchWithCache("_load")).method.isUndefined()) {
2912-
2913-
// real _load defined, cache and call it
2914-
getSingletonClass().cachedLoad = cache;
2915-
return cache.method.call(context, this, cache.sourceModule, "_load", data);
2916-
2896+
var singleton = singletonClass(context);
2897+
CacheEntry cache = singleton.cachedLoad;
2898+
if (cache.token == singleton.generation) return cache.method.call(context, this, cache.sourceModule, "_load", data);
2899+
2900+
cache = singleton.searchWithCache("respond_to?");
2901+
DynamicMethod method = cache.method;
2902+
if (!method.equals(runtime.getRespondToMethod()) && !method.isUndefined()) {
2903+
// custom respond_to?, cache nothing and use slow path
2904+
if (method.call(context, this, cache.sourceModule, "respond_to?", asSymbol(context, "_load")).isTrue()) {
2905+
return callMethod(context, "_load", data);
29172906
} else {
2918-
// provide an error, since it doesn't exist
29192907
throw typeError(context, "class ", this, " needs to have method `_load'");
29202908
}
2909+
} else if (!(cache = singleton.searchWithCache("_load")).method.isUndefined()) {
2910+
// real _load defined, cache and call it
2911+
singleton.cachedLoad = cache;
2912+
return cache.method.call(context, this, cache.sourceModule, "_load", data);
2913+
2914+
} else {
2915+
// provide an error, since it doesn't exist
2916+
throw typeError(context, "class ", this, " needs to have method `_load'");
29212917
}
29222918
}
29232919

core/src/main/java/org/jruby/RubyComplex.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public static RubyClass createComplexClass(ThreadContext context, RubyClass Nume
7979
defineMethods(context, RubyComplex.class).
8080
undefMethods(context, "<", "<=", ">", ">=", "between?", "clamp", "%", "div", "divmod", "floor", "ceil",
8181
"modulo", "remainder", "round", "step", "truncate", "positive?", "negative?").
82-
tap(c -> c.getSingletonClass().undefMethods(context, "allocate", "new")).
82+
tap(c -> c.singletonClass(context).undefMethods(context, "allocate", "new")).
8383
tap(c -> c.defineConstant("I", RubyComplex.convert(context, c, asFixnum(context, 0), asFixnum(context, 1))));
8484
}
8585

core/src/main/java/org/jruby/RubyContinuation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public static RubyClass createContinuation(ThreadContext context, RubyClass obje
6262
return defineClass(context, "Continuation", objectClass, objectClass.getAllocator()).
6363
reifiedClass(RubyContinuation.class).
6464
classIndex(ClassIndex.CONTINUATION).
65-
tap(c -> c.getSingletonClass().undefMethods(context, "new"));
65+
tap(c -> c.singletonClass(context).undefMethods(context, "new"));
6666
}
6767

6868
@Deprecated

core/src/main/java/org/jruby/RubyEncoding.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public static RubyClass createEncodingClass(ThreadContext context, RubyClass Obj
7979
kindOf(new RubyModule.JavaClassKindOf(RubyEncoding.class)).
8080
classIndex(ClassIndex.ENCODING).
8181
defineMethods(context, RubyEncoding.class).
82-
tap(c -> c.getSingletonClass().undefMethods(context, "allocate"));
82+
tap(c -> c.singletonClass(context).undefMethods(context, "allocate"));
8383
}
8484

8585
private Encoding encoding;

core/src/main/java/org/jruby/RubyFile.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public static RubyClass createFileClass(ThreadContext context, RubyClass IO) {
121121
defineConstant(context, "PATH_SEPARATOR", pathSeparator);
122122

123123
// For JRUBY-5276, physically define FileTest methods on File's singleton
124-
File.getSingletonClass().defineMethods(context, RubyFileTest.FileTestFileMethods.class);
124+
File.singletonClass(context).defineMethods(context, RubyFileTest.FileTestFileMethods.class);
125125

126126
var FileConstants = File.defineModuleUnder(context, "Constants").
127127
defineConstant(context, "RDONLY", asFixnum(context, OpenFlags.O_RDONLY.intValue())).
@@ -205,7 +205,7 @@ public static RubyClass createFileClass(ThreadContext context, RubyClass IO) {
205205
if (!Platform.IS_BSD) {
206206
// lchmod appears to be mostly a BSD-ism, not supported on Linux.
207207
// See https://github.com/jruby/jruby/issues/5547
208-
File.getSingletonClass().searchMethod("lchmod").setNotImplemented(true);
208+
File.singletonClass(context).searchMethod("lchmod").setNotImplemented(true);
209209
}
210210

211211
return File;

core/src/main/java/org/jruby/RubyFixnum.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,12 @@ public boolean isImmediate() {
180180
return true;
181181
}
182182

183-
@Override
184183
public RubyClass getSingletonClass() {
185-
throw typeError(getRuntime().getCurrentContext(), "can't define singleton");
184+
return singletonClass(getRuntime().getCurrentContext());
185+
}
186+
187+
public RubyClass singletonClass(ThreadContext context) {
188+
throw typeError(context, "can't define singleton");
186189
}
187190

188191
@Override

0 commit comments

Comments
 (0)