CE Environment.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Edit{
  5. /******************************************************************************/
  6. // TODO: stack variables reuse memory of destroyed vars
  7. /******************************************************************************/
  8. static void SetMemUInt(Ptr data, UInt value, UInt size)
  9. {
  10. VecB4 v; v.u=value;
  11. UInt *u=(UInt*)data; REP(size/SIZE(UInt))*u++ =v.u;
  12. Byte *b=(Byte*) u; REP(size%SIZE(UInt)) b[i]=v.c[i&3];
  13. }
  14. /******************************************************************************/
  15. void CodeEnvironment::Thread::del () {stack.del(); levels.del(); zero();}
  16. void CodeEnvironment::Thread::create(CodeEnvironment &env)
  17. {
  18. del();
  19. stack.setNum(CE_STACK_SIZE);
  20. heap =env.heap.data();
  21. debug=env.debug;
  22. if(debug)SetMemUInt(stack.data(), 0xBAADF00D, stack.elms()); // in debug mode fill stack with 0xBAADF00D
  23. }
  24. #if WINDOWS
  25. Bool CodeEnvironment::Thread::test()
  26. {
  27. __try
  28. {
  29. for(; func_code_pos<func_code_end; )
  30. {
  31. Call &call=*(Call*)func_code_pos;
  32. //func_code_pos+=Call::Size(call.params); // adjust the code position BEFORE the call, to allow modifying position INSIDE the call (this is currently done inside func calls because it is faster that way)
  33. call.func(call, T);
  34. }
  35. return true;
  36. }
  37. __except(EXCEPTION_EXECUTE_HANDLER) {return false;} // unhandled exception encountered
  38. }
  39. #endif
  40. Bool CodeEnvironment::Thread::start(FuncBody &func)
  41. {
  42. if(func.stack_size>stack.elms())Exit("Function requires too big stack size");
  43. T.func =&func;
  44. T.func_stack = stack.data();
  45. T.func_code_pos= func.code.data();
  46. T.func_code_end= func.code.data()+func.code.elms();
  47. for(;;) // levels
  48. {
  49. #if WINDOWS
  50. if(debug)
  51. {
  52. if(!test())return false;
  53. }else
  54. #endif
  55. for(; func_code_pos<func_code_end; ) // function
  56. {
  57. Call &call=*(Call*)func_code_pos;
  58. //func_code_pos+=Call::Size(call.params); // adjust the code position BEFORE the call, to allow modifying position INSIDE the call (this is currently done inside func calls because it is faster that way)
  59. call.func(call, T);
  60. }
  61. if(!levels.elms())break; // no more levels left
  62. // go back to last function
  63. Level &level=levels.last(); // get last function
  64. T.func =level.func ; // set new function
  65. func_code_pos =level.func_code_pos ; // restore last code position
  66. func_code_end =T.func->code.data()+T.func->code.elms(); // adjust code position end
  67. func_stack -=T.func->stack_size ; // decrease stack by NEW function
  68. func_param_stack=level.func_param_stack; // restore last param stack
  69. func_this =level.func_this ; // restore last this
  70. func_result =level.func_result ; // restore last result
  71. levels.removeLast();
  72. }
  73. return true;
  74. }
  75. void CodeEnvironment::Thread::call(FuncBody &func, Int param_stack_offset, Ptr func_this, Ptr result)
  76. {
  77. // save current level
  78. Level &level=levels.New();
  79. level.func =T.func;
  80. level.func_code_pos =T.func_code_pos;
  81. level.func_param_stack=T.func_param_stack;
  82. level.func_this =T.func_this;
  83. level.func_result =T.func_result;
  84. // set new func
  85. T.func_param_stack=T.func_stack+param_stack_offset; // set new param stack from current stack offsetted by 'param_stack_offset'
  86. T.func_stack +=T.func->stack_size; // adjust stack position by PREVIOUS function
  87. Int stack_required =func.stack_size,
  88. stack_available=stack.data() - T.func_stack + stack.elms();
  89. if( stack_required > stack_available)
  90. {
  91. Str msg=S+"Not enough stack memory available to call function.\nFunction call depth: "+levels.elms()+"\nTotal stack size: "+stack.elms()+"\nStack memory required: "+stack_required+"\nStack memory available: "+stack_available;
  92. if(debug)
  93. {
  94. Gui.msgBox("Error", msg);
  95. throw(0);
  96. }else
  97. {
  98. msg+="\nCall stack:";
  99. Int num=0;
  100. msg+=S+'\n'+ func. name;
  101. REPA(levels){msg+=S+'\n'+levels[i].func->name; if(++num>=16){msg+="\n.."; break;}}
  102. Exit(msg);
  103. }
  104. }
  105. T.func =&func;
  106. T.func_code_pos= func.code.data();
  107. T.func_code_end= func.code.data()+func.code.elms();
  108. T.func_this = (Byte*)func_this;
  109. T.func_result = (Byte*)result;
  110. }
  111. /******************************************************************************/
  112. static Int CompareName(Symbol*C &a, Symbol*C &b) {return ComparePath(a->fileName(), b->fileName());}
  113. Bool CodeEnvironment::VerifySymbols(Memc<Message> &msgs, Memc<Symbol*> &sorted_classes)
  114. {
  115. // helpers, set in root namespace to avoid unnecessary memory allocations
  116. Str temp; Memc<Symbol::Modif> templates;
  117. // get symbols from current build files
  118. Memc<Symbol*> active_symbols;
  119. FREPA(Symbols)
  120. {
  121. Symbol &symbol=Symbols.lockedData(i);
  122. if(symbol.source && symbol.source->active && symbol.valid)active_symbols.add(&symbol);
  123. }
  124. // various tests
  125. FREPA(active_symbols)
  126. {
  127. Symbol &symbol=*active_symbols[i];
  128. // static global variables functions
  129. if(symbol.isGlobalAndStatic())msgs.New().error("Invalid \"static\" keyword for global variable/function.", &symbol);
  130. // transparent classes that don't have non-transparent class
  131. if(symbol.type==Symbol::CLASS && (symbol.modifiers&Symbol::MODIF_TRANSPARENT))
  132. {
  133. Symbol *p=symbol.Parent();
  134. if(!p || p->type!=Symbol::CLASS)msgs.New().error("Transparent class must belong to non-transparent class.", &symbol);
  135. }
  136. // const_mem_addr used for non-const_mem_addr
  137. if(symbol.source && !symbol.source->header) // only in custom sources
  138. if(!symbol.value.constMemAddrOK())
  139. msgs.New().warning("Specified class requires to be stored in a constant memory address (const_mem_addr), however the target does not support it. If you're sure that this is not an error, then please specify the class with 'const_mem_addr' modifier, as <const_mem_addr TYPE>", &symbol);
  140. }
  141. // clear dependencies and setup processed
  142. REPA(Symbols)
  143. {
  144. Symbol &symbol =Symbols.lockedData(i); symbol.dependencies.del(); // clear dependencies
  145. Bool processed=false;
  146. if( symbol.type==Symbol::KEYWORD )processed=true; // keywords are already processed
  147. if(!symbol.source || !symbol.source->active)processed=true; // symbols which aren't in current build files (for example EE headers) set as processed
  148. FlagSet(symbol.helper, Symbol::HELPER_PROCESSED|Symbol::HELPER_PROCESSED_FULL, processed);
  149. }
  150. // setup dependencies
  151. REPA(Symbols)
  152. {
  153. Symbol &symbol=Symbols.lockedData(i);
  154. Bool active=(symbol.source && symbol.source->active && symbol.valid);
  155. if( active // process only active symbols (user defined, not from the engine)
  156. || symbol.type==Symbol::VAR && symbol.value && symbol.value->type==Symbol::TYPENAME // or engine defined if they're a template, this is needed because:
  157. )
  158. /*
  159. <TYPE> class FixedArray // this Engine Defined
  160. {
  161. TYPE data[..];
  162. }
  163. // following is user defined:
  164. class Base // base class
  165. {
  166. }
  167. class Use // usage of base using engine's 'FixedArray'
  168. {
  169. FixedArray<Base> array;
  170. }
  171. In the above example, we're making sure that 'data' is set as a dependency to 'FixedArray',
  172. thanks to which allows to detect 'Base' as dependency to 'Use'.
  173. */
  174. {
  175. REPA(symbol.base)symbol.addDependency(symbol.base[i]); // add base classes
  176. if(symbol.type==Symbol::VAR && symbol.Parent() && symbol.Parent()->type==Symbol::CLASS)symbol.Parent()->addDependency(symbol.value); // add member types to their classes
  177. // add all nested classes because they couldn't be forward declared earlier, for example "class A { class AA {} } class B { A.AA *x; }" make sure that "B" depends on root of "AA" (which is "A") this will guarantee the "A" header declared before "B" header (so "AA" is known)
  178. if(symbol.type==Symbol::VAR || symbol.type==Symbol::FUNC || symbol.type==Symbol::TYPEDEF)
  179. {
  180. if(symbol.Parent() && symbol.Parent()->type==Symbol::CLASS)
  181. {
  182. symbol.Parent()->addDependencyIfNested(symbol.value()); // include value of the varaible
  183. REPA(symbol.params)if(Symbol *param=symbol.params[i]()) // iterate all params of a function
  184. {
  185. symbol.Parent()->addDependencyIfNested(param->value()); // include value of all parameters of the function to handle "void func(A.AA *x)"
  186. if(param->modifiers&Symbol::MODIF_DEF_VALUE) // include default value for function parameters to handle "class A{}; A global; void func(A p=global);"
  187. for(Int i=param->def_val_range.x; i<=param->def_val_range.y; )
  188. {
  189. Int start=i;
  190. if(Symbol *s=GetFullSymbol(param->source->tokens, i, temp, &symbol, templates))
  191. {
  192. Symbol::Modif modif; modif=s; symbol.Parent()->addDependency(modif);
  193. }
  194. MAX(i, start+1);
  195. }
  196. }
  197. }
  198. }
  199. }
  200. }
  201. // now that we know what typenames are used by what classes "<TYPE> class A { class Sub : TYPE { class Sub2 {} }}" (Sub has TYPE in its 'dependencies', Sub2 doesn't, however it should check for all parents)
  202. REPA(active_symbols)
  203. {
  204. Symbol &symbol=*active_symbols[i];
  205. if(symbol.Parent() && symbol.Parent()->type==Symbol::CLASS) // element that belongs to class
  206. {
  207. Symbol::Modif &value=symbol.value; // get its value "Memc<int> x" -> "Memc<int>"
  208. REPA(value.templates)
  209. {
  210. Symbol::Modif &templat=value.templates[i];
  211. if(Symbol *src_template=templat.src_template()) // iterate all its templates "Memc.TYPE"
  212. {
  213. if(templat && templat->type==Symbol::ENUM) // enums can't be forward declared (they can in VS but not in GCC)
  214. {
  215. symbol.Parent()->addDependency(templat); // add dependency to "enum"
  216. }else
  217. for(Symbol *cur=value(); cur; cur=cur->parent()) // check if that template is used by class or any of its parents
  218. if(cur->type==Symbol::CLASS)
  219. if(cur->dependencies.has(src_template))
  220. {
  221. symbol.Parent()->addDependency(templat); // add dependency to "int"
  222. break;
  223. }
  224. }
  225. }
  226. }
  227. }
  228. // add dependencies from nested classes to their root
  229. REPA(active_symbols)
  230. {
  231. Symbol &symbol=*active_symbols[i];
  232. if(symbol.type==Symbol::CLASS)
  233. if(Symbol *root_class=symbol.rootClass())
  234. if(root_class!=&symbol)
  235. REPA(symbol.dependencies)
  236. {
  237. Symbol *dep=symbol.dependencies[i];
  238. if(dep!=root_class)root_class->dependencies.include(dep);
  239. }
  240. }
  241. // create list of global classes
  242. Memc<Symbol*> classes;
  243. REPA(active_symbols)
  244. {
  245. Symbol &symbol=*active_symbols[i];
  246. if(symbol.type==Symbol::CLASS && symbol.isGlobal())classes.add(&symbol); // global classes only
  247. }
  248. classes.sort(CompareName); // sort classes by name, to try generating them always in the same order
  249. for(;;)
  250. {
  251. Bool removed=false;
  252. // list classes ready to process
  253. REPA(classes)
  254. {
  255. Symbol &symbol=*classes[i];
  256. REPAD(d, symbol.dependencies)if(!(symbol.dependencies[d]->helper&Symbol::HELPER_PROCESSED) && symbol.dependencies[d]->type!=Symbol::TYPENAME)goto not_yet; // if at least one dependency not yet available then skip (here ignore typename dependencies)
  257. symbol.helper|=Symbol::HELPER_PROCESSED; // we list classes sequentially one-by-one (in 'to_process' container and later when writing it) so we can set HELPER_PROCESSED here already
  258. sorted_classes.add(&symbol); classes.remove(i); removed=true;
  259. not_yet:;
  260. }
  261. if(!removed)break; // if no class was processed in this step, then break the loop
  262. }
  263. FREPA(classes) // report all un-processed classes as errors
  264. {
  265. Symbol &symbol=*classes[i];
  266. Message &msg = msgs.New().error(S+"class \""+symbol.fullCppName()+"\" is dependent on following classes:", &symbol);
  267. FREPA(symbol.dependencies)
  268. {
  269. Symbol &dependency=*symbol.dependencies[i];
  270. if( !(dependency.helper&Symbol::HELPER_PROCESSED) && dependency.type!=Symbol::TYPENAME)msg.children.New().set(dependency.fullCppName(), &dependency); // here ignore typename dependencies
  271. }
  272. }
  273. return !msgs.elms();
  274. }
  275. static Int CompareTokenIndex(Symbol*C &a, Symbol*C &b) {return Compare(a->token_index, b->token_index);}
  276. void CodeEnvironment::SetupChildren()
  277. {
  278. // delete children
  279. REPA(Symbols){Symbol &symbol=Symbols.lockedData(i); symbol.children.clear();}
  280. // setup children
  281. FREPA(Symbols)
  282. {
  283. Symbol &symbol=Symbols.lockedData(i);
  284. if(symbol.valid && symbol.parent && symbol.parent->type==Symbol::CLASS) // use direct parent (without skipping transparent classes), skip function params, templates and other useless stuff
  285. if((symbol.isVar() && !(symbol.modifiers&Symbol::MODIF_STATIC)) // non-static variables
  286. || (symbol.type==Symbol::CLASS && (symbol.modifiers&Symbol::MODIF_TRANSPARENT)) // transparent classes
  287. || (symbol.type==Symbol::FUNC_LIST)) // func lists
  288. symbol.parent->children.add(&symbol);
  289. }
  290. // sort the children by the token index (to make sure that they are in the correct order)
  291. FREPA(Symbols)Symbols.lockedData(i).children.sort(CompareTokenIndex);
  292. }
  293. /******************************************************************************/
  294. // TODO: call this for 32/64
  295. static void SetArchitecture(Bool config_32_bit)
  296. {
  297. PtrSize=(config_32_bit ? 4 : 8);
  298. Symbols( "intptr")->value=(config_32_bit ? "int" : "long");
  299. Symbols("uintptr")->value=(config_32_bit ? "uint" : "ulong");
  300. }
  301. /******************************************************************************/
  302. void CodeEnvironment::del()
  303. {
  304. main_thread.del();
  305. func_bodies.del();
  306. heap .del(); heap_size=0;
  307. // set all token.parent of functions to the function (to remove any references for symbols from inside the function), set func.parsed to false
  308. FREPA(Symbols){Symbol &symbol=Symbols.lockedData(i); if(symbol.source && symbol.source->active && symbol.valid)symbol.clearBody(); symbol.raw_offset=-1;}
  309. // delete all symbols from functions from active sources (except function params "void func(int param) {}" and function templates "<TYPE> void func() {}")
  310. FREPA(CE.sources) // iterate all sources
  311. {
  312. Source &source=CE.sources[i];
  313. if(source.active)REPA(source.symbols) // iterate all symbols from active source
  314. {
  315. Symbol &symbol=*source.symbols[i];
  316. if(!(symbol.modifiers&Symbol::MODIF_FUNC_PARAM)) // skip function parameters
  317. if(Symbol *root_func=symbol.rootFunc()) // get root function of the symbol
  318. if(root_func!=&symbol) // if we're not processing the function itself
  319. if(symbol.token_index > root_func->token_index) // if symbol is defined after the function definition (this will skip the function templates "<TYPE> void func() {}")
  320. source.symbols.remove(i); // remove that symbol
  321. }
  322. }
  323. }
  324. Bool CodeEnvironment::create(Memc<Message> &msgs)
  325. {
  326. del();
  327. //SetArchitecture(CE.config_32_bit);
  328. SetupChildren();
  329. Memc<Symbol*> sorted_classes;
  330. if(VerifySymbols(msgs, sorted_classes))
  331. {
  332. CompilerContext ctx(T);
  333. ctx.store_known_global_var_on_heap=true;
  334. // initialize the heap
  335. FREPA(Symbols)
  336. {
  337. Symbol &symbol=Symbols.lockedData(i);
  338. if(symbol.source && symbol.source->active && symbol.valid && symbol.isVar() && symbol.isGlobalOrStatic())
  339. {
  340. Int size=symbol.rawSize(true);
  341. symbol.raw_offset=AlignAddress(heap_size, symbol.firstMemberSize());
  342. heap_size=symbol.raw_offset+size;
  343. }
  344. }
  345. // allocate room for 2 functions (global var init and shut) so they are first on the list
  346. Int func_global_vars=func_bodies.addNum(2);
  347. // compile function bodies
  348. FREPA(Symbols)
  349. {
  350. Symbol &symbol=Symbols.lockedData(i);
  351. if(symbol.source && symbol.source->active && symbol.valid && symbol.isFunc() && (symbol.modifiers&Symbol::MODIF_FUNC_BODY))
  352. {
  353. symbol.raw_offset=func_bodies.elms();
  354. func_bodies.New().create(symbol, msgs, ctx);
  355. }
  356. }
  357. // initialize global variables
  358. createGlobalVarSetup(func_global_vars, msgs, ctx);
  359. // link function bodies
  360. REPAO(func_bodies).link(msgs, T);
  361. // check for errors
  362. Bool ok=true; REPA(msgs)if(msgs[i].type==Message::ERROR){ok=false; break;}
  363. if( !ok)
  364. {
  365. func_bodies.del();
  366. return false;
  367. }
  368. // create the heap
  369. heap.setNumZero(heap_size);
  370. // copy constants
  371. REPA(ctx. constants){CompilerContext::Constant &c=ctx. constants[i]; Copy(heap.data()+c.heap_offset, ctx.const_data.data()+c.const_offset, c.size);}
  372. REPA(ctx.var_constants){CompilerContext::Constant &c=ctx.var_constants[i]; Copy(heap.data()+c.heap_offset, ctx.const_data.data()+c.const_offset, c.size);}
  373. // optimize function bodies
  374. REPAO(func_bodies).optimize(msgs, T);
  375. // create the main thread
  376. main_thread.create(T);
  377. return true;
  378. }
  379. return false;
  380. }
  381. /******************************************************************************/
  382. void CodeEditor::playEsenthelCompiler()
  383. {
  384. Bool debug=CE.config_debug;
  385. CE.stopBuild ();
  386. CE.buildClear();
  387. CE.buildNew ().set(S+"Compiling Project (using Esenthel compiler, "+(debug ? "Debug" : "Release")+" configuration)");
  388. CE.buildNew ().set("-------------");
  389. Memc<Message> msgs;
  390. CodeEnvironment CEnv; CEnv.debug=debug;
  391. Dbl compile_time=Time.curTime(); Bool ok=(CE.verifyBuildFiles(msgs) && CEnv.create(msgs));
  392. compile_time=Time.curTime()-compile_time;
  393. CE.buildNew(msgs.sort(Compare));
  394. CE.buildNew().set(S+"Codes compiled in "+Flt(compile_time)+"s");
  395. // TODO:
  396. if(ok)
  397. if(SymbolPtr main=FindSymbol("Main", null))if(main->type==Symbol::FUNC_LIST)
  398. REPA(main->funcs)if(Symbol *m=main->funcs[i]())
  399. if(!m->hasResult() && !m->params.elms() && InRange(m->raw_offset, CEnv.func_bodies))
  400. {
  401. Bool safe=true;
  402. Dbl run_time=Time.curTime();
  403. if(safe && InRange(0, CEnv.func_bodies))safe=CEnv.main_thread.start(CEnv.func_bodies[ 0]); // init global vars
  404. if(safe )safe=CEnv.main_thread.start(CEnv.func_bodies[m->raw_offset]); // func
  405. if(safe && InRange(1, CEnv.func_bodies))safe=CEnv.main_thread.start(CEnv.func_bodies[ 1]); // shut global vars
  406. run_time=Time.curTime()-run_time;
  407. if(!safe)CE.buildNew().set(S+"Program triggered unhandled exception!");
  408. CE.buildNew().set(S+"Codes executed in "+Flt(run_time)+"s");
  409. break;
  410. }
  411. Int errors=0, warnings=0;
  412. REPA(msgs)switch(msgs[i].type)
  413. {
  414. case Message::ERROR : errors ++; break;
  415. case Message::WARNING: warnings++; break;
  416. }
  417. if(msgs.elms())CE.buildNew ().set("-------------");
  418. CE.buildNew ().set(S+(ok ? "Success" : "Failed")+", errors: "+errors+", warnings: "+warnings);
  419. CE.buildUpdate();
  420. }
  421. /******************************************************************************/
  422. }}
  423. /******************************************************************************/