Modules | Files | Inheritance Tree | Inheritance Graph | Name Index | Config
File: Synopsis/Parser/C++/occ/metaclass.cc
    1| /*
    2|   Copyright (C) 1997-2000 Shigeru Chiba, University of Tsukuba.
    3| 
    4|   Permission to use, copy, distribute and modify this software and   
    5|   its documentation for any purpose is hereby granted without fee,        
    6|   provided that the above copyright notice appear in all copies and that 
    7|   both that copyright notice and this permission notice appear in 
    8|   supporting documentation.
    9| 
   10|   Shigeru Chiba makes no representations about the suitability of this 
   11|   software for any purpose.  It is provided "as is" without express or
   12|   implied warranty.
   13| */
   14| /*
   15|   Copyright (c) 1995, 1996 Xerox Corporation.
   16|   All Rights Reserved.
   17| 
   18|   Use and copying of this software and preparation of derivative works
   19|   based upon this software are permitted. Any copy of this software or
   20|   of any derivative work must include the above copyright notice of
   21|   Xerox Corporation, this paragraph and the one after it.  Any
   22|   distribution of this software or derivative works must comply with all
   23|   applicable United States export control laws.
   24| 
   25|   This software is made available AS IS, and XEROX CORPORATION DISCLAIMS
   26|   ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
   27|   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28|   PURPOSE, AND NOTWITHSTANDING ANY OTHER PROVISION CONTAINED HEREIN, ANY
   29|   LIABILITY FOR DAMAGES RESULTING FROM THE SOFTWARE OR ITS USE IS
   30|   EXPRESSLY DISCLAIMED, WHETHER ARISING IN CONTRACT, TORT (INCLUDING
   31|   NEGLIGENCE) OR STRICT LIABILITY, EVEN IF XEROX CORPORATION IS ADVISED
   32|   OF THE POSSIBILITY OF SUCH DAMAGES.
   33| */
   34| 
   35| #include "metaclass.h"
   36| #include "ptree-core.h"
   37| 
   38| #if USE_DLOADER
   39| #include <iostream>
   40| #include <cstdio>
   41| #include <fstream>
   42| #include <cstring>
   43| #include <cstdlib>      /* for exi
   44| 
   45| // in driver2.cc
   46| extern void RunSoCompiler(const char* src_file);
   47| extern voidLoadSoLib(char* file_name);
   48| extern voidLookupSymbol(void* handle, char* symbol);
   49| 
   50| #if !USE_SO
   51| extern void BaseClassUsed(char *, int);        // in dr
   52| #endif /* USE_SO */
   53| 
   54| #endif /* USE_DLOADER */
   55| 
   56| extern bool verboseMode;        // defined in driver.cc
   57| extern bool makeSharedLibrary;
   58| 
   59| 
   60| // class QuoteClass
   61| //
   62| // Part of the implementation of QuoteClass is included here to let
   63| // quote-class.cc linked to others if the compiler is produced by
   64| // "g++ -o occ opencxx.a".
   65| 
   66| #include "quote-class.h"
   67| 
   68| // The followings should be automatically generated but we write it
   69| // down here for bootstrapping.  Also see Metaclass::IsBuiltinMetaclass()
   70| 
   71| static opcxx_ListOfMetaclassQuoteClassCreator;
   72| static opcxx_ListOfMetaclassmetaclassCreator;
   73| 
   74| static ClassCreateQuoteClass(Ptree* def, Ptree* marg)
   75| {
   76|     Classmetaobject = new QuoteClass;
   77|     metaobject->InitializeInstance(defmarg);
   78|     return metaobject;
   79| }
   80| 
   81| opcxx_ListOfMetaclassopcxx_init_QuoteClass()
   82| {
   83|     return new opcxx_ListOfMetaclass("QuoteClass", CreateQuoteClass,
   84|                                   QuoteClass::Initialize, nil);
   85| }
   86| 
   87| static ClassCreateMetaclass(Ptree* def, Ptree* marg)
   88| {
   89|     Classmetaobject = new Metaclass;
   90|     metaobject->InitializeInstance(defmarg);
   91|     return metaobject;
   92| }
   93| 
   94| opcxx_ListOfMetaclassopcxx_init_Metaclass()
   95| {
   96|     return new opcxx_ListOfMetaclass("Metaclass", CreateMetaclass,
   97|                                  Metaclass::Initialize, nil);
   98| }
   99| 
  100| 
  101| bool QuoteClass::Initialize()
  102| {
  103|     return TRUE;
  104| }
  105| 
  106| charQuoteClass::MetaclassName()
  107| {
  108|     return "QuoteClass";
  109| }
  110| 
  111| 
  112| // class Metaclass
  113| 
  114| void Metaclass::do_init_static()
  115| {
  116|     QuoteClassCreator = new opcxx_ListOfMetaclass(
  117|             "QuoteClass", CreateQuoteClass, QuoteClass::Initialize, nil);
  118|     metaclassCreator = new opcxx_ListOfMetaclass(
  119|             "Metaclass", CreateMetaclass, Metaclass::Initialize, nil);
  120| }
  121| 
  122| Metaclass::Metaclass()
  123| {
  124|     new_function_name = nil;
  125|     first_not_inlined_vf = -1;
  126| }
  127| 
  128| bool Metaclass::Initialize()
  129| {
  130|     return TRUE;
  131| }
  132| 
  133| charMetaclass::MetaclassName()
  134| {
  135|     return "Metaclass";
  136| }
  137| 
  138| void Metaclass::TranslateClass(Environment* env)
  139| {
  140|     Ptreename = Name();
  141| 
  142|     if(!IsBuiltinMetaclass(name)){
  143|         CheckObsoleteness();
  144|         InsertInitialize();
  145| #if defined(_MSC_VER) || defined(_PARSE_VCC)
  146|         AddClassSpecifier(Ptree::Make("__declspec(dllexport)"));
  147| #endif
  148|         AppendMember(Ptree::Make("public: char* MetaclassName() {\n"
  149|                              "    return \"%p\"; }\n",
  150|                Name()));
  151| 
  152|         Ptreetmpname = Ptree::GenSym();
  153|         Ptreetmpname2 = Ptree::GenSym();
  154|         Ptreefinalizer = GetFinalizer();
  155|         AppendAfterToplevel(env, Ptree::Make(
  156|                "static Class* %p(Ptree* def, Ptree* marg){\n"
  157|                "    Class* c = new %p;\n"
  158|                "    c->InitializeInstance(def, marg);\n"
  159|                "    return c; }\n"
  160|                "static opcxx_ListOfMetaclass %p(\"%p\", %p,\n"
  161|                "    %p::Initialize, %p);\n",
  162|                tmpnamenametmpname2nametmpnamenamefinalizer));
  163| 
  164|         if(makeSharedLibrary){
  165|             ProduceInitFile(name);
  166|             first_not_inlined_vf = FindFirstNotInlinedVirtualFunction();
  167|             new_function_name = tmpname;
  168|             if(first_not_inlined_vf < 0)
  169|                AppendHousekeepingCode(envName(), tmpnamefinalizer);
  170|         }
  171|     }
  172| 
  173|     Class::TranslateClass(env);
  174| }
  175| 
  176| PtreeMetaclass::GetFinalizer()
  177| {
  178|     Member m;
  179|     if(LookupMember("FinalizeClass"m) && m.Supplier() == this){
  180|         if(!m.IsStatic())
  181|             ErrorMessage("FinalizeClass() must be static in "Name(),
  182|                       Definition());
  183| 
  184|         return Ptree::Make("%p::FinalizeClass"Name());
  185|     }
  186|     else
  187|         return Ptree::Make("0");
  188| }
  189| 
  190| void Metaclass::CheckObsoleteness()
  191| {
  192|     Member m;
  193| 
  194|     if(LookupMember("Finalize"m) && m.Supplier() == this)
  195|         WarningMessage("Finalize() is obsolete.  Use FinalizeInstance() in ",
  196|                Name(),
  197|                      Definition());
  198| }
  199| 
  200| void Metaclass::ProduceInitFile(Ptree* class_name)
  201| {
  202| #if USE_DLOADER
  203| #if USE_SO
  204|     const charfname = Ptree::Make("%p-init.cc"class_name)->ToString();
  205|     if(verboseMode)
  206|         std::cerr << "Produce " << fname << " ..\n";
  207| 
  208|     std::ofstream src_file(fname);
  209|     if(!src_file){
  210|         perror(fname);
  211|         exit(1);
  212|     }
  213| 
  214|     src_file << "extern void LoadMetaclass(char*);\n";
  215|     src_file << "char* opcxx_Init_" << class_name << "(){\n";
  216| 
  217|     Ptreebase_name;
  218|     for(int i = 0; (base_name = NthBaseClassName(i)) != nil; ++i)
  219|         if(!base_name->Eq("Class"))
  220|             src_file << "  LoadMetaclass(\"" << base_name << "\");\n";
  221| 
  222|     src_file << "    return 0;\n}\n";
  223| 
  224|     src_file.close();
  225| 
  226|     RunSoCompiler(fname);
  227| #else
  228|     // Push base class names forward to RunCompiler
  229|     Ptree* base_name;
  230|     for (int i = 0; (base_name = NthBaseClassName(i)) != nil; ++i)
  231|         if (!base_name->Eq("Class") && !base_name->Eq("TemplateClass"))
  232|             BaseClassUsed(base_name->GetPosition(), base_name->GetLength());
  233| #endif /* USE_SO */
  234| #endif /* USE_DLOADER */
  235| }
  236| 
  237| bool Metaclass::IsBuiltinMetaclass(Ptree* name)
  238| {
  239|     return bool(name->Eq("Class") || name->Eq("Metaclass")
  240|                || name->Eq("TemplateClass")
  241|                || name->Eq("QuoteClass"));
  242| }
  243| 
  244| void Metaclass::InsertInitialize()
  245| {
  246|     Member m;
  247|     if(!LookupMember("Initialize"m) || m.Supplier() != this){
  248| #if !defined(_MSC_VER) || (_MSC_VER >= 1100)
  249|         AppendMember(Ptree::Make(
  250|                "public: static bool Initialize() { return 1; }\n"));
  251| #else
  252|         AppendMember(Ptree::Make(
  253|                "public: static int Initialize() { return 1; }\n"));
  254| #endif
  255|     }
  256|     else if(!m.IsStatic())
  257|         ErrorMessage("Initialize() must be static in "Name(),
  258|                    Definition());
  259| }
  260| 
  261| int Metaclass::FindFirstNotInlinedVirtualFunction()
  262| {
  263|     Member m;
  264|     for(int i = 0NthMember(im); ++i)
  265|         if(m.IsFunction() && m.IsVirtual() && !m.IsInline()
  266|            && m.Supplier() == this)
  267|             return i;
  268| 
  269|     WarningMessage("a metaclass should include at least one"
  270|                   " not-inlined virtual function: ", Name(), Name());
  271|     return -1;
  272| }
  273| 
  274| void Metaclass::TranslateMemberFunction(Environment* env, Member& m)
  275| {
  276|     if(m.Nth() != first_not_inlined_vf)
  277|         return;
  278| 
  279|     if(m.IsInline()){
  280|         ErrorMessage("This member function should not be inlined: ",
  281|                     m.Name(), m.ArgumentList());
  282|         return;
  283|     }
  284| 
  285|     AppendHousekeepingCode(envName(), new_function_name,
  286|                       GetFinalizer());
  287| }
  288| 
  289| void Metaclass::AppendHousekeepingCode(Environment* env, Ptree* class_name,
  290|                              Ptree* creator_name,
  291|                              Ptree* finalizer)
  292| {
  293| #if !defined(_MSC_VER)
  294|     AppendAfterToplevel(env, Ptree::Make(
  295|                "opcxx_ListOfMetaclass* opcxx_init_%p(){\n"
  296|                "    return new opcxx_ListOfMetaclass(\"%p\", %p,\n"
  297|                "                   %p::Initialize, %p); }\n",
  298|                class_nameclass_namecreator_nameclass_name,
  299|                finalizer));
  300| #endif
  301| }
  302| 
  303| void LoadMetaclass(char* metaclass_name)
  304| {
  305| #if USE_DLOADER
  306|     if(metaclass_name != nil && *metaclass_name != '\0')
  307|         if(!opcxx_ListOfMetaclass::AlreadyRecorded(metaclass_name))
  308|             Metaclass::Load(metaclass_namestrlen(metaclass_name));
  309| #endif
  310| }
  311| 
  312| void Metaclass::Load(Ptree* metaclass_name)
  313| {
  314| #if USE_DLOADER
  315|     if(opcxx_ListOfMetaclass::AlreadyRecorded(metaclass_name))
  316|         return;
  317| 
  318|     Load(metaclass_name->GetPosition(), metaclass_name->GetLength());
  319| #endif
  320| }
  321| 
  322| void Metaclass::Load(char* metaclass_name, int len)
  323| {
  324| #if USE_DLOADER
  325| #if USE_SO
  326| #if DLSYM_NEED_UNDERSCORE
  327|     static char header[] = "_opcxx_Init_";
  328| #else
  329|     static char header[] = "opcxx_Init_";
  330| #endif
  331| #if defined(IRIX_CC)
  332|     static char tail[] = "__Gv";
  333| #else
  334|     static char tail[] = "__Fv";
  335| #endif
  336| 
  337|     charfunc_name = new char[len + sizeof(header) + sizeof(tail)];
  338|     strcpy(func_nameheader);
  339|     memmove(func_name + sizeof(header) - 1metaclass_namelen);
  340|     strcpy(func_name + sizeof(header) + len - 1tail);
  341| 
  342|     // here, func_name is "_opcxx_Init_<metaclass>__Fv" or ".._Gv".
  343| 
  344|     charfile_name = new char[len + 9];
  345|     memmove(file_namemetaclass_namelen);
  346| 
  347|     strcpy(file_name + len"-init.so");
  348|     voidhandle_init = LoadSoLib(file_name);   // load <metaclass>-init
  349| 
  350|     // call opcxx_Init_<metaclass>() in <metaclass>-init.so
  351| 
  352|     void (*loader)();
  353|     loader = (void (*)())LookupSymbol(handle_initfunc_name);
  354|     (*loader)();
  355| 
  356|     strcpy(file_name + len".so");
  357|     voidhandle = LoadSoLib(file_name);        // load <metac
  358| 
  359|     if(verboseMode)
  360|         std::cerr << "Initialize.. ";
  361| 
  362|     // call opcxx_init_<metaclass>() in <metaclass>.so
  363| 
  364|     func_name[sizeof(header) - 6] = 'i';
  365|     void (*func)();
  366|     func = (void (*)())LookupSymbol(handlefunc_name);
  367|     (*func)();
  368| 
  369|     delete [] file_name;
  370|     delete [] func_name;
  371| 
  372|     if(verboseMode)
  373|         std::cerr << "Done.\n";
  374| 
  375| #else /* USE_SO */
  376| 
  377|     // Win32 uses auto-initialization of DLL's static variables
  378|     static char ext[] = ".dll";
  379|     char* file_name = new char[len + sizeof(ext)];
  380|     memmove(file_name, metaclass_name, len);
  381|     strcpy(file_name + len, ext);
  382|     void* handle = LoadSoLib(file_name);        // load <metacl
  383| 
  384|     delete [] file_name;
  385| 
  386|     if(verboseMode)
  387|         std::cerr << "Done.\n";
  388| #endif /* USE_SO */
  389| #endif /* USE_DLOADER */
  390| }
  391| 
  392| voidMetaclass::LoadSoLib(char* file_name)
  393| {
  394|     voidhandle = nil;
  395| #if USE_DLOADER
  396|     if(verboseMode)
  397|         std::cerr << "Load " << file_name << ".. ";
  398| 
  399|     handle = ::LoadSoLib(file_name);
  400| #endif /* USE_DLOADER */
  401| 
  402|     return handle;
  403| }
  404| 
  405| voidMetaclass::LookupSymbol(void* handle, char* symbol)
  406| {
  407|     voidfunc = 0;
  408| #if USE_DLOADER
  409|     func = ::LookupSymbol(handlesymbol);
  410| #endif
  411|     return func;
  412| }