📄 class.cpp
字号:
if (Import::scheme()->vtable_at_begining()) {
build_obj_list(); // to construct m_field_list
EntryList::iterator eli;
FORALL(eli, m_field_list) {
pe = *eli;
pe->data += sizeof(void *);
}
pe = Parser::state.add_variable(t_void_ptr,"__vftable");
pe->data = 0;
}
else Parser::state.add_variable(t_void_ptr,"__vftable");
}
// return; // *fix 1.2.0 we always try to force import ctors & dtors (issue: but if they are not complete?)
}
// this class requires construction and destruction!
// *fix 1.1.0 or maybe not...these guys will not generate default ctors etc if it isn't necessary
// *fix 1.2.6 Insist on not generating ctors and dtors if it really isn't necessary.
if (!has_constructors()) {
if (! auto_construct(true)) goto finish;
}
if (!imported()) {
if (!copy_constructor()) auto_assign_copy(false);
// Do note that we _never_ inherit operator= directly!
if (not_locally_defined(this,lookup("="))) auto_assign_copy(true);
}
if (!destructor()) auto_destruct(true);
m_simple_struct = ! has_constructors();
finish:
// finally, we can compile the method bodies
compile_methods();
Parser::state.set_construct_destruct(IsPlain);
}
bool Class::make_available()
{
// force a full instantiation of this template class
TemplateInstance *ti = get_template();
if (ti != NULL) {
if(! ti->instantiated()) {
try {
ti->get_template()->instantiate(ti);
} catch(string msg) {
error(msg); return false;
}
return true;
} else return true;
} else return true;
}
int Class::size()
{
//...add a word to class size if we have a VMT!!
int sz = Allocator::size();
return sz + ((m_VMT) ? sizeof(int) : 0) + ((m_vtable_size) ? sizeof(int) : 0);
}
int Class::distance_from(Class *pc)
{
if (pc == this) return 0; // on the nose...
Class *bc = base_class();
if (bc) return bc->distance_from(pc)+1;
else return NOT_RELATED;
}
bool Class::inherits_from(Class *pc)
{
return distance_from(pc) < NOT_RELATED ? true : false;
}
Class *Class::base_class()
{
// Watch out here for _nested classes_
return (m_parent->type()==IS_STRUCT && m_base_access != NotDerived)
? (Class *)m_parent : NULL;
}
// ------------------ Managing conversion to and from this class -----------------------
void Class::set_conversion_to(Function *fn)
{
m_to_list.push_back(fn->return_type());
m_to_fn.push_back(fn);
}
bool Class::get_from_type_list(TypeList& tl)
{ return grab_list(m_from_list,tl); }
bool Class::get_to_type_list(TypeList& tl)
{ return grab_list(m_to_list,tl); }
void
Class::copy_convert_to_list()
{
Class *pb = base_class();
m_to_list = pb->m_to_list;
m_to_fn = pb->m_to_fn;
}
// *fix 0.9.7 No longer require exact match for getting conversion operators
// *note* there will be an issue in the cases where a standard conversion requires code!
// *fix 1.1.0 the utility get_std_match() tries to match a type trivially, by promotion,
// and then by standard conversion. Point here is that it will favour the trivial match
// even where a standard match was possible. See end of this module.
Function *
Class::get_conversion_to(Type t)
{
return get_std_match(m_to_list,m_to_fn,t);
}
Function *
Class::get_conversion_from(Type t)
{
return get_std_match(m_from_list,m_from_fn,t);
}
//.---------------------.._safe_ ways to manipulate the class VMT....-----------------
void Class::set_slot(int id, Function *fn)
{
FBlock *pfb = fn->fun_block();
if (id < 1 && id > m_slot_id) error("class: slot out of range");
if (m_VMT) m_VMT[id] = (PClass)pfb; else
mVMT[id] = pfb;
// if our class is derived from an imported class, then we have
// to create a native stub for this method, and add it to the native vtable!
// Note: the vtable slot indices are _zero-based_!!
// We refuse to add any virtual methods beyond those already present in
// in the original export!
if (!fn->builtin() && vtable_size() > 0 && id <= vtable_size()) {
m_vtable_slots. push_back(id-1);
m_vtable_funs. push_back((Function *)Builtin::generate_native_stub(fn));
// cerr << "update slot " << id << ' ' << fn->name() << endl;
}
}
PFBlock Class::get_slot(int id)
{
if (id < 1 && id > m_slot_id) error("class: slot out of range");
if (m_VMT) return (PFBlock)m_VMT[id]; else
return (PFBlock)mVMT[id];
}
// pc->last_slot() > 0 is a more reliable way of telling whether a class has a VMT
// The issue here is that the VMT will sometimes only be generated when the class is finalized.
bool Class::has_VMT()
{
return last_slot() > 0 || get_VMT() != NULL;
}
// *add 1.2.0 Imported objects may avoid overallocation problems and attach
// the VMT to the object pointer using a map....
typedef std::map<void *,void *> PointerMap;
static PointerMap s_vmt_map;
void Class::attach_VMT(void *obj, PPClass vmt)
{
s_vmt_map[obj] = (vmt==NULL) ? get_VMT() : vmt;
}
PPClass Class::find_VMT(void *obj)
{
// might be in the cache...
/*
PCacheEntry pcache = s_vmt_cache
for(int i = 0; i < n_vmt_cache; i++,pcache++)
if (pcache->first==obj) return PPClass(pcache->second);
*/
// otherwise, look in the map
PointerMap::iterator pmi = s_vmt_map.find(obj);
if (pmi != s_vmt_map.end()) {
// s_vmt_cache[0] = *pmi;
return PPClass(pmi->second);
} else
return NULL;
}
bool Class::has_true_VMT()
{
return has_VMT() && !(m_import && ! m_import->cpp_friendly());
}
//--------------------- imported classes - managing vtables --------------------
bool Class::imported()
{ return m_imported; }
int Class::vtable_size()
{ return m_vtable_size; }
bool Class::derived_from_import() // this is dubious!
{ return vtable_size() > 0; }
void Class::set_imported()
{
if (! m_import) {
m_import = Import::create_scheme();
m_imported = true;
// Schemes like GCC2 put the hidden vtable pointer at the end of the first base class
// with virtual methods
if (! base_class() && ! m_import->vtable_at_begining())
m_import->set_first_virtual_class(Allocator::size()/sizeof(int));
}
}
void Class::update_vtable(char *obj)
{
// This implements VTABLE_PATCH, which is found in the ctors of imported classes w/ vtables
if (m_vtable_slots.size() == 0) return; // no modifications!
if (m_import->patched())
m_import->vtable_write(obj); // write our new vtable into the object
else { // unless new vtable must be constructed.....
m_import->vtable_size(vtable_size());
m_import->vtable_read(obj); // read the original vtable from object
m_import->clone_vtable(); // make a copy...
// and patch any slots that we have overrided....
IntList::iterator ili = m_vtable_slots.begin();
FunctionList::iterator fli = m_vtable_funs.begin();
for(; ili != m_vtable_slots.end(); ++ili, ++fli) {
int id = *ili;
// cerr << "patch slot " << id << ' ' << *fli << endl;
m_import->vtable_write_slot(id,(CALLFN)*fli);
}
m_import->now_patched();
m_import->vtable_write(obj);
}
}
char *
Class::check_object_pointer(char *p)
{
// Given a imported C++ object, ensure that it's got a proper UC VMT
// We are given the base class - have to hunt to find the exact derived class!
// The strategy is to look at the classes of all the methods we find in the vtable
// and pick the class furthest from the base.
// This does mean that we need to see ALL the headers, not just the interface header
// for the base class - otherwise, we can't tell what class an imported method belongs
// to.
// This implements CHKVMT
if (! p) return NULL; // *fix 1.2.4 doesn't apply to null pointers
if ( (has_true_VMT() && *VMT(p) == NULL) || find_VMT(p)==NULL) {
PFBlock provisional_VMT[MAX_VMT_ENTRIES]; // constraint enforced elsewhere
PClass furthest_class = this;
int tdist,max_tdist = 0, indefinites = 0, k = 1; // our slots begin at one...
m_import->vtable_read(p);
// for all entries in the base's VMT
for (int i = 0,n = last_slot(); i < n; i++) { // wuz -1?
CALLFN pf = m_import->vtable_read_slot(i);
PFBlock pfb = Builtin::imported_fblock_from_function((void *)pf);
if (pfb != NULL) { // this method has been already imported...
PClass pc = pfb->class_ptr;
if (pc != NULL) { // and we have seen its class defn
tdist = pc->distance_from(this);
if (tdist != NOT_RELATED && tdist > max_tdist) {
max_tdist = tdist;
furthest_class = pc;
}
} else ++indefinites;
} else { // haven't seen this one yet; import it! (Slot ids are one-based!)
pfb = Builtin::import_vmethod(pf,get_slot(i+1));
++indefinites;
}
provisional_VMT[k++] = pfb;
} // for all slots
PPClass vmt;
m_import->vtable_size(m_slot_id);
if (indefinites == 0) vmt = furthest_class->get_VMT();
else vmt = (PPClass)m_import->hunt_for_matching_VMT(provisional_VMT,furthest_class);
// and finally, actually patch in the VMT
// *add 1.2.0 'unfriendly' imported classes use the VMT association strategy
if (! has_true_VMT()) attach_VMT(p,vmt);
else *VMT(p) = vmt;
// if (! Parser::debug.suppress_link_errors) cmsg << "Type was " << furthest_class->name() << endl;
}
return p;
}
//----------------------managing class initialization---------------------------
void Class::add_class_init_list(PEntry pe, PExprList pel)
{
if (pe->m_typename && pe->type.is_class()) {
PClass pce = pe->type.as_class();
if (m_base_entry == NULL) build_obj_list();
if (pce==base_class()) pe = m_base_entry;
else error("not a base class");
}
s_entry_map[pe] = pel;
}
Class *as_class(PEntry pe)
{
return pe->type.as_class();
}
// constructing the list of _members which are objects_
bool Class::build_obj_list()
{
if (m_base_entry != NULL) return true; //*just remember always to reset m_base_entry*
// find all our non-static member fields, particularly
// looking for objects
m_field_list.clear(); // *for now*
m_obj_list.clear(); //*just in case*
EntryMap::iterator ei;
// *NOTE* there MUST be a more elegant way to find proper allocated _fields_
for(ei = m_map->begin(); ei != m_map->end(); ++ei) {
PEntry pe = ei->second;
if (pe->m_typename) continue;
Type t = pe->type;
// *fix 0.9.4 Include named enumeration member variables!
if (!t.is_function() && pe->rmode!=DIRECT) { /*t.is_enum()*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -