gmMachine.cpp 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017
  1. /*
  2. _____ __ ___ __ ____ _ __
  3. / ___/__ ___ _ ___ / |/ /__ ___ / /_____ __ __/ __/_______(_)__ / /_
  4. / (_ / _ `/ ' \/ -_) /|_/ / _ \/ _ \/ '_/ -_) // /\ \/ __/ __/ / _ \/ __/
  5. \___/\_,_/_/_/_/\__/_/ /_/\___/_//_/_/\_\\__/\_, /___/\__/_/ /_/ .__/\__/
  6. /___/ /_/
  7. See Copyright Notice in gmMachine.h
  8. */
  9. #include "gmConfig.h"
  10. #include "gmMachine.h"
  11. #include "gmThread.h"
  12. #include "gmTableObject.h"
  13. #include "gmStringObject.h"
  14. #include "gmUserObject.h"
  15. #include "gmFunctionObject.h"
  16. #if !GMMACHINE_REMOVECOMPILER
  17. #include "gmCodeTree.h"
  18. #include "gmCodeGen.h"
  19. #endif //GMMACHINE_REMOVECOMPILER
  20. #include "gmOperators.h"
  21. #include "gmMachineLib.h"
  22. #include "gmCrc.h"
  23. #include "gmStream.h"
  24. #include "gmLibHooks.h"
  25. #if GM_USE_INCGC
  26. #include "gmIncGC.h"
  27. #endif //GM_USE_INCGC
  28. #if !GM_USE_INCGC
  29. #define GM_ADDOBJECT(A) { (A)->m_sysNext = m_objects; m_objects = (A); }
  30. #endif //!GM_USE_INCGC
  31. //
  32. //
  33. // gmHooks is an implementation of gmCodeGenHooks and is used by gmMachine to compile gm scripts.
  34. //
  35. //
  36. class gmHooks : public gmCodeGenHooks
  37. {
  38. public:
  39. gmHooks(gmMachine * a_machine, const char * a_source, const char * a_filename);
  40. virtual ~gmHooks();
  41. virtual bool Begin(bool a_debug);
  42. virtual bool AddFunction(gmFunctionInfo &a_info);
  43. virtual bool End(int a_errors);
  44. virtual gmptr GetFunctionId();
  45. virtual gmptr GetSymbolId(const char * a_symbol);
  46. virtual gmptr GetStringId(const char * a_string);
  47. gmFunctionObject * GetRootFunction() { return m_rootFunction; }
  48. private:
  49. gmFunctionObject * m_rootFunction;
  50. int m_errors;
  51. bool m_debug;
  52. bool m_gcEnabled;
  53. gmMachine * m_machine;
  54. const char * m_source;
  55. const char * m_filename;
  56. gmuint32 m_sourceId;
  57. };
  58. //
  59. //
  60. // Implementation of gmSourceEntry, used for storing source code in debug mode
  61. //
  62. //
  63. class gmSourceEntry : public gmListDoubleNode<gmSourceEntry>
  64. {
  65. public:
  66. gmSourceEntry(const char * a_source, const char * a_filename)
  67. {
  68. int slen = (int)strlen(a_source);
  69. int flen = (int)strlen(a_filename);
  70. m_id = gmCrc32String(a_source);
  71. m_source = GM_NEW( char[slen + flen + 2] );
  72. memcpy(m_source, a_source, slen + 1);
  73. m_filename = m_source + slen + 1;
  74. memcpy(m_filename, a_filename, flen + 1);
  75. }
  76. ~gmSourceEntry()
  77. {
  78. if(m_source)
  79. delete[] m_source;
  80. }
  81. gmuint32 m_id;
  82. char * m_source;
  83. char * m_filename;
  84. };
  85. //
  86. //
  87. // Implementation of gmBlock, gmSignal, gmBlocklist for thread blocking
  88. //
  89. //
  90. class gmBlockList : public gmHashNode<gmVariable, gmBlockList, gmVariable>
  91. {
  92. public:
  93. gmBlockList() {}
  94. virtual ~gmBlockList() {}
  95. virtual const gmVariable &GetKey() const
  96. {
  97. return m_block;
  98. }
  99. gmVariable m_block;
  100. gmListDouble<gmBlock> m_blocks;
  101. };
  102. //
  103. //
  104. // Default Print Callback
  105. //
  106. //
  107. void gmDefaultPrintCallback(gmMachine * a_machine, const char * a_string)
  108. {
  109. GM_PRINTF("%s"GM_NL, a_string);
  110. }
  111. //
  112. //
  113. // Implementation of gmMachine
  114. //
  115. //
  116. gmMachineCallback gmMachine::s_machineCallback = NULL;
  117. gmPrintCallback gmMachine::s_printCallback = gmDefaultPrintCallback;
  118. gmUserBreakCallback gmMachine::s_userBreakCallback = NULL;
  119. #if GM_USE_INCGC
  120. void GM_CDECL gmMachine::ScanRootsCallBack(gmMachine* a_machine, gmGarbageCollector* a_gc)
  121. {
  122. gmThread * tit;
  123. // call the gc callback
  124. if(s_machineCallback) s_machineCallback(a_machine, MC_COLLECT_GARBAGE, NULL);
  125. // iterate cpp owned gmObjects
  126. gmHash<gmObject*, ObjHashNode>::Iterator cgmoIt;
  127. for(cgmoIt = a_machine->m_cppOwnedGMObjs.First(); cgmoIt; ++cgmoIt)
  128. {
  129. gmObject* curObj = cgmoIt->m_obj;
  130. a_gc->GetNextObject(curObj);
  131. }
  132. // iterate over all threads and mark the stacks.
  133. for(tit = a_machine->m_runningThreads.GetFirst(); a_machine->m_runningThreads.IsValid(tit); tit = a_machine->m_runningThreads.GetNext(tit)) tit->GCScanRoots(a_machine, a_gc);
  134. for(tit = a_machine->m_blockedThreads.GetFirst(); a_machine->m_blockedThreads.IsValid(tit); tit = a_machine->m_blockedThreads.GetNext(tit)) tit->GCScanRoots(a_machine, a_gc);
  135. for(tit = a_machine->m_sleepingThreads.GetFirst(); a_machine->m_sleepingThreads.IsValid(tit); tit = a_machine->m_sleepingThreads.GetNext(tit)) tit->GCScanRoots(a_machine, a_gc);
  136. for(tit = a_machine->m_exceptionThreads.GetFirst(); a_machine->m_exceptionThreads.IsValid(tit); tit = a_machine->m_sleepingThreads.GetNext(tit)) tit->GCScanRoots(a_machine, a_gc);
  137. // iterate over global variables and mark
  138. if(a_machine->m_global)
  139. {
  140. a_gc->GetNextObject(a_machine->m_global);
  141. }
  142. // iterate over type variables and mark
  143. gmuint i;
  144. for(i = 0; i < a_machine->m_types.Count(); ++i)
  145. {
  146. a_gc->GetNextObject(a_machine->m_types[i].m_variables);
  147. }
  148. #if !GM_GC_KEEP_PERSISTANT_SEPARATE
  149. //NOTE This needs to be spread over time perhaps.
  150. for(i=0; i<(gmuint)a_machine->m_numPermanantStrings; ++i)
  151. {
  152. a_gc->GetNextObject(a_machine->m_permanantStrings[i]);
  153. }
  154. #endif //!GM_GC_KEEP_PERSISTANT_SEPARATE
  155. }
  156. #endif //GM_USE_INCGC
  157. gmMachine::gmMachine()
  158. :
  159. m_threads(128),
  160. m_memStringObj(sizeof(gmStringObject), GMMACHINE_STRINGCHUNKSIZE),
  161. m_memTableObj(sizeof(gmTableObject), GMMACHINE_TBLCHUNKSIZE),
  162. m_memFunctionObj(sizeof(gmFunctionObject), GMMACHINE_OBJECTCHUNKSIZE),
  163. m_memUserObj(sizeof(gmUserObject), GMMACHINE_OBJECTCHUNKSIZE),
  164. m_memStackFrames(sizeof(gmStackFrame), GMMACHINE_STACKFCHUNKSIZE),
  165. m_strings(GMMACHINE_STRINGHASHSIZE),
  166. m_blocks(64),
  167. m_cppOwnedGMObjs(GMMACHINE_CPPOWNEDGMOBJHASHSIZE)
  168. {
  169. m_line = NULL;
  170. m_call = NULL;
  171. m_return = NULL;
  172. m_isBroken = NULL;
  173. #if GM_USE_INCGC
  174. m_gc = GM_NEW( gmGarbageCollector );
  175. m_gc->Init(ScanRootsCallBack, this);
  176. #if !GM_GC_KEEP_PERSISTANT_SEPARATE
  177. m_permanantStrings.SetCount(0);
  178. #endif //!GM_GC_KEEP_PERSISTANT_SEPARATE
  179. #endif //GM_USE_INCGC
  180. m_global = NULL;
  181. m_objects = NULL;
  182. m_threadId = 0;
  183. m_nextThread = NULL;
  184. m_nextThreadValid = false;
  185. m_autoMem = GMMACHINE_AUTOMEM;
  186. m_currentMemoryUsage = 0;
  187. m_desiredByteMemoryUsageHard = GMMACHINE_INITIALGCHARDLIMIT;
  188. m_desiredByteMemoryUsageSoft = GMMACHINE_INITIALGCSOFTLIMIT;
  189. m_mark = GM_MARK_START;
  190. m_framesSinceLastIncCollect = 0;
  191. m_gcPhaseCount = 0;
  192. m_statsGCFullCollect = 0;
  193. m_statsGCIncCollect = 0;
  194. m_statsGCWarnings = 0;
  195. m_debug = false;
  196. m_debugUser = NULL;
  197. m_gcEnabled = true;
  198. m_global = AllocTableObject(); // Alloc global table
  199. m_types.SetCount(0);
  200. ResetDefaultTypes();
  201. m_time = 0;
  202. gmMachineLib(this);
  203. }
  204. gmMachine::~gmMachine()
  205. {
  206. ResetAndFreeMemory();
  207. #if GM_USE_INCGC
  208. delete m_gc;
  209. #endif //GM_USE_INCGC
  210. }
  211. void gmMachine::ResetAndFreeMemory()
  212. {
  213. #if GM_USE_INCGC
  214. m_gc->DestructAll();
  215. #if !GM_GC_KEEP_PERSISTANT_SEPARATE
  216. m_permanantStrings.SetCount(0);
  217. #endif //!GM_GC_KEEP_PERSISTANT_SEPARATE
  218. m_global = NULL;
  219. gmuint i;
  220. for(i = 0; i < m_types.Count(); ++i)
  221. {
  222. m_types[i].m_variables = NULL;
  223. m_types[i].m_name = NULL;
  224. }
  225. //FindMissingCountObj();
  226. #else //GM_USE_INCGC
  227. // destruct all objects
  228. for(gmObject* it = m_objects; it; )
  229. {
  230. gmObject * nit = it->m_sysNext;
  231. it->Destruct(this);
  232. FreeObject(it);
  233. it = nit;
  234. }
  235. m_global = NULL; //Global was freed with the rest
  236. // operators\types
  237. gmuint i;
  238. for(i = 0; i < m_types.Count(); ++i)
  239. {
  240. m_types[i].m_variables = NULL;
  241. m_types[i].m_name = NULL;
  242. }
  243. #endif //GM_USE_INCGC
  244. m_objects = NULL;
  245. // string table
  246. GM_ASSERT(m_strings.Count() == 0);
  247. m_strings.RemoveAll();
  248. // threads
  249. m_runningThreads.RemoveAll();
  250. m_blockedThreads.RemoveAll();
  251. m_sleepingThreads.RemoveAll();
  252. m_exceptionThreads.RemoveAll();
  253. m_killedThreads.RemoveAndDeleteAll();
  254. m_threads.RemoveAndDeleteAll();
  255. m_threadId = 0;
  256. m_time = 0;
  257. m_nextThread = NULL;
  258. m_nextThreadValid = false;
  259. GM_ASSERT(m_blocks.Count() == 0);
  260. // CPP owned gmObjects
  261. m_cppOwnedGMObjs.RemoveAll();
  262. // memory allocators (make sure we arent leaking memory)
  263. GM_ASSERT(m_memStringObj.GetMemUsed() == 0);
  264. m_memStringObj.ResetAndFreeMemory();
  265. GM_ASSERT(m_memTableObj.GetMemUsed() == 0);
  266. m_memTableObj.ResetAndFreeMemory();
  267. GM_ASSERT(m_memFunctionObj.GetMemUsed() == 0);
  268. m_memFunctionObj.ResetAndFreeMemory();
  269. GM_ASSERT(m_memUserObj.GetMemUsed() == 0);
  270. m_memUserObj.ResetAndFreeMemory();
  271. GM_ASSERT(m_memStackFrames.GetMemUsed() == 0);
  272. m_memStackFrames.ResetAndFreeMemory();
  273. GM_ASSERT(m_fixedSet.GetMemUsed() == 0);
  274. m_fixedSet.ResetAndFreeMemory();
  275. m_debug = false;
  276. m_debugUser = NULL;
  277. m_source.RemoveAndDeleteAll();
  278. // types
  279. m_types.ResetAndFreeMemory();
  280. // compiler
  281. m_log.ResetAndFreeMemory();
  282. #if !GMMACHINE_REMOVECOMPILER
  283. gmCodeTree::Get().FreeMemory();
  284. gmCodeGen::Get().FreeMemory();
  285. #endif //GMMACHINE_REMOVECOMPILER
  286. // garbage collection
  287. m_autoMem = GMMACHINE_AUTOMEM;
  288. m_currentMemoryUsage = 0;
  289. m_desiredByteMemoryUsageHard = GMMACHINE_INITIALGCHARDLIMIT;
  290. m_desiredByteMemoryUsageSoft = GMMACHINE_INITIALGCSOFTLIMIT;
  291. m_mark = GM_MARK_START;
  292. m_gcEnabled = true;
  293. }
  294. void gmMachine::Init()
  295. {
  296. m_gcEnabled = true;
  297. m_threadId = 0;
  298. m_autoMem = GMMACHINE_AUTOMEM;
  299. m_currentMemoryUsage = 0;
  300. m_desiredByteMemoryUsageHard = GMMACHINE_INITIALGCHARDLIMIT;
  301. m_desiredByteMemoryUsageSoft = GMMACHINE_INITIALGCSOFTLIMIT;
  302. m_mark = GM_MARK_START;
  303. m_global = AllocTableObject(); // Alloc global table
  304. m_types.SetCount(0);
  305. ResetDefaultTypes();
  306. m_blocks.RemoveAll();
  307. m_cppOwnedGMObjs.RemoveAll();
  308. m_time = 0;
  309. m_debug = false;
  310. gmMachineLib(this);
  311. }
  312. void gmMachine::RegisterLibrary(gmFunctionEntry * a_functions, int a_numFunctions, const char * a_asTable, bool a_newTable)
  313. {
  314. gmTableObject * table = m_global;
  315. if( a_asTable )
  316. {
  317. #if GM_CASE_INSENSITIVE
  318. char * asTable = (char *) gmNewStackArray(char, strlen(a_asTable) + 1);
  319. strcpy(asTable, a_asTable);
  320. _strlwr(asTable);
  321. a_asTable = asTable;
  322. #endif // GM_CASE_INSENSITIVE
  323. if( a_newTable == true )
  324. {
  325. table = AllocTableObject();
  326. }
  327. else
  328. {
  329. gmVariable tabVar = m_global->Get(this, a_asTable);
  330. if( tabVar.m_type == GM_TABLE )
  331. {
  332. // Existing table found, use this
  333. table = (gmTableObject *)tabVar.m_value.m_ref;
  334. }
  335. else
  336. {
  337. // Otherwise create a new table afterall
  338. table = AllocTableObject();
  339. }
  340. }
  341. m_global->Set(this, a_asTable, gmVariable(GM_TABLE, (gmptr) table));
  342. }
  343. GM_ASSERT(table);
  344. for(int index = 0; index < a_numFunctions; ++index )
  345. {
  346. gmFunctionObject* funcObj = AllocFunctionObject(a_functions[index].m_function);
  347. funcObj->m_cUserData = a_functions[index].m_userData;
  348. #if GM_CASE_INSENSITIVE
  349. char * funcNameLower = (char *) gmNewStackArray(char, strlen(a_functions[index].m_name) + 1);
  350. strcpy(funcNameLower, a_functions[index].m_name);
  351. _strlwr(funcNameLower);
  352. table->Set(this, funcNameLower, gmVariable(GM_FUNCTION, (gmptr)funcObj));
  353. #else // !GM_CASE_INSENSITIVE
  354. table->Set(this, a_functions[index].m_name, gmVariable(GM_FUNCTION, (gmptr)funcObj));
  355. #endif // !GM_CASE_INSENSITIVE
  356. }
  357. }
  358. void gmMachine::RegisterTypeLibrary(gmType a_type, gmFunctionEntry * a_functions, int a_numFunctions)
  359. {
  360. int i;
  361. for(i = 0; i < a_numFunctions; ++i)
  362. {
  363. gmFunctionObject* funcObj = AllocFunctionObject(a_functions[i].m_function);
  364. funcObj->m_cUserData = a_functions[i].m_userData;
  365. RegisterTypeVariable(a_type, a_functions[i].m_name, gmVariable(GM_FUNCTION, (gmptr)funcObj));
  366. }
  367. }
  368. gmType gmMachine::CreateUserType(const char * a_name)
  369. {
  370. bool enabled = IsGCEnabled();
  371. EnableGC(false); //Disable GC as user types are roots and we are in the middle of creating a new one
  372. gmType type = (gmType) m_types.Count();
  373. m_types.InsertLast();
  374. m_types[type].Init();
  375. m_types[type].m_name = AllocPermanantStringObject(a_name);
  376. gmInitBasicType(GM_USER, m_types[type].m_nativeOperators);
  377. // Alloc user type table
  378. m_types[type].m_variables = AllocTableObject();
  379. EnableGC(enabled); //Restore GC
  380. return type;
  381. }
  382. #if GM_USE_INCGC
  383. void gmMachine::RegisterUserCallbacks(gmType a_type, gmGCTraceCallback a_gcTrace, gmGCDestructCallback a_gcDestruct, gmAsStringCallback a_asString)
  384. {
  385. m_types[a_type].m_gcTrace = a_gcTrace;
  386. m_types[a_type].m_gcDestruct = a_gcDestruct;
  387. m_types[a_type].m_asString = a_asString;
  388. }
  389. #else //GM_USE_INCGC
  390. void gmMachine::RegisterUserCallbacks(gmType a_type, gmGarbageCollectCallback a_mark, gmGarbageCollectCallback a_gc, gmAsStringCallback a_asString)
  391. {
  392. m_types[a_type].m_mark = a_mark;
  393. m_types[a_type].m_gc = a_gc;
  394. m_types[a_type].m_asString = a_asString;
  395. }
  396. #endif //GM_USE_INCGC
  397. void gmMachine::RegisterTypeVariable(gmType a_type, const char * a_variableName, const gmVariable &a_variable)
  398. {
  399. #if GM_CASE_INSENSITIVE
  400. char * varNameLower = (char *) gmNewStackArray(char, strlen(a_variableName) + 1);
  401. strcpy(varNameLower, a_variableName);
  402. _strlwr(varNameLower);
  403. m_types[a_type].m_variables->Set(this, varNameLower, a_variable);
  404. #else // !GM_CASE_INSENSITIVE
  405. m_types[a_type].m_variables->Set(this, a_variableName, a_variable);
  406. #endif // !GM_CASE_INSENSITIVE
  407. }
  408. bool gmMachine::RegisterTypeOperator(gmType a_type, gmOperator a_operator, gmFunctionObject * a_function, gmOperatorFunction a_nativeFunction)
  409. {
  410. // if(a_type < GM_USER) return false; //Prevent overriding default operators
  411. if(a_function)
  412. {
  413. m_types[a_type].m_operators[a_operator] = a_function->GetRef();
  414. }
  415. else if(a_nativeFunction)
  416. {
  417. m_types[a_type].m_nativeOperators[a_operator] = a_nativeFunction;
  418. }
  419. return true;
  420. }
  421. const char * gmMachine::GetTypeName(gmType a_type)
  422. {
  423. return (const char *) *m_types[a_type].m_name;
  424. }
  425. #if GM_USER_FOREACH
  426. bool gmMachine::RegisterTypeIterator(gmType a_type, gmTypeIteratorCallback a_callback)
  427. {
  428. m_types[a_type].m_itrFunc = a_callback;
  429. return true;
  430. }
  431. #endif //GM_USER_FOREACH
  432. int gmMachine::CheckSyntax(const char * a_string)
  433. {
  434. #if GMMACHINE_REMOVECOMPILER
  435. GetLog().LogEntry("No compiler in build");
  436. return 1;
  437. #else // GMMACHINE_REMOVECOMPILER
  438. gmCodeGenHooksNull nullHooks;
  439. // parse
  440. int errors = gmCodeTree::Get().Lock(a_string, &m_log);
  441. if(errors > 0)
  442. {
  443. gmCodeTree::Get().Unlock();
  444. return errors;
  445. }
  446. // compile
  447. errors = gmCodeGen::Get().Lock(gmCodeTree::Get().GetCodeTree(), &nullHooks, true, &m_log);
  448. if(errors > 0)
  449. {
  450. gmCodeTree::Get().Unlock();
  451. gmCodeGen::Get().Unlock();
  452. return errors;
  453. }
  454. gmCodeTree::Get().Unlock();
  455. gmCodeGen::Get().Unlock();
  456. return errors;
  457. #endif //GMMACHINE_REMOVECOMPILER
  458. }
  459. int gmMachine::ExecuteString(const char * a_string, int * a_threadId, bool a_now, const char * a_filename, gmVariable* a_this)
  460. {
  461. #if GMMACHINE_REMOVECOMPILER
  462. GetLog().LogEntry("No compiler in build");
  463. return 1;
  464. #else // GMMACHINE_REMOVECOMPILER
  465. if(a_threadId) { *a_threadId = GM_INVALID_THREAD; }
  466. // parse
  467. int errors = gmCodeTree::Get().Lock(a_string, &m_log);
  468. if(errors > 0)
  469. {
  470. gmCodeTree::Get().Unlock();
  471. return errors;
  472. }
  473. // compile
  474. gmHooks hooks(this, a_string, a_filename);
  475. errors = gmCodeGen::Get().Lock(gmCodeTree::Get().GetCodeTree(), &hooks, m_debug, &m_log);
  476. if(errors > 0)
  477. {
  478. gmCodeTree::Get().Unlock();
  479. gmCodeGen::Get().Unlock();
  480. return errors;
  481. }
  482. gmCodeTree::Get().Unlock();
  483. gmCodeGen::Get().Unlock();
  484. // null or this
  485. gmVariable thisVar;
  486. if(!a_this)
  487. {
  488. thisVar.Nullify();
  489. }
  490. else
  491. {
  492. thisVar = *a_this;
  493. }
  494. // execute
  495. gmThread * thread = CreateThread(thisVar, gmVariable(GM_FUNCTION, (gmptr) hooks.GetRootFunction()), a_threadId);
  496. if(a_now)
  497. {
  498. thread->Sys_Execute();
  499. }
  500. return 0;
  501. #endif // GMMACHINE_REMOVECOMPILER
  502. }
  503. bool gmMachine::ExecuteLib(gmStream &a_stream, int * a_threadId, bool a_now, const char * a_filename, gmVariable* a_this)
  504. {
  505. gmFunctionObject * rootFunction = gmLibHooks::BindLib(*this, a_stream, a_filename);
  506. if(rootFunction)
  507. {
  508. // null or this
  509. gmVariable thisVar;
  510. if(!a_this)
  511. {
  512. thisVar.Nullify();
  513. }
  514. else
  515. {
  516. thisVar = *a_this;
  517. }
  518. gmThread * thread = CreateThread(thisVar, gmVariable(GM_FUNCTION, rootFunction->GetRef()), a_threadId);
  519. if(a_now)
  520. {
  521. thread->Sys_Execute();
  522. }
  523. return true;
  524. }
  525. return false;
  526. }
  527. bool gmMachine::ExecuteFunction(gmFunctionObject * a_function, int * a_threadId, bool a_now, gmVariable* a_this)
  528. {
  529. gmVariable thisVar;
  530. if(!a_this)
  531. {
  532. thisVar.Nullify();
  533. }
  534. else
  535. {
  536. thisVar = *a_this;
  537. }
  538. gmThread * thread = CreateThread(thisVar, gmVariable(GM_FUNCTION, a_function->GetRef()), a_threadId);
  539. if(a_now)
  540. {
  541. thread->Sys_Execute();
  542. }
  543. return true;
  544. }
  545. int gmMachine::CompileStringToLib(const char * a_string, gmStream &a_stream)
  546. {
  547. #if GMMACHINE_REMOVECOMPILER
  548. GetLog().LogEntry("No compiler in build");
  549. return 1;
  550. #else // GMMACHINE_REMOVECOMPILER
  551. // parse
  552. int errors = gmCodeTree::Get().Lock(a_string, &m_log);
  553. if(errors > 0)
  554. {
  555. gmCodeTree::Get().Unlock();
  556. return errors;
  557. }
  558. #if 0 // Dump code tree to file for debugging
  559. FILE * fp = fopen("c:/codetree.txt", "wb");
  560. gmCodeTree::Get().Print(fp);
  561. fclose(fp);
  562. #endif
  563. // compile
  564. gmLibHooks hooks(a_stream, a_string);
  565. errors = gmCodeGen::Get().Lock(gmCodeTree::Get().GetCodeTree(), &hooks, m_debug, &m_log);
  566. gmCodeTree::Get().Unlock();
  567. gmCodeGen::Get().Unlock();
  568. return errors;
  569. #endif // GMMACHINE_REMOVECOMPILER
  570. }
  571. gmFunctionObject * gmMachine::CompileStringToFunction(const char * a_string, int *a_errorCount, const char * a_filename)
  572. {
  573. #if GMMACHINE_REMOVECOMPILER
  574. GetLog().LogEntry("No compiler in build");
  575. if(a_errorCount)
  576. {
  577. *a_errorCount++;
  578. }
  579. return NULL;
  580. #else // GMMACHINE_REMOVECOMPILER
  581. // parse
  582. int errors = gmCodeTree::Get().Lock(a_string, &m_log);
  583. if(errors > 0)
  584. {
  585. gmCodeTree::Get().Unlock();
  586. if(a_errorCount)
  587. *a_errorCount = errors;
  588. return NULL;
  589. }
  590. // compile
  591. gmHooks hooks(this, a_string, a_filename);
  592. errors = gmCodeGen::Get().Lock(gmCodeTree::Get().GetCodeTree(), &hooks, m_debug, &m_log);
  593. if(errors > 0)
  594. {
  595. gmCodeTree::Get().Unlock();
  596. gmCodeGen::Get().Unlock();
  597. if(a_errorCount)
  598. *a_errorCount = errors;
  599. return NULL;
  600. }
  601. gmCodeTree::Get().Unlock();
  602. gmCodeGen::Get().Unlock();
  603. if(a_errorCount)
  604. *a_errorCount = errors;
  605. return hooks.GetRootFunction();
  606. #endif //GMMACHINE_REMOVECOMPILER
  607. }
  608. gmFunctionObject * gmMachine::BindLibToFunction(gmStream &a_stream, const char * a_filename)
  609. {
  610. gmFunctionObject * rootFunction = gmLibHooks::BindLib(*this, a_stream, a_filename);
  611. return rootFunction;
  612. }
  613. gmThread * gmMachine::CreateThread(const gmVariable &a_this, const gmVariable &a_function, int * a_threadId)
  614. {
  615. gmThread * thread = CreateThread(a_threadId);
  616. thread->Push(a_this);
  617. thread->Push(a_function);
  618. if(thread->PushStackFrame(0, 0) == gmThread::RUNNING) return thread;
  619. return NULL;
  620. }
  621. void gmMachine::Sys_SignalCreateThread(gmThread * a_thread)
  622. {
  623. // Send create thread message
  624. if(s_machineCallback)
  625. {
  626. s_machineCallback(this, MC_THREAD_CREATE, a_thread);
  627. }
  628. }
  629. gmThread * gmMachine::CreateThread(int * a_threadId)
  630. {
  631. gmThread * thread = m_killedThreads.RemoveFirst();
  632. if(thread == NULL)
  633. {
  634. thread = GM_NEW( gmThread(this) );
  635. }
  636. thread->Sys_Reset(GetThreadId());
  637. if(a_threadId) *a_threadId = thread->GetId();
  638. m_threads.Insert(thread);
  639. thread->Sys_SetState(gmThread::RUNNING);
  640. thread->Sys_SetStartTime(m_time);
  641. m_runningThreads.InsertLast(thread); // insert last to maintain propper execution order.
  642. if( m_nextThreadValid
  643. && (!m_runningThreads.IsValid(m_nextThread)) )
  644. {
  645. m_nextThread = thread; // Inserted last, but iterator was at last pos, if we don't do this, we'll miss skip this thread until next cycle.
  646. }
  647. return thread;
  648. }
  649. gmThread * gmMachine::GetThread(int a_threadId)
  650. {
  651. return m_threads.Find(a_threadId);
  652. }
  653. bool gmMachine::Signal(const gmVariable &a_signal, int a_dstThreadId, int a_srcThreadId)
  654. {
  655. gmBlockList * blockList = m_blocks.Find(a_signal);
  656. bool used = false;
  657. if(blockList)
  658. {
  659. // iterate over all threads in the block list, and add the signal to the appropriate threads.
  660. gmBlock * block = blockList->m_blocks.GetFirst();
  661. while(blockList->m_blocks.IsValid(block))
  662. {
  663. gmThread * thread = block->m_thread;
  664. if(a_dstThreadId == GM_INVALID_THREAD || a_dstThreadId == thread->GetId())
  665. {
  666. gmSignal * signal = NULL;
  667. used = true;
  668. #if GM_USE_ENDON
  669. if(block->m_endOn == true)
  670. {
  671. block->m_signalled = true;
  672. block->m_srcThreadId = a_srcThreadId;
  673. Sys_SwitchState(thread, gmThread::KILLED);
  674. }
  675. else
  676. #endif //GM_USE_ENDON
  677. {
  678. // allocate a signal
  679. if(thread->GetState() == gmThread::SYS_PENDING)
  680. {
  681. signal = (gmSignal *) Sys_Alloc(sizeof(gmSignal));
  682. signal->m_signal = a_signal;
  683. signal->m_srcThreadId = a_srcThreadId;
  684. signal->m_dstThreadId = a_dstThreadId;
  685. signal->m_nextSignal = thread->Sys_GetSignals();
  686. thread->Sys_SetSignals(signal);
  687. }
  688. else
  689. {
  690. block->m_signalled = true;
  691. block->m_srcThreadId = a_srcThreadId;
  692. thread->Sys_SetState(gmThread::SYS_PENDING);
  693. }
  694. }
  695. if(a_dstThreadId != GM_INVALID_THREAD)
  696. {
  697. break;
  698. }
  699. }
  700. block = blockList->m_blocks.GetNext(block);
  701. }
  702. }
  703. return used;
  704. }
  705. #if GM_USE_ENDON
  706. int gmMachine::Sys_Block(gmThread * a_thread, int m_numBlocks, const gmVariable * a_blocks, bool a_endon)
  707. #else //GM_USE_ENDON
  708. int gmMachine::Sys_Block(gmThread * a_thread, int m_numBlocks, const gmVariable * a_blocks)
  709. #endif //GM_USE_ENDON
  710. {
  711. // use up our signals.
  712. gmSignal * signal = a_thread->Sys_GetSignals(), * next;
  713. while(signal)
  714. {
  715. int i;
  716. for(i = 0; i < m_numBlocks; ++i)
  717. {
  718. if(a_blocks[i].m_type == signal->m_signal.m_type &&
  719. a_blocks[i].m_value.m_ref == signal->m_signal.m_value.m_ref)
  720. {
  721. // remove the signal
  722. a_thread->Sys_SetSignals(signal->m_nextSignal);
  723. Sys_Free(signal);
  724. #if GM_USE_ENDON // NOTE: Not sure if this can ever occur
  725. if (a_endon)
  726. {
  727. // If this is set to end the thread and we've already got the signal
  728. // kill the thread now
  729. Sys_SwitchState(a_thread, gmThread::KILLED);
  730. }
  731. #endif //GM_USE_ENDON
  732. // return the block
  733. return i;
  734. }
  735. }
  736. // we didnt fire on the signal, so remove it.
  737. next = signal->m_nextSignal;
  738. #if GM_USE_ENDON
  739. if (a_endon == false) //only remove signals if we're running normal block logic, we don't want to gobble up signals!
  740. #endif //GM_USE_ENDON
  741. {
  742. a_thread->Sys_SetSignals(next);
  743. Sys_Free(signal);
  744. }
  745. signal = next;
  746. }
  747. // add the blocks.
  748. int i;
  749. for(i = 0; i < m_numBlocks; ++i)
  750. {
  751. // Catch attempts to block on null
  752. if( a_blocks[i].IsNull() )
  753. {
  754. return -2;
  755. }
  756. #if GM_USE_ENDON
  757. // hunt for an existing block on the thread
  758. gmBlock * block = a_thread->Sys_GetBlocks();
  759. while(block)
  760. {
  761. if (gmVariable::Compare(block->m_block, a_blocks[i]) == 0)
  762. {
  763. // found, error - can't block on this again
  764. GetLog().LogEntry("block or endon already set for thread");
  765. Sys_SwitchState(a_thread, gmThread::KILLED);
  766. return -3;
  767. }
  768. block = block->m_nextBlock;
  769. }
  770. #else //GM_USE_ENDON
  771. gmBlock * block;
  772. #endif //GM_USE_ENDON
  773. gmBlockList * blockList = m_blocks.Find(a_blocks[i]);
  774. if(blockList == NULL)
  775. {
  776. blockList = (gmBlockList *) Sys_Alloc(sizeof(gmBlockList));
  777. blockList = gmConstructElement<gmBlockList>(blockList);
  778. blockList->m_block = a_blocks[i];
  779. m_blocks.Insert(blockList);
  780. }
  781. block = (gmBlock *) Sys_Alloc(sizeof(gmBlock));
  782. block->m_list = blockList;
  783. block->m_block = a_blocks[i];
  784. block->m_signalled = false;
  785. #if GM_USE_ENDON
  786. block->m_endOn = a_endon;
  787. #endif //GM_USE_ENDON
  788. block->m_thread = a_thread;
  789. block->m_nextBlock = a_thread->Sys_GetBlocks();
  790. a_thread->Sys_SetBlocks(block);
  791. blockList->m_blocks.InsertFirst(block);
  792. }
  793. return -1;
  794. }
  795. void gmMachine::KillThread(int a_threadId)
  796. {
  797. gmThread * thread = GetThread(a_threadId);
  798. if(thread)
  799. {
  800. Sys_SwitchState(thread, gmThread::KILLED);
  801. }
  802. }
  803. void gmMachine::ForEachThread(gmThreadIteratorCallback a_callback, void * a_context)
  804. {
  805. gmListDouble<gmThread>::Iterator it;
  806. for(it = m_runningThreads.First(); it;)
  807. {
  808. gmThread * thread = it.Resolve();
  809. ++it;
  810. if(!a_callback(thread, a_context)) return;
  811. }
  812. for(it = m_blockedThreads.First(); it;)
  813. {
  814. gmThread * thread = it.Resolve();
  815. ++it;
  816. if(!a_callback(thread, a_context)) return;
  817. }
  818. for(it = m_sleepingThreads.First(); it;)
  819. {
  820. gmThread * thread = it.Resolve();
  821. ++it;
  822. if(!a_callback(thread, a_context)) return;
  823. }
  824. for(it = m_exceptionThreads.First(); it;)
  825. {
  826. gmThread * thread = it.Resolve();
  827. ++it;
  828. if(!a_callback(thread, a_context)) return;
  829. }
  830. }
  831. void gmMachine::Sys_SwitchState(gmThread * a_thread, int a_to)
  832. {
  833. if(a_thread->GetState() == (gmThread::State) a_to) return;
  834. switch(a_thread->GetState())
  835. {
  836. case gmThread::RUNNING :
  837. {
  838. Sys_RemoveSignals(a_thread);
  839. if(a_thread == m_nextThread)
  840. {
  841. m_nextThread = m_runningThreads.GetNext(a_thread);
  842. }
  843. m_runningThreads.Remove(a_thread);
  844. break;
  845. }
  846. case gmThread::BLOCKED :
  847. case gmThread::SYS_PENDING :
  848. {
  849. // remove and clean up the blocks.
  850. Sys_RemoveSignals(a_thread); // Prevent signals from accumulating
  851. Sys_RemoveBlocks(a_thread);
  852. m_blockedThreads.Remove(a_thread);
  853. break;
  854. }
  855. case gmThread::SLEEPING : m_sleepingThreads.Remove(a_thread); break;
  856. case gmThread::KILLED : m_killedThreads.Remove(a_thread); break;
  857. case gmThread::EXCEPTION : m_exceptionThreads.Remove(a_thread); break;
  858. default : GM_ASSERT(0); break;
  859. }
  860. switch(a_to)
  861. {
  862. case gmThread::RUNNING : m_runningThreads.InsertLast(a_thread); break;
  863. case gmThread::BLOCKED : m_blockedThreads.InsertFirst(a_thread); break;
  864. case gmThread::EXCEPTION : m_exceptionThreads.InsertFirst(a_thread); break;
  865. case gmThread::SLEEPING :
  866. {
  867. // insert ordered by thread time stamp (GetTimeStamp)
  868. gmListDouble<gmThread>::Iterator it = m_sleepingThreads.First();
  869. bool inserted = false;
  870. while(it)
  871. {
  872. if(it->GetTimeStamp() > a_thread->GetTimeStamp())
  873. {
  874. m_sleepingThreads.InsertBefore(it.Resolve(), a_thread);
  875. inserted = true;
  876. break;
  877. }
  878. ++it;
  879. }
  880. if(!inserted) m_sleepingThreads.InsertLast(a_thread);
  881. break;
  882. }
  883. case gmThread::KILLED :
  884. {
  885. // Change the thread state before resetting the thread for consistency.
  886. // The reset will clear the state.
  887. a_thread->Sys_SetState(gmThread::KILLED);
  888. // send destroy thread message
  889. if(s_machineCallback)
  890. {
  891. s_machineCallback(this, MC_THREAD_DESTROY, a_thread);
  892. }
  893. m_threads.Remove(a_thread);
  894. a_thread->Sys_Reset(0);
  895. if(m_killedThreads.Count() < GMMACHINE_MAXKILLEDTHREADS)
  896. {
  897. m_killedThreads.InsertFirst(a_thread);
  898. // Thread is dead and we don't want to set it's state (already set).
  899. // Besides it's ID is now invalid.
  900. return;
  901. }
  902. // NOTE: Might be good to always delay thread deletion so killed threads are valid in nested call stacks.
  903. // Would we need to take care not to reuse a recent thread if it could still be read/written to?
  904. delete a_thread;
  905. return;
  906. }
  907. default : GM_ASSERT(0); break;
  908. }
  909. a_thread->Sys_SetState((gmThread::State) a_to);
  910. }
  911. void gmMachine::KillExceptionThreads()
  912. {
  913. gmThread * thread = m_exceptionThreads.GetLast();
  914. while(m_exceptionThreads.IsValid(thread))
  915. {
  916. Sys_SwitchState(thread, gmThread::KILLED);
  917. thread = m_exceptionThreads.GetLast();
  918. }
  919. }
  920. int gmMachine::Execute(gmuint32 a_delta)
  921. {
  922. m_time += a_delta;
  923. //
  924. // Wake up any sleeping threads at their timestamp
  925. //
  926. for(;;)
  927. {
  928. gmThread * thread = m_sleepingThreads.GetFirst();
  929. if(m_sleepingThreads.IsValid(thread) && (thread->GetTimeStamp() <= m_time))
  930. {
  931. Sys_SwitchState(thread, gmThread::RUNNING);
  932. continue;
  933. }
  934. break;
  935. }
  936. //
  937. // Move all SYS_PENDING threads from the blocked list to the front of the RUNNING list.
  938. //
  939. gmThread * it, * nit;
  940. for(it = m_blockedThreads.GetFirst(); m_blockedThreads.IsValid(it);)
  941. {
  942. nit = m_blockedThreads.GetNext(it);
  943. if(it->GetState() == gmThread::SYS_PENDING)
  944. {
  945. // get the unblocking signal
  946. gmBlock * block = it->Sys_GetBlocks();
  947. while(block)
  948. {
  949. if(block->m_signalled) break;
  950. block = block->m_nextBlock;
  951. }
  952. GM_ASSERT(block);
  953. it->Pop();
  954. it->Push(block->m_block);
  955. // move the thread to the running state
  956. Sys_SwitchState(it, gmThread::RUNNING);
  957. }
  958. it = nit;
  959. }
  960. //
  961. // Execute running threads
  962. //
  963. m_nextThreadValid = true;
  964. for(it = m_runningThreads.GetFirst(); m_runningThreads.IsValid(it);)
  965. {
  966. m_nextThread = m_runningThreads.GetNext(it);
  967. it->Sys_Execute();
  968. it = m_nextThread;
  969. }
  970. m_nextThreadValid = false;
  971. CollectGarbage();
  972. return m_threads.Count();
  973. }
  974. void gmMachine::Presize(int a_pool8,
  975. int a_pool16,
  976. int a_pool24,
  977. int a_pool32,
  978. int a_pool64,
  979. int a_pool128,
  980. int a_pool256,
  981. int a_pool512,
  982. int a_gmStringObj,
  983. int a_gmTableObj,
  984. int a_gmFunctionObj,
  985. int a_gmUserObj,
  986. int a_gmStackFrame
  987. )
  988. {
  989. m_fixedSet.Presize(a_pool8, a_pool16, a_pool24, a_pool32, a_pool64, a_pool128, a_pool256, a_pool512);
  990. if( a_gmStringObj ) { m_memStringObj.Presize(a_gmStringObj); }
  991. if( a_gmTableObj) { m_memTableObj.Presize(a_gmTableObj); }
  992. if( a_gmFunctionObj ) { m_memFunctionObj.Presize(a_gmFunctionObj); }
  993. if( a_gmUserObj ) { m_memUserObj.Presize(a_gmUserObj); }
  994. if( a_gmStackFrame ) { m_memStackFrames.Presize(a_gmStackFrame); }
  995. }
  996. #if GM_USE_INCGC
  997. bool gmMachine::CollectGarbage(bool a_forceFullCollect)
  998. {
  999. // NOTES:
  1000. //
  1001. // 1) If the desired hard memory limit is set high and the
  1002. // desired soft memory limit collects before ever reaching the hard limit
  1003. // the actual amount of memory used is unknown as there is always some
  1004. // slack memory in use or being classified. This is normal, but may not
  1005. // help calibrate memory limits.
  1006. //
  1007. // 2) You may want to calibrate memory usage by setting the hard limit too low
  1008. // then letting it grow as it needs to. After that, adjust the soft limit
  1009. // until the full collects never occur.
  1010. //
  1011. // 3) The hard and soft limits should be set well above the actual used memory limit
  1012. // for efficient operation (wheather manually or automatically). If this is not
  1013. // the case, the GC may occur unnecessarily often.
  1014. //
  1015. bool result = false;
  1016. if(m_gcEnabled)
  1017. {
  1018. GM_ASSERT(GetDesiredByteMemoryUsageSoft() <= GetDesiredByteMemoryUsageHard());
  1019. GM_ASSERT(GetDesiredByteMemoryUsageHard() > 0);
  1020. // Even with assert, to prevent undefined behaviour, don't let soft limit be set above hard limit here.
  1021. if(GetDesiredByteMemoryUsageSoft() > GetDesiredByteMemoryUsageHard())
  1022. {
  1023. SetDesiredByteMemoryUsageSoft(GetDesiredByteMemoryUsageHard());
  1024. }
  1025. ++m_framesSinceLastIncCollect;
  1026. // Have we exceeded the hard limit?
  1027. if(a_forceFullCollect || (GetCurrentMemoryUsage() > GetDesiredByteMemoryUsageHard()))
  1028. {
  1029. //int beforeMemUsage = GetCurrentMemoryUsage();
  1030. ++m_statsGCFullCollect;
  1031. result = true;
  1032. // Perform full collection & reclaimation now
  1033. m_gc->FullCollect();
  1034. if(m_autoMem)
  1035. {
  1036. int afterMemUsage = GetCurrentMemoryUsage();
  1037. if(afterMemUsage < GetDesiredByteMemoryUsageSoft()) // Used must be below both soft and hard
  1038. {
  1039. float fracMemUsed = ((float)afterMemUsage / (float)GetDesiredByteMemoryUsageHard());
  1040. // If we hardly used any of our memory, let the memory limit shrink
  1041. if(fracMemUsed < GMMACHINE_GC_HARD_MEM_SHRINK_THRESH)
  1042. {
  1043. if( GMMACHINE_AUTOMEMALLOWSHRINK )
  1044. {
  1045. SetDesiredByteMemoryUsageHard( (int)(GMMACHINE_GC_HARD_MEM_DEC_FRAC_OF_USED * (float)afterMemUsage) );
  1046. SetDesiredByteMemoryUsageSoft( (int)(GMMACHINE_GC_SOFT_MEM_DEFAULT_FRAC_OF_HARD * (float)GetDesiredByteMemoryUsageHard()) );
  1047. }
  1048. }
  1049. else
  1050. {
  1051. float softFrac = (float)GetDesiredByteMemoryUsageSoft() / (float)GetDesiredByteMemoryUsageHard();
  1052. softFrac -= GMMACHINE_GC_SOFT_MEM_DEC_FRAC;
  1053. if(softFrac > GMMACHINE_GC_SOFT_MEM_MIN_FRAC)
  1054. {
  1055. // We ran out of memory, but the machine didn't need to, we should have started inc GC earlier
  1056. int desired = (int)(softFrac * (float)GetDesiredByteMemoryUsageHard());
  1057. if(desired > afterMemUsage)
  1058. {
  1059. SetDesiredByteMemoryUsageSoft(desired);
  1060. // NOTE: Not using GMMACHINE_AUTOMEMALLOWSHRINK here because hard limit is the critical
  1061. // one and soft limit was badly set, so allow soft to be shrunk in this case only.
  1062. }
  1063. }
  1064. else
  1065. {
  1066. // This should never occur.
  1067. // The GC needs to be configured to collect more per cycle so it finishes faster
  1068. // Check out the values of m_gc.GetWorkPerIncrement() and m_gc.GetDestructPerIncrement()
  1069. ++m_statsGCWarnings;
  1070. }
  1071. }
  1072. }
  1073. else
  1074. {
  1075. // We ran out of memory because we needed more than our limit, so increase limit
  1076. int newHard = (int)(GMMACHINE_GC_HARD_MEM_INC_FRAC_OF_USED * (float)afterMemUsage);
  1077. int newSoft = (int)(GMMACHINE_GC_SOFT_MEM_DEFAULT_FRAC_OF_HARD * (float)newHard);
  1078. if( !GMMACHINE_AUTOMEMALLOWSHRINK )
  1079. {
  1080. // Don't allow shrink
  1081. newSoft = gmMax(newSoft, GetDesiredByteMemoryUsageSoft());
  1082. newHard = gmMax(newHard, GetDesiredByteMemoryUsageHard());
  1083. // We can only size up, so make sure hard limit is at least this fraction above soft
  1084. float softFracHard = (float)newSoft / (float)newHard;
  1085. if( softFracHard < GMMACHINE_GC_SOFT_MEM_DEFAULT_FRAC_OF_HARD )
  1086. {
  1087. newHard = (int)(newSoft * (1.0f / GMMACHINE_GC_SOFT_MEM_DEFAULT_FRAC_OF_HARD) );
  1088. }
  1089. }
  1090. SetDesiredByteMemoryUsageHard( newHard );
  1091. SetDesiredByteMemoryUsageSoft( newSoft );
  1092. }
  1093. }
  1094. }
  1095. else
  1096. {
  1097. // If we are not collecting, see if we need to start
  1098. if(m_gc->IsOff())
  1099. {
  1100. // Have esceeded the soft limit?
  1101. if(GetCurrentMemoryUsage() > GetDesiredByteMemoryUsageSoft())
  1102. {
  1103. // Reclaim memory from known garbage if we can
  1104. if(!m_gc->ReclaimSomeFreeObjects())
  1105. {
  1106. ++m_gcPhaseCount;
  1107. // Turn GC back on
  1108. m_gc->ReclaimObjectsAndRestartCollection();
  1109. }
  1110. }
  1111. }
  1112. // If we are collecting, then collect some more this opportunity
  1113. if(!m_gc->IsOff())
  1114. {
  1115. if(m_gc->Collect())
  1116. {
  1117. // We have finished collecting. The to-be-freed memory will still be waiting for reclaimation.
  1118. if( m_gcPhaseCount == 2 )
  1119. {
  1120. m_gcPhaseCount = 0;
  1121. if(m_framesSinceLastIncCollect < GMMACHINE_GC_MIN_FRAMES_SINCE_RESTART)
  1122. {
  1123. // Since we got here and we have been collecting very regularly,
  1124. // the soft limit may be set too close to the actual memory usage
  1125. // causing oscilation. Both the hard and soft limits should be set higher.
  1126. ++m_statsGCWarnings;
  1127. }
  1128. m_framesSinceLastIncCollect = 0;
  1129. }
  1130. ++m_statsGCIncCollect;
  1131. // Note that this point is not the low memory after a GC cycle.
  1132. // It may be half of the two part process after restarting due to the alloc black method.
  1133. // If GC took a while, lots of new allocs may have built up also.
  1134. // This is the reason auto-calibrating memory limits in the soft range is difficult.
  1135. }
  1136. }
  1137. }
  1138. }
  1139. return result;
  1140. }
  1141. bool gmMachine::IsGCRunning()
  1142. {
  1143. return !m_gc->IsOff();
  1144. }
  1145. #else //GM_USE_INCGC
  1146. bool gmMachine::CollectGarbage(bool a_forceFullCollect)
  1147. {
  1148. gmThread * tit;
  1149. gmObject * obj;
  1150. // do we need to garbage collect?
  1151. if(m_gcEnabled && (a_forceFullCollect || (GetCurrentMemoryUsage() > m_desiredByteMemoryUsageHard)) )
  1152. {
  1153. //printf("************* COLLECTING GARBAGE ****************"GM_NL);
  1154. if(++m_mark == GM_MARK_PERSIST) m_mark = GM_MARK_START + 1;
  1155. // call the gc callback
  1156. if(s_machineCallback) s_machineCallback(this, MC_COLLECT_GARBAGE, (void *) &m_mark);
  1157. // iterate cpp owned gmObjects
  1158. gmHash<gmObject*, ObjHashNode>::Iterator cgmoIt;
  1159. for(cgmoIt = a_machine->m_cppOwnedGMObjs.First(); cgmoIt; ++cgmoIt)
  1160. {
  1161. gmObject* curObj = cgmoIt->m_obj;
  1162. curObj->Mark(a_machine, mark);
  1163. }
  1164. // iterate over all threads and mark the stacks.
  1165. for(tit = m_runningThreads.GetFirst(); m_runningThreads.IsValid(tit); tit = m_runningThreads.GetNext(tit)) tit->Mark(m_mark);
  1166. for(tit = m_blockedThreads.GetFirst(); m_blockedThreads.IsValid(tit); tit = m_blockedThreads.GetNext(tit)) tit->Mark(m_mark);
  1167. for(tit = m_sleepingThreads.GetFirst(); m_sleepingThreads.IsValid(tit); tit = m_sleepingThreads.GetNext(tit)) tit->Mark(m_mark);
  1168. for(tit = m_exceptionThreads.GetFirst(); m_exceptionThreads.IsValid(tit); tit = m_exceptionThreads.GetNext(tit)) tit->Mark(m_mark);
  1169. // iterate over global variables and mark
  1170. m_global->Mark(this, m_mark);
  1171. gmuint i;
  1172. for(i = 0; i < m_types.Count(); ++i)
  1173. {
  1174. m_types[i].m_variables->Mark(this, m_mark);
  1175. }
  1176. #if GMMACHINE_THREEPASSGC
  1177. // mark any persisting objects such that they may mark their children
  1178. obj = m_objects;
  1179. while(obj)
  1180. {
  1181. if(obj->m_mark == GM_MARK_PERSIST)
  1182. {
  1183. obj->Mark(this, m_mark);
  1184. }
  1185. obj = obj->m_sysNext;
  1186. }
  1187. #endif // GMMACHINE_THREEPASSGC
  1188. // iterate over all objects, destruct any old object and free it.
  1189. gmObject ** objnext = &m_objects;
  1190. while(*objnext)
  1191. {
  1192. obj = *objnext;
  1193. if(obj->m_mark != m_mark && obj->m_mark != GM_MARK_PERSIST)
  1194. {
  1195. *objnext = obj->m_sysNext;
  1196. obj->Destruct(this);
  1197. FreeObject(obj);
  1198. }
  1199. else
  1200. {
  1201. objnext = &obj->m_sysNext;
  1202. }
  1203. }
  1204. if(m_autoMem)
  1205. {
  1206. m_desiredByteMemoryUsageHard = (int) (GMMACHINE_AUTOMEMMULTIPY * (float) GetCurrentMemoryUsage());
  1207. }
  1208. return true;
  1209. }
  1210. return false;
  1211. }
  1212. bool gmMachine::IsGCRunning()
  1213. {
  1214. return false;
  1215. }
  1216. #endif //GM_USE_INCGC
  1217. unsigned int gmMachine::GetSystemMemUsed() const
  1218. {
  1219. unsigned int total = 0;
  1220. total += m_memStringObj.GetSystemMemUsed();
  1221. total += m_memTableObj.GetSystemMemUsed();
  1222. total += m_memFunctionObj.GetSystemMemUsed();
  1223. total += m_memUserObj.GetSystemMemUsed();
  1224. total += m_memStackFrames.GetSystemMemUsed();
  1225. total += m_fixedSet.GetSystemMemUsed();
  1226. // threads
  1227. gmThread * tit;
  1228. for(tit = m_runningThreads.GetFirst(); m_runningThreads.IsValid(tit); tit = m_runningThreads.GetNext(tit)) total += tit->GetSystemMemUsed();
  1229. for(tit = m_blockedThreads.GetFirst(); m_blockedThreads.IsValid(tit); tit = m_blockedThreads.GetNext(tit)) total += tit->GetSystemMemUsed();
  1230. for(tit = m_sleepingThreads.GetFirst(); m_sleepingThreads.IsValid(tit); tit = m_sleepingThreads.GetNext(tit)) total += tit->GetSystemMemUsed();
  1231. for(tit = m_killedThreads.GetFirst(); m_killedThreads.IsValid(tit); tit = m_killedThreads.GetNext(tit)) total += tit->GetSystemMemUsed();
  1232. for(tit = m_exceptionThreads.GetFirst(); m_exceptionThreads.IsValid(tit); tit = m_exceptionThreads.GetNext(tit)) total += tit->GetSystemMemUsed();
  1233. return total;
  1234. }
  1235. gmStringObject * gmMachine::AllocStringObject(const char * a_string, int a_length)
  1236. {
  1237. gmStringObject * newStringObj = m_strings.Find(a_string);
  1238. if(newStringObj)
  1239. {
  1240. m_gc->Revive(newStringObj); // If string was in free list waiting to be finalized, revive it.
  1241. return newStringObj;
  1242. }
  1243. if(a_length < 0)
  1244. {
  1245. a_length = (int)strlen(a_string);
  1246. }
  1247. char * string = (char *) Sys_Alloc(a_length + 1);
  1248. memcpy(string, a_string, a_length + 1);
  1249. #if GMMACHINE_GCEVERYALLOC
  1250. CollectGarbage();
  1251. #endif
  1252. newStringObj = (gmStringObject *) m_memStringObj.Alloc();
  1253. GM_PLACEMENT_NEW( gmStringObject(string, a_length), newStringObj );
  1254. #if GM_USE_INCGC
  1255. m_gc->AllocateObject(newStringObj);
  1256. //AddCountObj(newStringObj);
  1257. #else //GM_USE_INCGC
  1258. GM_ADDOBJECT(newStringObj);
  1259. #endif //GM_USE_INCGC
  1260. // insert into hash
  1261. m_strings.Insert(newStringObj);
  1262. m_currentMemoryUsage += sizeof(gmStringObject);
  1263. return newStringObj;
  1264. }
  1265. gmStringObject * gmMachine::AllocPermanantStringObject(const char * a_string, int a_length)
  1266. {
  1267. gmStringObject * newStringObj = AllocStringObject(a_string, a_length);
  1268. #if GM_USE_INCGC
  1269. newStringObj->SetPersist(true);
  1270. #if GM_GC_KEEP_PERSISTANT_SEPARATE
  1271. m_gc->MakeObjectPersistant(newStringObj);
  1272. #else //GM_GC_KEEP_PERSISTANT_SEPARATE
  1273. m_permanantStrings.InsertLast(newStringObj);
  1274. #endif //GM_GC_KEEP_PERSISTANT_SEPARATE
  1275. #else //GM_USE_INCGC
  1276. newStringObj->m_mark = GM_MARK_PERSIST;
  1277. #endif //GM_USE_INCGC
  1278. return newStringObj;
  1279. }
  1280. gmTableObject * gmMachine::AllocTableObject()
  1281. {
  1282. #if GMMACHINE_GCEVERYALLOC
  1283. CollectGarbage();
  1284. #endif
  1285. gmTableObject * newTableObj = (gmTableObject *) m_memTableObj.Alloc();
  1286. GM_PLACEMENT_NEW(gmTableObject, newTableObj);
  1287. #if GM_USE_INCGC
  1288. m_gc->AllocateObject(newTableObj);
  1289. //AddCountObj(newTableObj);
  1290. #else //GM_USE_INCGC
  1291. GM_ADDOBJECT(newTableObj);
  1292. #endif //GM_USE_INCGC
  1293. m_currentMemoryUsage += sizeof(gmTableObject);
  1294. return newTableObj;
  1295. }
  1296. gmFunctionObject * gmMachine::AllocFunctionObject(gmCFunction a_function)
  1297. {
  1298. #if GMMACHINE_GCEVERYALLOC
  1299. CollectGarbage();
  1300. #endif
  1301. gmFunctionObject * newFunctionObj = (gmFunctionObject *) m_memFunctionObj.Alloc();
  1302. GM_PLACEMENT_NEW(gmFunctionObject, newFunctionObj);
  1303. #if GM_USE_INCGC
  1304. m_gc->AllocateObject(newFunctionObj);
  1305. //AddCountObj(newFunctionObj);
  1306. #else //GM_USE_INCGC
  1307. GM_ADDOBJECT(newFunctionObj);
  1308. #endif //GM_USE_INCGC
  1309. newFunctionObj->m_cFunction = a_function;
  1310. m_currentMemoryUsage += sizeof(gmFunctionObject);
  1311. return newFunctionObj;
  1312. }
  1313. gmUserObject * gmMachine::AllocUserObject(void * a_user, int a_userType)
  1314. {
  1315. #if GMMACHINE_GCEVERYALLOC
  1316. CollectGarbage();
  1317. #endif
  1318. gmUserObject * newUserObj = (gmUserObject *) m_memUserObj.Alloc();
  1319. gmConstructElement<gmUserObject>(newUserObj);
  1320. #if GM_USE_INCGC
  1321. m_gc->AllocateObject(newUserObj);
  1322. //AddCountObj(newUserObj);
  1323. #else //GM_USE_INCGC
  1324. GM_ADDOBJECT(newUserObj);
  1325. #endif //GM_USE_INCGC
  1326. newUserObj->m_userType = a_userType;
  1327. newUserObj->m_user = a_user;
  1328. m_currentMemoryUsage += sizeof(gmUserObject);
  1329. return newUserObj;
  1330. }
  1331. void gmMachine::Sys_FreeUniqueString(const char * a_string)
  1332. {
  1333. if(m_strings.RemoveKey(a_string))
  1334. {
  1335. Sys_Free(const_cast<char *>(a_string));
  1336. }
  1337. }
  1338. int gmMachine::GetThreadId()
  1339. {
  1340. while(GetThread(++m_threadId)) {}
  1341. return m_threadId;
  1342. }
  1343. void gmMachine::FreeObject(gmObject * a_obj)
  1344. {
  1345. //RemoveCountObj(a_obj);
  1346. switch(a_obj->GetType())
  1347. {
  1348. case GM_STRING:
  1349. {
  1350. m_memStringObj.Free(a_obj);
  1351. m_currentMemoryUsage -= sizeof(gmStringObject);
  1352. break;
  1353. }
  1354. case GM_TABLE:
  1355. {
  1356. m_memTableObj.Free(a_obj);
  1357. m_currentMemoryUsage -= sizeof(gmTableObject);
  1358. break;
  1359. }
  1360. case GM_FUNCTION:
  1361. {
  1362. m_memFunctionObj.Free(a_obj);
  1363. m_currentMemoryUsage -= sizeof(gmFunctionObject);
  1364. break;
  1365. }
  1366. default: // >= GM_USER types
  1367. {
  1368. m_memUserObj.Free(a_obj);
  1369. m_currentMemoryUsage -= sizeof(gmUserObject);
  1370. break;
  1371. }
  1372. }
  1373. }
  1374. #if GM_USE_INCGC
  1375. gmObject * gmMachine::CheckReference(gmptr a_ref)
  1376. {
  1377. return m_gc->CheckReference(a_ref);
  1378. }
  1379. #else //GM_USE_INCGC
  1380. gmObject * gmMachine::CheckReference(gmptr a_ref)
  1381. {
  1382. for(gmObject* it = m_objects; it; it = it->m_sysNext)
  1383. {
  1384. if((gmptr)it == a_ref)
  1385. {
  1386. return it;
  1387. }
  1388. }
  1389. // check global refs
  1390. if(a_ref == (gmptr) m_global) return m_global;
  1391. GM_ASSERT(0);
  1392. return NULL;
  1393. }
  1394. #endif //GM_USE_INCGC
  1395. void gmMachine::Type::Init()
  1396. {
  1397. m_variables = NULL;
  1398. m_name = NULL;
  1399. memset(m_nativeOperators, 0, sizeof(gmOperatorFunction) * O_MAXOPERATORS);
  1400. memset(m_operators, 0, sizeof(gmptr) * O_MAXOPERATORS);
  1401. m_asString = NULL;
  1402. #if GM_USE_INCGC
  1403. m_gcDestruct = NULL;
  1404. m_gcTrace = NULL;
  1405. #else
  1406. m_mark = NULL;
  1407. m_gc = NULL;
  1408. #endif
  1409. m_asString = NULL;
  1410. #if GM_USER_FOREACH
  1411. m_itrFunc = NULL;
  1412. #endif //GM_USER_FOREACH
  1413. }
  1414. void gmMachine::ResetDefaultTypes()
  1415. {
  1416. // clean up old types
  1417. gmuint i;
  1418. for(i = 0; i < m_types.Count(); ++i)
  1419. {
  1420. #if GM_USE_INCGC
  1421. //Note, old objects must be null or already destructed by GC
  1422. m_types[i].m_variables = NULL;
  1423. m_types[i].m_name = NULL;
  1424. #else //GM_USE_INCGC
  1425. m_types[i].m_variables->Destruct(this);
  1426. FreeObject(m_types[i].m_variables);
  1427. m_types[i].m_name = NULL;
  1428. #endif //GM_USE_INCGC
  1429. }
  1430. // init the basic types
  1431. m_types.SetCount(GM_USER);
  1432. // Alloc type table
  1433. for(i=0; i<m_types.Count(); ++i)
  1434. {
  1435. m_types[i].Init();
  1436. m_types[i].m_variables = AllocTableObject();
  1437. }
  1438. // init names
  1439. m_types[GM_NULL].m_name = AllocPermanantStringObject("null");
  1440. m_types[GM_INT].m_name = AllocPermanantStringObject("int");
  1441. m_types[GM_FLOAT].m_name = AllocPermanantStringObject("float");
  1442. m_types[GM_STRING].m_name = AllocPermanantStringObject("string");
  1443. m_types[GM_TABLE].m_name = AllocPermanantStringObject("table");
  1444. m_types[GM_FUNCTION].m_name = AllocPermanantStringObject("function");
  1445. // init basic operators
  1446. gmInitBasicType(GM_NULL, m_types[GM_NULL].m_nativeOperators);
  1447. gmInitBasicType(GM_INT, m_types[GM_INT].m_nativeOperators);
  1448. gmInitBasicType(GM_FLOAT, m_types[GM_FLOAT].m_nativeOperators);
  1449. gmInitBasicType(GM_STRING, m_types[GM_STRING].m_nativeOperators);
  1450. gmInitBasicType(GM_TABLE, m_types[GM_TABLE].m_nativeOperators);
  1451. gmInitBasicType(GM_FUNCTION, m_types[GM_FUNCTION].m_nativeOperators);
  1452. }
  1453. void gmMachine::Sys_RemoveBlocks(gmThread * a_thread)
  1454. {
  1455. gmBlock * block = a_thread->Sys_GetBlocks(), * next;
  1456. while(block)
  1457. {
  1458. next = block->m_nextBlock;
  1459. gmBlockList * list = block->m_list;
  1460. block->Remove();
  1461. if(list->m_blocks.IsEmpty())
  1462. {
  1463. list = (gmBlockList *) m_blocks.Remove(list);
  1464. Sys_Free(list);
  1465. }
  1466. Sys_Free(block);
  1467. block = next;
  1468. }
  1469. a_thread->Sys_SetBlocks(NULL);
  1470. }
  1471. void gmMachine::Sys_RemoveSignals(gmThread * a_thread)
  1472. {
  1473. gmSignal * signal = a_thread->Sys_GetSignals(), * next;
  1474. while(signal)
  1475. {
  1476. next = signal->m_nextSignal;
  1477. Sys_Free(signal);
  1478. signal = next;
  1479. }
  1480. a_thread->Sys_SetSignals(NULL);
  1481. }
  1482. gmuint32 gmMachine::AddSourceCode(const char * a_source, const char * a_filename)
  1483. {
  1484. gmuint32 id = 0;
  1485. if(a_filename == NULL) { a_filename = "unknown"; }
  1486. if(m_debug)
  1487. {
  1488. // calculate the id.
  1489. id = gmCrc32String(a_source);
  1490. // see if we already have the source.
  1491. gmSourceEntry * entry = m_source.GetFirst();
  1492. while(m_source.IsValid(entry))
  1493. {
  1494. if(entry->m_id == id)
  1495. {
  1496. return id;
  1497. }
  1498. entry = m_source.GetNext(entry);
  1499. }
  1500. // we dont have it, add it
  1501. m_source.InsertFirst( GM_NEW( gmSourceEntry(a_source, a_filename) ) );
  1502. }
  1503. return id;
  1504. }
  1505. bool gmMachine::GetSourceCode(gmuint32 a_id, const char * &a_source, const char * &a_filename)
  1506. {
  1507. if(m_debug)
  1508. {
  1509. gmSourceEntry * entry = m_source.GetFirst();
  1510. while(m_source.IsValid(entry))
  1511. {
  1512. if(entry->m_id == a_id)
  1513. {
  1514. a_source = entry->m_source;
  1515. a_filename = entry->m_filename;
  1516. return true;
  1517. }
  1518. entry = m_source.GetNext(entry);
  1519. }
  1520. }
  1521. return false;
  1522. }
  1523. #if GM_USE_INCGC
  1524. const void * gmMachine::GetInstructionAtBreakPoint(gmuint32 a_sourceId, int a_line)
  1525. {
  1526. return m_gc->GetInstructionAtBreakPoint(a_sourceId, a_line);
  1527. }
  1528. #else //GM_INC_GM
  1529. const void * gmMachine::GetInstructionAtBreakPoint(gmuint32 a_sourceId, int a_line)
  1530. {
  1531. gmObject * object = m_objects;
  1532. while(object)
  1533. {
  1534. if(object->GetType() == GM_FUNCTION)
  1535. {
  1536. gmFunctionObject * function = (gmFunctionObject *) object;
  1537. if(function->GetSourceId() == a_sourceId)
  1538. {
  1539. const void * i = function->GetInstructionAtLine(a_line);
  1540. if(i) return i;
  1541. }
  1542. }
  1543. object = object->m_sysNext;
  1544. }
  1545. return NULL;
  1546. }
  1547. #endif //GM_INC_GM
  1548. bool gmMachine::IsCPPOwnedGMObject(gmObject * a_obj)
  1549. {
  1550. ObjHashNode * foundNode = m_cppOwnedGMObjs.Find(a_obj);
  1551. return (foundNode != NULL);
  1552. }
  1553. void gmMachine::AddCPPOwnedGMObject(gmObject * a_obj)
  1554. {
  1555. if( !a_obj )
  1556. {
  1557. return; // Ignore NULL
  1558. }
  1559. #ifdef GM_DEBUG_BUILD
  1560. // Should not already exist
  1561. ObjHashNode * foundNode = m_cppOwnedGMObjs.Find(a_obj);
  1562. GM_ASSERT( !foundNode );
  1563. #endif //GM_DEBUG_BUILD
  1564. ObjHashNode * newNode = (ObjHashNode *)Sys_Alloc( sizeof(ObjHashNode) );
  1565. newNode->m_obj = a_obj;
  1566. m_cppOwnedGMObjs.Insert(newNode);
  1567. }
  1568. void gmMachine::RemoveCPPOwnedGMObject(gmObject * a_obj)
  1569. {
  1570. if( !a_obj )
  1571. {
  1572. return; // Ignore NULL
  1573. }
  1574. ObjHashNode * foundNode = m_cppOwnedGMObjs.Find(a_obj);
  1575. if( foundNode )
  1576. {
  1577. m_cppOwnedGMObjs.Remove(foundNode);
  1578. Sys_Free(foundNode);
  1579. // Apply write barrier for this logical LHS
  1580. m_gc->WriteBarrier(a_obj);
  1581. }
  1582. }
  1583. gmTableObject * gmMachine::GetTypeTable(gmType a_type)
  1584. {
  1585. if( (a_type >= 0) && (a_type < (int)m_types.Count()) )
  1586. {
  1587. return m_types[a_type].m_variables;
  1588. }
  1589. return NULL;
  1590. }
  1591. gmType gmMachine::GetTypeId(const char * a_typename) const
  1592. {
  1593. for(gmuint id = GM_NULL; id < m_types.Count(); ++id)
  1594. {
  1595. if( strcmp((const char *)(*m_types[id].m_name), a_typename) == 0 )
  1596. {
  1597. return id;
  1598. }
  1599. }
  1600. return GM_INVALID_TYPE;
  1601. }
  1602. //
  1603. //
  1604. // Implementation of gmHooks
  1605. //
  1606. //
  1607. gmHooks::gmHooks(gmMachine * a_machine, const char * a_source, const char * a_filename) :
  1608. m_machine(a_machine),
  1609. m_source(a_source),
  1610. m_filename(a_filename)
  1611. {
  1612. m_gcEnabled = a_machine->IsGCEnabled();
  1613. m_debug = false;
  1614. m_errors = 0;
  1615. m_rootFunction = NULL;
  1616. m_sourceId = 0;
  1617. }
  1618. gmHooks::~gmHooks()
  1619. {
  1620. }
  1621. bool gmHooks::Begin(bool a_debug)
  1622. {
  1623. m_gcEnabled = m_machine->IsGCEnabled();
  1624. m_machine->EnableGC(false);
  1625. // add the source code. if we are debugging
  1626. if(a_debug)
  1627. {
  1628. m_sourceId = m_machine->AddSourceCode(m_source, m_filename);
  1629. }
  1630. m_debug = a_debug;
  1631. return true;
  1632. }
  1633. bool gmHooks::AddFunction(gmFunctionInfo &a_info)
  1634. {
  1635. gmObject * object = GM_MOBJECT(m_machine, a_info.m_id);
  1636. if(object->GetType() == GM_FUNCTION)
  1637. {
  1638. gmFunctionObject * function = (gmFunctionObject *) object;
  1639. if(a_info.m_root) { m_rootFunction = function; }
  1640. return function->Init(m_machine, m_debug, a_info, m_sourceId);
  1641. }
  1642. return false;
  1643. }
  1644. bool gmHooks::End(int a_errors)
  1645. {
  1646. m_machine->EnableGC(m_gcEnabled);
  1647. m_errors = a_errors;
  1648. return true;
  1649. }
  1650. gmptr gmHooks::GetFunctionId()
  1651. {
  1652. return (gmptr) m_machine->AllocFunctionObject(NULL);
  1653. }
  1654. gmptr gmHooks::GetSymbolId(const char * a_symbol)
  1655. {
  1656. return (gmptr) m_machine->AllocPermanantStringObject(a_symbol);
  1657. }
  1658. gmptr gmHooks::GetStringId(const char * a_string)
  1659. {
  1660. return (gmptr) m_machine->AllocStringObject(a_string);
  1661. }