/
object.hpp
483 lines (379 loc) · 13.7 KB
/
object.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
#ifndef RBX_VM_BUILTIN_OBJECT_HPP
#define RBX_VM_BUILTIN_OBJECT_HPP
#include <vector>
#include "vm.hpp"
#include "vm/oop.hpp"
#include "vm/type_info.hpp"
#include "vm/lookup_data.hpp"
#include "executor.hpp"
namespace rubinius {
/**
* Create a writer method for a slot.
*
* For attr_writer(foo, SomeClass), creates void foo(STATE, SomeClass* obj)
* that sets the instance variable foo_ to the object given and runs the write
* barrier.
*/
#define attr_writer(name, type) \
template <class T> \
void name(T state, type* obj) { \
name ## _ = obj; \
if(mature_object_p()) this->write_barrier(state, obj); \
}
/**
* Create a reader method for a slot.
*
* For attr_reader(foo, SomeClass), creates SomeClass* foo() which returns the
* instance variable foo_. A const version is also generated.
*/
#define attr_reader(name, type) \
type* name() { return name ## _; } \
const type* name() const { return name ## _; }
/**
* Ruby-like accessor creation for a slot.
*
* Both attr_writer and attr_reader.
*/
#define attr_accessor(name, type) \
attr_reader(name, type) \
attr_writer(name, type)
/* Forwards */
class Fixnum;
class Integer;
class String;
class Module;
class Executable;
class Array;
class TypeInfo;
class Object;
typedef std::vector<Object*> ObjectArray;
/**
* Object is the basic Ruby object.
*
* Because of needing to exactly control the in-memory layout of
* Objects, none of the subclasses of Object (or ObjectHeader)
* is allowed to use define virtual methods. In order to achieve
* virtual dispatch for the cases where it is needed (it usually
* is not), the TypeInfo class should be used. Each builtin class
* defines a contained type Info which inherits--directly or not
* from TypeInfo. TypeInfos use virtual methods to achieve dynamism.
* Instances of these Info classes are held by the VM, where they
* can be retrieved using a given Object's object_type. The Info
* object will then dispatch the correct virtual method for the
* type. The methods are written to understand the types they are
* dealing with.
*
* The class definition layout differs from the normal alphabetic
* order in order to group the different aspects involved better
* and to simplify finding/adding &c. related methods.
*
* @todo The entire codebase should be reviewed for const
* correctness. --rue
*
* @todo Remove the unimplemented definitions? --rue
*
* @see vm/type_info.hpp
*
*/
class Object : public ObjectHeader {
public: /* Slots and bookkeeping */
/** Class type identifier. */
static const object_type type = ObjectType;
static void bootstrap_methods(STATE);
public: /* GC support, bookkeeping &c. */
/** Provides access to the GC write barrier from any object. */
void write_barrier(STATE, void* obj);
void inline_write_barrier_passed(STATE, void* obj);
void write_barrier(VM*, void* obj);
void inline_write_barrier_passed(VM*, void* obj);
/** Special-case write_barrier() for Fixnums. */
void write_barrier(STATE, Fixnum* obj);
/** Special-case write_barrier() for Symbols. */
void write_barrier(STATE, Symbol* obj);
void write_barrier(gc::WriteBarrier* wb, void* obj);
void setup_allocation_site(STATE, CallFrame* call_frame = NULL);
public: /* Type information, field access, copy support &c. */
/**
* Returns a copy of this object. This is NOT the same as Ruby
* Kernel#dup. Code that needs Kernel#dup semantics MUST call
* #dup from Ruby. This method is used in the VM to duplicate
* data structures. It will not call the Ruby allocate() or
* initialize_copy() methods.
*/
Object* duplicate(STATE);
Object* copy_object(STATE, Object* other);
/**
* Copies the object including any instance variables. Called by
* Kernel#dup.
*/
// Rubinius.primitive :object_copy_object
Object* copy_object_prim(STATE, Object* other, CallFrame* calling_environment);
/**
* Copies this Object's MetaClass to the other Object. Called
* by Kernel#clone.
*/
// Rubinius.primitive :object_copy_singleton_class
Object* copy_singleton_class(STATE, GCToken gct, Object* other);
/** True if this Object* is actually a Fixnum, false otherwise. */
bool fixnum_p() const;
/**
* Retrieve the Object stored in given field index of this Object.
*
* Uses TypeInfo.
*/
Object* get_field(STATE, std::size_t index);
/** Safely return the object type, even if the receiver is an immediate. */
object_type get_type() const;
/** True if given Module is this Object's class, superclass or an included Module. */
bool kind_of_p(STATE, Object* module);
/** Store the given Object at given field index of this Object through TypeInfo. */
void set_field(STATE, std::size_t index, Object* val);
/** True if this Object* is actually a Symbol, false otherwise. */
bool symbol_p() const;
/** Return the TypeInfo for this Object's type. */
TypeInfo* type_info(STATE) const;
public: /* Method dispatch stuff */
/** Class object in which to look for the MethodTable for this Object. */
Class* lookup_begin(STATE);
/**
* Directly send a method to this Object.
*
* Sets up the current task to send the given method name to this
* Object, passing the given number of arguments through varargs.
*/
Object* send(STATE, CallFrame* caller, Symbol* name, Array* args,
Object* block = cNil, bool allow_private = true);
Object* send(STATE, CallFrame* caller, Symbol* name, bool allow_private = true);
Object* send_prim(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args,
Symbol* min_visibility);
/**
* Ruby #send/#__send__
*/
// Rubinius.primitive? :object_send
Object* private_send_prim(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args);
/**
* Ruby #public_send
*/
// Rubinius.primitive? :object_public_send
Object* public_send_prim(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args);
public: /* Ruby interface */
/** Returns the Class object of which this Object is an instance. */
// Rubinius.primitive+ :object_class
Class* class_object(STATE) const;
/**
* Ruby #equal?.
*
* Returns true if and only if this and the other object are
* the SAME object, false otherwise.
*/
// Rubinius.primitive :object_equal
Object* equal(STATE, Object* other);
/** Sets the frozen flag. Rubinius does NOT currently support freezing. */
// Rubinius.primitive :object_freeze
Object* freeze(STATE);
/** Returns true if this Object's frozen flag set, false otherwise. */
// Rubinius.primitive :object_frozen_p
Object* frozen_p(STATE);
/**
* Ruby #instance_variable_get.
*
* Return the Object stored as instance variable under the given
* identifier.
*/
// Rubinius.primitive :object_get_ivar
Object* get_ivar_prim(STATE, Symbol* sym);
Object* get_ivar(STATE, Symbol* sym);
// A version that only attempts to find +sym+ in the ivars slot
Object* get_table_ivar(STATE, Symbol* sym);
// Rubinius.primitive :object_del_ivar
Object* del_ivar(STATE, Symbol* sym);
Object* del_table_ivar(STATE, Symbol* sym, bool* removed = 0);
Object* table_ivar_defined(STATE, Symbol* sym);
Object* ivar_defined(STATE, Symbol* sym);
// Rubinius.primitive :object_ivar_defined
Object* ivar_defined_prim(STATE, Symbol* sym);
/** Returns the structure containing this object's instance variables. */
// Rubinius.primitive :object_ivar_names
Array* ivar_names(STATE);
Array* ivar_names(STATE, Array* ary);
/** Calculate a hash value for this object. */
hashval hash(STATE);
/** Returns the hash value as an Integer. @see hash(). */
// Rubinius.primitive :object_hash
Integer* hash_prim(STATE);
/** Returns an Integer ID for this object. Created as needed. */
// Rubinius.primitive :object_id
Integer* id(STATE);
/** Indicates if this object has been assigned an object id. */
bool has_id(STATE);
/** Reset the object id */
void reset_id(STATE);
// Rubinius.primitive :object_infect
Object* infect_prim(STATE, Object* obj, Object* other) {
other->infect(state, obj);
return obj;
}
/**
* Taints other if this is tainted.
*/
void infect(STATE, Object* other);
/**
* Ruby #kind_of?
*
* Returns true if given Module is this Object's class,
* superclass or an included Module, false otherwise.
*/
// Rubinius.primitive :object_kind_of
Object* kind_of_prim(STATE, Module* klass);
/**
* Ruby #instance_of?
*
* Returns true if given Module is this Object's class,
* false otherwise.
*/
// Rubinius.primitive :object_instance_of
Object* instance_of_prim(STATE, Module* klass);
/** Return object's MetaClass object. Created as needed. */
Class* singleton_class(STATE);
/**
* Ruby #instance_variable_set
*
* Store the given object in the instance variable by
* given identifier.
*/
// Rubinius.primitive :object_set_ivar
Object* set_ivar_prim(STATE, Symbol* sym, Object* val);
Object* set_ivar(STATE, Symbol* sym, Object* val);
// Specialized version that only checks ivars_
Object* set_table_ivar(STATE, Symbol* sym, Object* val);
/** String describing this object (through TypeInfo.) */
// Rubinius.primitive :object_show
Object* show(STATE);
/** Indented String describing this object (through TypeInfo.) */
Object* show(STATE, int level);
/** Shorter String describing this object (through TypeInfo.) */
Object* show_simple(STATE);
/** Shorter indented String describing this object (through TypeInfo.) */
Object* show_simple(STATE, int level);
/**
* Set tainted flag on this object.
*/
// Rubinius.primitive :object_taint
Object* taint(STATE);
/**
* Returns true if this object's tainted flag is set.
*/
// Rubinius.primitive :object_tainted_p
Object* tainted_p(STATE);
/**
* Clears the tainted flag on this object.
*/
// Rubinius.primitive :object_untaint
Object* untaint(STATE);
/**
* Returns true if this object's untrusted flag is set.
*/
// Rubinius.primitive :object_untrusted_p
Object* untrusted_p(STATE);
/**
* Sets the untrusted flag on this object.
*/
// Rubinius.primitive :object_untrust
Object* untrust(STATE);
/**
* Clears the untrusted flag on this object.
*/
// Rubinius.primitive :object_trust
Object* trust(STATE);
/**
* Returns an #inspect-like representation of an Object for
* use in C++ code. Not called from Ruby code.
*
* If address is true, uses the actual address of the object.
* Otherwise, uses the object's id().
*/
String* to_s(STATE, bool address = false);
/**
*
* Returns cTrue if this responds to method +meth+
*/
// Rubinius.primitive :object_respond_to
Object* respond_to(STATE, Symbol* name, Object* priv);
// Rubinius.primitive :object_respond_to_public
Object* respond_to_public(STATE, Object* obj);
/**
* Checks if object is frozen and raises RuntimeError if it is.
* Similar to CRuby rb_check_frozen
*/
void check_frozen(STATE);
public: /* accessors */
/* klass_ from ObjectHeader. */
attr_accessor(klass, Class);
/* ivars_ from ObjectHeader. */
attr_accessor(ivars, Object);
public: /* TypeInfo */
/**
* Static type information for Object.
*/
class Info : public TypeInfo {
public:
virtual ~Info() {}
Info(object_type type)
: TypeInfo(type)
{}
virtual void auto_mark(Object* obj, ObjectMark& mark) {}
};
private:
// Define these as private and without implementation so we
// don't accidently let C++ create them.
Object();
~Object();
Object(const Object&);
Object& operator= (const Object&);
};
/* Object inlines -- Alphabetic, unlike class definition. */
inline bool Object::fixnum_p() const {
return __FIXNUM_P__(this);
}
inline Class* Object::lookup_begin(STATE) {
if(reference_p()) {
return klass_;
}
return state->globals().special_classes[((uintptr_t)this) & SPECIAL_CLASS_MASK].get();
}
inline bool Object::symbol_p() const {
return __SYMBOL_P__(this);
}
inline void Object::write_barrier(STATE, Fixnum* obj) {
/* No-op */
}
inline void Object::write_barrier(STATE, Symbol* obj) {
/* No-op */
}
inline void Object::write_barrier(STATE, void* ptr) {
Object* obj = reinterpret_cast<Object*>(ptr);
if(!obj->reference_p() ||
state->vm()->young_object_p(this) ||
!state->vm()->young_object_p(obj)) return;
inline_write_barrier_passed(state, ptr);
}
inline void Object::write_barrier(VM* vm, void* ptr) {
Object* obj = reinterpret_cast<Object*>(ptr);
if(!obj->reference_p() ||
vm->young_object_p(this) ||
!vm->young_object_p(obj)) return;
inline_write_barrier_passed(vm, ptr);
}
// Used in filtering APIs
class ObjectMatcher {
public:
virtual ~ObjectMatcher() {}
virtual bool match_p(STATE, Object* obj) = 0;
};
class ObjectMatchAll : public ObjectMatcher {
public:
virtual ~ObjectMatchAll() {}
virtual bool match_p(STATE, Object* obj) { return true; }
};
}
#endif