1 /***** BEGIN LICENSE BLOCK *****
2 * Version: CPL 1.0/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Common Public
5 * License Version 1.0 (the "License"); you may not use this file
6 * except in compliance with the License. You may obtain a copy of
7 * the License at http://www.eclipse.org/legal/cpl-v10.html
9 * Software distributed under the License is distributed on an "AS
10 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11 * implied. See the License for the specific language governing
12 * rights and limitations under the License.
14 * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
15 * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
16 * Copyright (C) 2004-2005 Thomas E Enebo <enebo@acm.org>
17 * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
19 * Alternatively, the contents of this file may be used under the terms of
20 * either of the GNU General Public License Version 2 or later (the "GPL"),
21 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
22 * in which case the provisions of the GPL or the LGPL are applicable instead
23 * of those above. If you wish to allow use of your version of this file only
24 * under the terms of either the GPL or the LGPL, and not to allow others to
25 * use your version of this file under the terms of the CPL, indicate your
26 * decision by deleting the provisions above and replace them with the notice
27 * and other provisions required by the GPL or the LGPL. If you do not delete
28 * the provisions above, a recipient may use your version of this file under
29 * the terms of any one of the CPL, the GPL or the LGPL.
30 ***** END LICENSE BLOCK *****/
33 import java
.io
.IOException
;
34 import java
.util
.ArrayList
;
35 import java
.util
.Collection
;
36 import java
.util
.Collections
;
38 import org
.jruby
.anno
.JRubyMethod
;
39 import org
.jruby
.anno
.JRubyClass
;
41 import org
.jruby
.internal
.runtime
.methods
.DynamicMethod
;
42 import org
.jruby
.internal
.runtime
.methods
.JavaMethod
;
43 import org
.jruby
.javasupport
.util
.RuntimeHelpers
;
44 import org
.jruby
.runtime
.Block
;
45 import org
.jruby
.runtime
.CallSite
;
46 import org
.jruby
.runtime
.CallSite
.InlineCachingCallSite
;
47 import org
.jruby
.runtime
.CallType
;
48 import org
.jruby
.runtime
.ClassIndex
;
49 import org
.jruby
.runtime
.ObjectAllocator
;
50 import org
.jruby
.runtime
.ObjectMarshal
;
51 import org
.jruby
.runtime
.ThreadContext
;
52 import org
.jruby
.runtime
.Visibility
;
53 import org
.jruby
.runtime
.builtin
.IRubyObject
;
54 import org
.jruby
.runtime
.marshal
.MarshalStream
;
55 import org
.jruby
.runtime
.marshal
.UnmarshalStream
;
56 import org
.jruby
.util
.collections
.WeakHashSet
;
62 @JRubyClass(name
="Class", parent
="Module")
63 public class RubyClass
extends RubyModule
{
64 public static final int CS_IDX_INITIALIZE
= 0;
65 public static final String
[] CS_NAMES
= {
68 private final CallSite
[] baseCallSites
= new CallSite
[CS_NAMES
.length
];
70 for(int i
= 0; i
< CS_NAMES
.length
; i
++) {
71 baseCallSites
[i
] = new InlineCachingCallSite(CS_NAMES
[i
], CallType
.FUNCTIONAL
);
75 private CallSite
[] extraCallSites
;
77 public static void createClassClass(Ruby runtime
, RubyClass classClass
) {
78 classClass
.index
= ClassIndex
.CLASS
;
79 classClass
.kindOf
= new RubyModule
.KindOf() {
81 public boolean isKindOf(IRubyObject obj
, RubyModule type
) {
82 return obj
instanceof RubyClass
;
86 classClass
.undefineMethod("module_function");
87 classClass
.undefineMethod("append_features");
88 classClass
.undefineMethod("extend_object");
90 classClass
.defineAnnotatedMethods(RubyClass
.class);
92 classClass
.addMethod("new", new SpecificArityNew(classClass
, Visibility
.PUBLIC
));
94 // This is a non-standard method; have we decided to start extending Ruby?
95 //classClass.defineFastMethod("subclasses", callbackFactory.getFastOptMethod("subclasses"));
97 // FIXME: for some reason this dispatcher causes a VerifyError...
98 //classClass.dispatcher = callbackFactory.createDispatcher(classClass);
101 public static final ObjectAllocator CLASS_ALLOCATOR
= new ObjectAllocator() {
102 public IRubyObject
allocate(Ruby runtime
, RubyClass klass
) {
103 RubyClass clazz
= new RubyClass(runtime
);
104 clazz
.allocator
= ObjectAllocator
.NOT_ALLOCATABLE_ALLOCATOR
; // Class.allocate object is not allocatable before it is initialized
109 public ObjectAllocator
getAllocator() {
113 public void setAllocator(ObjectAllocator allocator
) {
114 this.allocator
= allocator
;
117 @JRubyMethod(name
= "allocate")
118 public IRubyObject
allocate() {
119 if (superClass
== null) throw runtime
.newTypeError("can't instantiate uninitialized class");
120 IRubyObject obj
= allocator
.allocate(runtime
, this);
121 if (obj
.getMetaClass().getRealClass() != getRealClass()) throw runtime
.newTypeError("wrong instance allocation");
125 public CallSite
[] getExtraCallSites() {
126 return extraCallSites
;
130 public int getNativeTypeIndex() {
131 return ClassIndex
.CLASS
;
135 public boolean isModule() {
140 public boolean isClass() {
145 public boolean isSingleton() {
150 * Create an initial Object meta class before Module and Kernel dependencies have
151 * squirreled themselves together.
153 * @param runtime we need it
154 * @return a half-baked meta class for object
156 public static RubyClass
createBootstrapClass(Ruby runtime
, String name
, RubyClass superClass
, ObjectAllocator allocator
) {
159 if (superClass
== null ) { // boot the Object class
160 obj
= new RubyClass(runtime
);
161 obj
.marshal
= DEFAULT_OBJECT_MARSHAL
;
162 } else { // boot the Module and Class classes
163 obj
= new RubyClass(runtime
, superClass
);
165 obj
.setAllocator(allocator
);
166 obj
.setBaseName(name
);
170 private final Ruby runtime
;
171 private ObjectAllocator allocator
; // the default allocator
172 protected ObjectMarshal marshal
;
173 private Set
<RubyClass
> subclasses
;
175 /** separate path for MetaClass and IncludedModuleWrapper construction
176 * (rb_class_boot version for MetaClasses)
177 * no marshal, allocator initialization and addSubclass(this) here!
179 protected RubyClass(Ruby runtime
, RubyClass superClass
, boolean objectSpace
) {
180 super(runtime
, runtime
.getClassClass(), objectSpace
);
181 this.runtime
= runtime
;
182 this.superClass
= superClass
; // this is the only case it might be null here (in MetaClass construction)
185 /** used by CLASS_ALLOCATOR (any Class' class will be a Class!)
186 * also used to bootstrap Object class
188 protected RubyClass(Ruby runtime
) {
189 super(runtime
, runtime
.getClassClass());
190 this.runtime
= runtime
;
191 index
= ClassIndex
.CLASS
;
194 /** rb_class_boot (for plain Classes)
195 * also used to bootstrap Module and Class classes
197 protected RubyClass(Ruby runtime
, RubyClass superClazz
) {
199 superClass
= superClazz
;
200 marshal
= superClazz
.marshal
; // use parent's marshal
201 superClazz
.addSubclass(this);
203 infectBy(superClass
);
207 * A constructor which allows passing in an array of supplementary call sites.
209 protected RubyClass(Ruby runtime
, RubyClass superClazz
, CallSite
[] extraCallSites
) {
211 this.superClass
= superClazz
;
212 this.marshal
= superClazz
.marshal
; // use parent's marshal
213 superClazz
.addSubclass(this);
215 this.extraCallSites
= extraCallSites
;
217 infectBy(superClass
);
221 * Construct a new class with the given name scoped under Object (global)
222 * and with Object as its immediate superclass.
223 * Corresponds to rb_class_new in MRI.
225 public static RubyClass
newClass(Ruby runtime
, RubyClass superClass
) {
226 if (superClass
== runtime
.getClassClass()) throw runtime
.newTypeError("can't make subclass of Class");
227 if (superClass
.isSingleton()) throw runtime
.newTypeError("can't make subclass of virtual class");
228 return new RubyClass(runtime
, superClass
);
232 * A variation on newClass that allow passing in an array of supplementary
233 * call sites to improve dynamic invocation.
235 public static RubyClass
newClass(Ruby runtime
, RubyClass superClass
, CallSite
[] extraCallSites
) {
236 if (superClass
== runtime
.getClassClass()) throw runtime
.newTypeError("can't make subclass of Class");
237 if (superClass
.isSingleton()) throw runtime
.newTypeError("can't make subclass of virtual class");
238 return new RubyClass(runtime
, superClass
, extraCallSites
);
242 * Construct a new class with the given name, allocator, parent class,
243 * and containing class. If setParent is true, the class's parent will be
244 * explicitly set to the provided parent (rather than the new class just
245 * being assigned to a constant in that parent).
246 * Corresponds to rb_class_new/rb_define_class_id/rb_name_class/rb_set_class_path
249 public static RubyClass
newClass(Ruby runtime
, RubyClass superClass
, String name
, ObjectAllocator allocator
, RubyModule parent
, boolean setParent
) {
250 RubyClass clazz
= newClass(runtime
, superClass
);
251 clazz
.setBaseName(name
);
252 clazz
.setAllocator(allocator
);
253 clazz
.makeMetaClass(superClass
.getMetaClass());
254 if (setParent
) clazz
.setParent(parent
);
255 parent
.setConstant(name
, clazz
);
256 clazz
.inherit(superClass
);
261 * A variation on newClass that allows passing in an array of supplementary
262 * call sites to improve dynamic invocation performance.
264 public static RubyClass
newClass(Ruby runtime
, RubyClass superClass
, String name
, ObjectAllocator allocator
, RubyModule parent
, boolean setParent
, CallSite
[] extraCallSites
) {
265 RubyClass clazz
= newClass(runtime
, superClass
, extraCallSites
);
266 clazz
.setBaseName(name
);
267 clazz
.setAllocator(allocator
);
268 clazz
.makeMetaClass(superClass
.getMetaClass());
269 if (setParent
) clazz
.setParent(parent
);
270 parent
.setConstant(name
, clazz
);
271 clazz
.inherit(superClass
);
275 /** rb_make_metaclass
279 public RubyClass
makeMetaClass(RubyClass superClass
) {
280 if (isSingleton()) { // could be pulled down to RubyClass in future
281 MetaClass klass
= new MetaClass(getRuntime(), superClass
); // rb_class_boot
284 klass
.setAttached(this);
285 klass
.setMetaClass(klass
);
286 klass
.setSuperClass(getSuperClass().getRealClass().getMetaClass());
290 return super.makeMetaClass(superClass
);
295 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, int methodIndex
, String name
, IRubyObject
[] args
, CallType callType
, Block block
) {
296 return invoke(context
, self
, name
, args
, callType
, block
);
299 public boolean notVisibleAndNotMethodMissing(DynamicMethod method
, String name
, IRubyObject caller
, CallType callType
) {
300 return !method
.isCallableFrom(caller
, callType
) && !name
.equals("method_missing");
303 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
304 CallType callType
, Block block
) {
305 DynamicMethod method
= searchMethod(name
);
306 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
307 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, context
.getFrameSelf(), callType
, block
);
309 return method
.call(context
, self
, this, name
, block
);
312 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
, Block block
) {
313 DynamicMethod method
= searchMethod(name
);
314 if (method
.isUndefined()) {
315 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, block
);
317 return method
.call(context
, self
, this, name
, block
);
320 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
321 IRubyObject
[] args
, CallType callType
, Block block
) {
323 DynamicMethod method
= searchMethod(name
);
324 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
325 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, args
, context
.getFrameSelf(), callType
, block
);
327 return method
.call(context
, self
, this, name
, args
, block
);
330 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
,
331 IRubyObject
[] args
, Block block
) {
333 DynamicMethod method
= searchMethod(name
);
334 if (method
.isUndefined()) {
335 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, args
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, block
);
337 return method
.call(context
, self
, this, name
, args
, block
);
340 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
341 IRubyObject arg
, CallType callType
, Block block
) {
342 DynamicMethod method
= searchMethod(name
);
343 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
344 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg
, context
.getFrameSelf(), callType
, block
);
346 return method
.call(context
, self
, this, name
, arg
, block
);
349 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
,
350 IRubyObject arg
, Block block
) {
351 DynamicMethod method
= searchMethod(name
);
352 if (method
.isUndefined()) {
353 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, block
);
355 return method
.call(context
, self
, this, name
, arg
, block
);
358 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
359 IRubyObject arg0
, IRubyObject arg1
, CallType callType
, Block block
) {
360 DynamicMethod method
= searchMethod(name
);
361 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
362 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg0
, arg1
, context
.getFrameSelf(), callType
, block
);
364 return method
.call(context
, self
, this, name
, arg0
, arg1
, block
);
367 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
,
368 IRubyObject arg0
, IRubyObject arg1
, Block block
) {
369 DynamicMethod method
= searchMethod(name
);
370 if (method
.isUndefined()) {
371 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg0
, arg1
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, block
);
373 return method
.call(context
, self
, this, name
, arg0
, arg1
, block
);
376 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
377 IRubyObject arg0
, IRubyObject arg1
, IRubyObject arg2
, CallType callType
, Block block
) {
378 DynamicMethod method
= searchMethod(name
);
379 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
380 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg0
, arg1
, arg2
, context
.getFrameSelf(), callType
, block
);
382 return method
.call(context
, self
, this, name
, arg0
, arg1
, arg2
, block
);
385 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
,
386 IRubyObject arg0
, IRubyObject arg1
, IRubyObject arg2
, Block block
) {
387 DynamicMethod method
= searchMethod(name
);
388 if (method
.isUndefined()) {
389 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg0
, arg1
, arg2
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, block
);
391 return method
.call(context
, self
, this, name
, arg0
, arg1
, arg2
, block
);
394 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
396 DynamicMethod method
= searchMethod(name
);
397 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
398 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, context
.getFrameSelf(), callType
, Block
.NULL_BLOCK
);
400 return method
.call(context
, self
, this, name
);
403 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
) {
404 DynamicMethod method
= searchMethod(name
);
405 if (method
.isUndefined()) {
406 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, Block
.NULL_BLOCK
);
408 return method
.call(context
, self
, this, name
);
411 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
412 IRubyObject
[] args
, CallType callType
) {
414 DynamicMethod method
= searchMethod(name
);
415 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
416 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, args
, context
.getFrameSelf(), callType
, Block
.NULL_BLOCK
);
418 return method
.call(context
, self
, this, name
, args
);
421 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
,
422 IRubyObject
[] args
) {
424 DynamicMethod method
= searchMethod(name
);
425 if (method
.isUndefined()) {
426 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, args
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, Block
.NULL_BLOCK
);
428 return method
.call(context
, self
, this, name
, args
);
431 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
432 IRubyObject arg
, CallType callType
) {
433 DynamicMethod method
= searchMethod(name
);
434 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
435 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg
, context
.getFrameSelf(), callType
, Block
.NULL_BLOCK
);
437 return method
.call(context
, self
, this, name
, arg
);
440 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
,
442 DynamicMethod method
= searchMethod(name
);
443 if (method
.isUndefined()) {
444 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, Block
.NULL_BLOCK
);
446 return method
.call(context
, self
, this, name
, arg
);
449 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
450 IRubyObject arg0
, IRubyObject arg1
, CallType callType
) {
451 DynamicMethod method
= searchMethod(name
);
452 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
453 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg0
, arg1
, context
.getFrameSelf(), callType
, Block
.NULL_BLOCK
);
455 return method
.call(context
, self
, this, name
, arg0
, arg1
);
458 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
,
459 IRubyObject arg0
, IRubyObject arg1
) {
460 DynamicMethod method
= searchMethod(name
);
461 if (method
.isUndefined()) {
462 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg0
, arg1
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, Block
.NULL_BLOCK
);
464 return method
.call(context
, self
, this, name
, arg0
, arg1
);
467 public IRubyObject
invoke(ThreadContext context
, IRubyObject self
, String name
,
468 IRubyObject arg0
, IRubyObject arg1
, IRubyObject arg2
, CallType callType
) {
469 DynamicMethod method
= searchMethod(name
);
470 if (method
.isUndefined() || notVisibleAndNotMethodMissing(method
, name
, context
.getFrameSelf(), callType
)) {
471 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg0
, arg1
, arg2
, context
.getFrameSelf(), callType
, Block
.NULL_BLOCK
);
473 return method
.call(context
, self
, this, name
, arg0
, arg1
, arg2
);
476 public IRubyObject
finvoke(ThreadContext context
, IRubyObject self
, String name
,
477 IRubyObject arg0
, IRubyObject arg1
, IRubyObject arg2
) {
478 DynamicMethod method
= searchMethod(name
);
479 if (method
.isUndefined()) {
480 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, name
, arg0
, arg1
, arg2
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, Block
.NULL_BLOCK
);
482 return method
.call(context
, self
, this, name
, arg0
, arg1
, arg2
);
485 public IRubyObject
invokeInherited(ThreadContext context
, IRubyObject self
, IRubyObject subclass
) {
486 DynamicMethod method
= getMetaClass().searchMethod("inherited");
488 if (method
.isUndefined()) {
489 return RuntimeHelpers
.callMethodMissing(context
, self
, method
, "inherited", subclass
, context
.getFrameSelf(), CallType
.FUNCTIONAL
, Block
.NULL_BLOCK
);
492 return method
.call(context
, self
, getMetaClass(), "inherited", subclass
, Block
.NULL_BLOCK
);
495 /** rb_class_new_instance
498 public IRubyObject
newInstance(ThreadContext context
, IRubyObject
[] args
, Block block
) {
499 IRubyObject obj
= allocate();
500 baseCallSites
[CS_IDX_INITIALIZE
].call(context
, obj
, args
, block
);
504 // TODO: replace this with a smarter generated invoker that can handle 0-N args
505 public static class SpecificArityNew
extends JavaMethod
{
506 public SpecificArityNew(RubyModule implClass
, Visibility visibility
) {
507 super(implClass
, visibility
);
509 public IRubyObject
call(ThreadContext context
, IRubyObject self
, RubyModule clazz
, String name
, IRubyObject
[] args
, Block block
) {
510 RubyClass cls
= (RubyClass
)self
;
511 IRubyObject obj
= cls
.allocate();
512 cls
.baseCallSites
[CS_IDX_INITIALIZE
].call(context
, obj
, args
, block
);
515 public IRubyObject
call(ThreadContext context
, IRubyObject self
, RubyModule clazz
, String name
, Block block
) {
516 RubyClass cls
= (RubyClass
)self
;
517 IRubyObject obj
= cls
.allocate();
518 cls
.baseCallSites
[CS_IDX_INITIALIZE
].call(context
, obj
, block
);
521 public IRubyObject
call(ThreadContext context
, IRubyObject self
, RubyModule clazz
, String name
, IRubyObject arg0
, Block block
) {
522 RubyClass cls
= (RubyClass
)self
;
523 IRubyObject obj
= cls
.allocate();
524 cls
.baseCallSites
[CS_IDX_INITIALIZE
].call(context
, obj
, arg0
, block
);
527 public IRubyObject
call(ThreadContext context
, IRubyObject self
, RubyModule clazz
, String name
, IRubyObject arg0
, IRubyObject arg1
, Block block
) {
528 RubyClass cls
= (RubyClass
)self
;
529 IRubyObject obj
= cls
.allocate();
530 cls
.baseCallSites
[CS_IDX_INITIALIZE
].call(context
, obj
, arg0
, arg1
, block
);
533 public IRubyObject
call(ThreadContext context
, IRubyObject self
, RubyModule clazz
, String name
, IRubyObject arg0
, IRubyObject arg1
, IRubyObject arg2
, Block block
) {
534 RubyClass cls
= (RubyClass
)self
;
535 IRubyObject obj
= cls
.allocate();
536 cls
.baseCallSites
[CS_IDX_INITIALIZE
].call(context
, obj
, arg0
, arg1
, arg2
, block
);
541 /** rb_class_initialize
544 @JRubyMethod(name
= "initialize", optional
= 1, frame
= true, visibility
= Visibility
.PRIVATE
)
545 public IRubyObject
initialize(IRubyObject
[] args
, Block block
) {
546 if (superClass
!= null) {
547 throw getRuntime().newTypeError("already initialized class");
550 IRubyObject superObject
;
551 if (args
.length
== 0) {
552 superObject
= getRuntime().getObject();
554 superObject
= args
[0];
555 checkInheritable(superObject
);
558 RubyClass superClazz
= (RubyClass
) superObject
;
560 superClass
= superClazz
;
561 allocator
= superClazz
.allocator
;
562 makeMetaClass(superClazz
.getMetaClass());
564 marshal
= superClazz
.marshal
;
566 superClazz
.addSubclass(this);
568 super.initialize(block
);
575 /** rb_class_init_copy
578 @JRubyMethod(name
= "initialize_copy", required
= 1)
580 public IRubyObject
initialize_copy(IRubyObject original
){
581 if (superClass
!= null) throw runtime
.newTypeError("already initialized class");
582 if (original
instanceof MetaClass
) throw getRuntime().newTypeError("can't copy singleton class");
584 super.initialize_copy(original
);
585 allocator
= ((RubyClass
)original
).allocator
;
589 // TODO: Someday, enable.
590 // @JRubyMethod(name = "subclasses", optional = 1)
591 public IRubyObject
subclasses(ThreadContext context
, IRubyObject
[] args
) {
592 boolean recursive
= false;
593 if (args
.length
== 1) {
594 if (args
[0] instanceof RubyBoolean
) {
595 recursive
= args
[0].isTrue();
597 context
.getRuntime().newTypeError(args
[0], context
.getRuntime().fastGetClass("Boolean"));
601 return RubyArray
.newArray(context
.getRuntime(), subclasses(recursive
)).freeze(context
);
604 public Collection
subclasses(boolean includeDescendants
) {
605 if (subclasses
!= null) {
606 Collection
<RubyClass
> mine
= new ArrayList
<RubyClass
>(subclasses
);
607 if (includeDescendants
) {
608 for (RubyClass i
: subclasses
) {
609 mine
.addAll(i
.subclasses(includeDescendants
));
615 return Collections
.EMPTY_LIST
;
619 public synchronized void addSubclass(RubyClass subclass
) {
620 if (subclasses
== null) subclasses
= new WeakHashSet
<RubyClass
>();
621 subclasses
.add(subclass
);
624 public Ruby
getClassRuntime() {
628 public RubyClass
getRealClass() {
632 @JRubyMethod(name
= "inherited", required
= 1)
633 public IRubyObject
inherited(ThreadContext context
, IRubyObject arg
) {
634 return context
.getRuntime().getNil();
637 /** rb_class_inherited (reversed semantics!)
640 public void inherit(RubyClass superClazz
) {
641 if (superClazz
== null) superClazz
= getRuntime().getObject();
643 superClazz
.invokeInherited(getRuntime().getCurrentContext(), superClazz
, this);
646 /** Return the real super class of this class.
648 * rb_class_superclass
651 @JRubyMethod(name
= "superclass")
652 public IRubyObject
superclass(ThreadContext context
) {
653 RubyClass superClazz
= superClass
;
655 if (superClazz
== null) throw context
.getRuntime().newTypeError("uninitialized class");
657 if (isSingleton()) superClazz
= metaClass
;
658 while (superClazz
!= null && superClazz
.isIncluded()) superClazz
= superClazz
.superClass
;
660 return superClazz
!= null ? superClazz
: context
.getRuntime().getNil();
663 /** rb_check_inheritable
666 public static void checkInheritable(IRubyObject superClass
) {
667 if (!(superClass
instanceof RubyClass
)) {
668 throw superClass
.getRuntime().newTypeError("superclass must be a Class (" + superClass
.getMetaClass() + " given)");
670 if (((RubyClass
)superClass
).isSingleton()) {
671 throw superClass
.getRuntime().newTypeError("can't make subclass of virtual class");
675 public final ObjectMarshal
getMarshal() {
679 public final void setMarshal(ObjectMarshal marshal
) {
680 this.marshal
= marshal
;
683 public final void marshal(Object obj
, MarshalStream marshalStream
) throws IOException
{
684 getMarshal().marshalTo(getRuntime(), obj
, this, marshalStream
);
687 public final Object
unmarshal(UnmarshalStream unmarshalStream
) throws IOException
{
688 return getMarshal().unmarshalFrom(getRuntime(), this, unmarshalStream
);
691 public static void marshalTo(RubyClass clazz
, MarshalStream output
) throws java
.io
.IOException
{
692 output
.registerLinkTarget(clazz
);
693 output
.writeString(MarshalStream
.getPathFromClass(clazz
));
696 public static RubyClass
unmarshalFrom(UnmarshalStream input
) throws java
.io
.IOException
{
697 String name
= RubyString
.byteListToString(input
.unmarshalString());
698 RubyClass result
= UnmarshalStream
.getClassFromPath(input
.getRuntime(), name
);
699 input
.registerLinkTarget(result
);
703 protected static final ObjectMarshal DEFAULT_OBJECT_MARSHAL
= new ObjectMarshal() {
704 public void marshalTo(Ruby runtime
, Object obj
, RubyClass type
,
705 MarshalStream marshalStream
) throws IOException
{
706 IRubyObject object
= (IRubyObject
)obj
;
708 marshalStream
.registerLinkTarget(object
);
709 marshalStream
.dumpVariables(object
.getVariableList());
712 public Object
unmarshalFrom(Ruby runtime
, RubyClass type
,
713 UnmarshalStream unmarshalStream
) throws IOException
{
714 IRubyObject result
= type
.allocate();
716 unmarshalStream
.registerLinkTarget(result
);
718 unmarshalStream
.defaultVariablesUnmarshal(result
);