⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 class.cpp

📁 UC Library Extensions UnderC comes with a pocket implementation of the standard C++ libraries, wh
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        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 + -