00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "metaclass.h"
00037 #include "ptree-core.h"
00038
00039 #if USE_DLOADER
00040 #include <stdio.h>
00041 #include <fstream.h>
00042 #include <string.h>
00043 #include <stdlib.h>
00044
00045
00046 extern void RunSoCompiler(const char* src_file);
00047 extern void* LoadSoLib(char* file_name);
00048 extern void* LookupSymbol(void* handle, char* symbol);
00049
00050 #if !USE_SO
00051 extern void BaseClassUsed(char *, int);
00052 #endif
00053
00054 #endif
00055
00056 extern bool verboseMode;
00057 extern bool makeSharedLibrary;
00058
00059
00060
00061
00062
00063
00064
00065
00066 #include "quote-class.h"
00067
00068
00069
00070
00071 static Class* CreateQuoteClass(Ptree* def, Ptree* marg)
00072 {
00073 Class* metaobject = new QuoteClass;
00074 metaobject->InitializeInstance(def, marg);
00075 return metaobject;
00076 }
00077
00078 static opcxx_ListOfMetaclass QuoteClassCreator("QuoteClass",
00079 CreateQuoteClass,
00080 QuoteClass::Initialize,
00081 nil);
00082
00083 opcxx_ListOfMetaclass* opcxx_init_QuoteClass()
00084 {
00085 return new opcxx_ListOfMetaclass("QuoteClass", CreateQuoteClass,
00086 QuoteClass::Initialize, nil);
00087 }
00088
00089 bool QuoteClass::Initialize()
00090 {
00091 return TRUE;
00092 }
00093
00094 char* QuoteClass::MetaclassName()
00095 {
00096 return "QuoteClass";
00097 }
00098
00099
00100
00101
00102 static Class* CreateMetaclass(Ptree* def, Ptree* marg)
00103 {
00104 Class* metaobject = new Metaclass;
00105 metaobject->InitializeInstance(def, marg);
00106 return metaobject;
00107 }
00108
00109 static opcxx_ListOfMetaclass metaclassCreator("Metaclass", CreateMetaclass,
00110 Metaclass::Initialize, nil);
00111
00112 opcxx_ListOfMetaclass* opcxx_init_Metaclass()
00113 {
00114 return new opcxx_ListOfMetaclass("Metaclass", CreateMetaclass,
00115 Metaclass::Initialize, nil);
00116 }
00117
00118 Metaclass::Metaclass()
00119 {
00120 new_function_name = nil;
00121 first_not_inlined_vf = -1;
00122 }
00123
00124 bool Metaclass::Initialize()
00125 {
00126 return TRUE;
00127 }
00128
00129 char* Metaclass::MetaclassName()
00130 {
00131 return "Metaclass";
00132 }
00133
00134 void Metaclass::TranslateClass(Environment* env)
00135 {
00136 Ptree* name = Name();
00137
00138 if(!IsBuiltinMetaclass(name)){
00139 CheckObsoleteness();
00140 InsertInitialize();
00141 #if defined(_MSC_VER) || defined(_PARSE_VCC)
00142 AddClassSpecifier(Ptree::Make("__declspec(dllexport)"));
00143 #endif
00144 AppendMember(Ptree::Make("public: char* MetaclassName() {\n"
00145 " return \"%p\"; }\n",
00146 Name()));
00147
00148 Ptree* tmpname = Ptree::GenSym();
00149 Ptree* tmpname2 = Ptree::GenSym();
00150 Ptree* finalizer = GetFinalizer();
00151 AppendAfterToplevel(env, Ptree::Make(
00152 "static Class* %p(Ptree* def, Ptree* marg){\n"
00153 " Class* c = new %p;\n"
00154 " c->InitializeInstance(def, marg);\n"
00155 " return c; }\n"
00156 "static opcxx_ListOfMetaclass %p(\"%p\", %p,\n"
00157 " %p::Initialize, %p);\n",
00158 tmpname, name, tmpname2, name, tmpname, name, finalizer));
00159
00160 if(makeSharedLibrary){
00161 ProduceInitFile(name);
00162 first_not_inlined_vf = FindFirstNotInlinedVirtualFunction();
00163 new_function_name = tmpname;
00164 if(first_not_inlined_vf < 0)
00165 AppendHousekeepingCode(env, Name(), tmpname, finalizer);
00166 }
00167 }
00168
00169 Class::TranslateClass(env);
00170 }
00171
00172 Ptree* Metaclass::GetFinalizer()
00173 {
00174 Member m;
00175 if(LookupMember("FinalizeClass", m) && m.Supplier() == this){
00176 if(!m.IsStatic())
00177 ErrorMessage("FinalizeClass() must be static in ", Name(),
00178 Definition());
00179
00180 return Ptree::Make("%p::FinalizeClass", Name());
00181 }
00182 else
00183 return Ptree::Make("0");
00184 }
00185
00186 void Metaclass::CheckObsoleteness()
00187 {
00188 Member m;
00189
00190 if(LookupMember("Finalize", m) && m.Supplier() == this)
00191 WarningMessage("Finalize() is obsolete. Use FinalizeInstance() in ",
00192 Name(),
00193 Definition());
00194 }
00195
00196 void Metaclass::ProduceInitFile(Ptree* class_name)
00197 {
00198 #if USE_DLOADER
00199 #if USE_SO
00200 const char* fname = Ptree::Make("%p-init.cc", class_name)->ToString();
00201 if(verboseMode)
00202 cerr << "Produce " << fname << " ..\n";
00203
00204 ofstream src_file(fname);
00205 if(!src_file){
00206 perror(fname);
00207 exit(1);
00208 }
00209
00210 src_file << "extern void LoadMetaclass(char*);\n";
00211 src_file << "char* opcxx_Init_" << class_name << "(){\n";
00212
00213 Ptree* base_name;
00214 for(int i = 0; (base_name = NthBaseClassName(i)) != nil; ++i)
00215 if(!base_name->Eq("Class"))
00216 src_file << " LoadMetaclass(\"" << base_name << "\");\n";
00217
00218 src_file << " return 0;\n}\n";
00219
00220 src_file.close();
00221
00222 RunSoCompiler(fname);
00223 #else
00224
00225 Ptree* base_name;
00226 for (int i = 0; (base_name = NthBaseClassName(i)) != nil; ++i)
00227 if (!base_name->Eq("Class") && !base_name->Eq("TemplateClass"))
00228 BaseClassUsed(base_name->GetPosition(), base_name->GetLength());
00229 #endif
00230 #endif
00231 }
00232
00233 bool Metaclass::IsBuiltinMetaclass(Ptree* name)
00234 {
00235 return bool(name->Eq("Class") || name->Eq("Metaclass")
00236 || name->Eq("TemplateClass")
00237 || name->Eq("QuoteClass"));
00238 }
00239
00240 void Metaclass::InsertInitialize()
00241 {
00242 Member m;
00243 if(!LookupMember("Initialize", m) || m.Supplier() != this){
00244 #if !defined(_MSC_VER) || (_MSC_VER >= 1100)
00245 AppendMember(Ptree::Make(
00246 "public: static bool Initialize() { return 1; }\n"));
00247 #else
00248 AppendMember(Ptree::Make(
00249 "public: static int Initialize() { return 1; }\n"));
00250 #endif
00251 }
00252 else if(!m.IsStatic())
00253 ErrorMessage("Initialize() must be static in ", Name(),
00254 Definition());
00255 }
00256
00257 int Metaclass::FindFirstNotInlinedVirtualFunction()
00258 {
00259 Member m;
00260 for(int i = 0; NthMember(i, m); ++i)
00261 if(m.IsFunction() && m.IsVirtual() && !m.IsInline()
00262 && m.Supplier() == this)
00263 return i;
00264
00265 WarningMessage("a metaclass should include at least one"
00266 " not-inlined virtual function: ", Name(), Name());
00267 return -1;
00268 }
00269
00270 void Metaclass::TranslateMemberFunction(Environment* env, Member& m)
00271 {
00272 if(m.Nth() != first_not_inlined_vf)
00273 return;
00274
00275 if(m.IsInline()){
00276 ErrorMessage("This member function should not be inlined: ",
00277 m.Name(), m.ArgumentList());
00278 return;
00279 }
00280
00281 AppendHousekeepingCode(env, Name(), new_function_name,
00282 GetFinalizer());
00283 }
00284
00285 void Metaclass::AppendHousekeepingCode(Environment* env, Ptree* class_name,
00286 Ptree* creator_name,
00287 Ptree* finalizer)
00288 {
00289 #if !defined(_MSC_VER)
00290 AppendAfterToplevel(env, Ptree::Make(
00291 "opcxx_ListOfMetaclass* opcxx_init_%p(){\n"
00292 " return new opcxx_ListOfMetaclass(\"%p\", %p,\n"
00293 " %p::Initialize, %p); }\n",
00294 class_name, class_name, creator_name, class_name,
00295 finalizer));
00296 #endif
00297 }
00298
00299 void LoadMetaclass(char* metaclass_name)
00300 {
00301 #if USE_DLOADER
00302 if(metaclass_name != nil && *metaclass_name != '\0')
00303 if(!opcxx_ListOfMetaclass::AlreadyRecorded(metaclass_name))
00304 Metaclass::Load(metaclass_name, strlen(metaclass_name));
00305 #endif
00306 }
00307
00308 void Metaclass::Load(Ptree* metaclass_name)
00309 {
00310 #if USE_DLOADER
00311 if(opcxx_ListOfMetaclass::AlreadyRecorded(metaclass_name))
00312 return;
00313
00314 Load(metaclass_name->GetPosition(), metaclass_name->GetLength());
00315 #endif
00316 }
00317
00318 void Metaclass::Load(char* metaclass_name, int len)
00319 {
00320 #if USE_DLOADER
00321 #if USE_SO
00322 #if DLSYM_NEED_UNDERSCORE
00323 static char header[] = "_opcxx_Init_";
00324 #else
00325 static char header[] = "opcxx_Init_";
00326 #endif
00327 #if defined(IRIX_CC)
00328 static char tail[] = "__Gv";
00329 #else
00330 static char tail[] = "__Fv";
00331 #endif
00332
00333 char* func_name = new char[len + sizeof(header) + sizeof(tail)];
00334 strcpy(func_name, header);
00335 memmove(func_name + sizeof(header) - 1, metaclass_name, len);
00336 strcpy(func_name + sizeof(header) + len - 1, tail);
00337
00338
00339
00340 char* file_name = new char[len + 9];
00341 memmove(file_name, metaclass_name, len);
00342
00343 strcpy(file_name + len, "-init.so");
00344 void* handle_init = LoadSoLib(file_name);
00345
00346
00347
00348 void (*loader)();
00349 loader = (void (*)())LookupSymbol(handle_init, func_name);
00350 (*loader)();
00351
00352 strcpy(file_name + len, ".so");
00353 void* handle = LoadSoLib(file_name);
00354
00355 if(verboseMode)
00356 cerr << "Initialize.. ";
00357
00358
00359
00360 func_name[sizeof(header) - 6] = 'i';
00361 void (*func)();
00362 func = (void (*)())LookupSymbol(handle, func_name);
00363 (*func)();
00364
00365 delete [] file_name;
00366 delete [] func_name;
00367
00368 if(verboseMode)
00369 cerr << "Done.\n";
00370
00371 #else
00372
00373
00374 static char ext[] = ".dll";
00375 char* file_name = new char[len + sizeof(ext)];
00376 memmove(file_name, metaclass_name, len);
00377 strcpy(file_name + len, ext);
00378 void* handle = LoadSoLib(file_name);
00379
00380 delete [] file_name;
00381
00382 if(verboseMode)
00383 cerr << "Done.\n";
00384 #endif
00385 #endif
00386 }
00387
00388 void* Metaclass::LoadSoLib(char* file_name)
00389 {
00390 void* handle = nil;
00391 #if USE_DLOADER
00392 if(verboseMode)
00393 cerr << "Load " << file_name << ".. ";
00394
00395 handle = ::LoadSoLib(file_name);
00396 #endif
00397
00398 return handle;
00399 }
00400
00401 void* Metaclass::LookupSymbol(void* handle, char* symbol)
00402 {
00403 void* func = 0;
00404 #if USE_DLOADER
00405 func = ::LookupSymbol(handle, symbol);
00406 #endif
00407 return func;
00408 }