1 /*
2 see copyright notice in squirrel.h
3 */
4 #include "sqpcheader.h"
5 #include "sqopcodes.h"
6 #include "sqvm.h"
7 #include "sqfuncproto.h"
8 #include "sqclosure.h"
9 #include "sqstring.h"
10 #include "sqtable.h"
11 #include "sqarray.h"
12 #include "squserdata.h"
13 #include "sqclass.h"
14
15 SQObjectPtr _null_;
16 SQObjectPtr _true_( true );
17 SQObjectPtr _false_( false );
18 SQObjectPtr _one_( 1 );
19 SQObjectPtr _minusone_( -1 );
20
SQSharedState()21 SQSharedState::SQSharedState() {
22 _compilererrorhandler = NULL;
23 _printfunc = NULL;
24 _debuginfo = false;
25 }
26
27 #define newsysstring(s) { \
28 _systemstrings->push_back(SQString::Create(this,s)); \
29 }
30
31 #define newmetamethod(s) { \
32 _metamethods->push_back(SQString::Create(this,s)); \
33 _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
34 }
35
CompileTypemask(SQIntVec & res,const SQChar * typemask)36 bool CompileTypemask( SQIntVec &res, const SQChar *typemask ) {
37 SQInteger i = 0;
38
39 SQInteger mask = 0;
40 while ( typemask[i] != 0 ) {
41
42 switch ( typemask[i] ) {
43 case 'o': mask |= _RT_NULL; break;
44 case 'i': mask |= _RT_INTEGER; break;
45 case 'f': mask |= _RT_FLOAT; break;
46 case 'n': mask |= ( _RT_FLOAT | _RT_INTEGER ); break;
47 case 's': mask |= _RT_STRING; break;
48 case 't': mask |= _RT_TABLE; break;
49 case 'a': mask |= _RT_ARRAY; break;
50 case 'u': mask |= _RT_USERDATA; break;
51 case 'c': mask |= ( _RT_CLOSURE | _RT_NATIVECLOSURE ); break;
52 case 'b': mask |= _RT_BOOL; break;
53 case 'g': mask |= _RT_GENERATOR; break;
54 case 'p': mask |= _RT_USERPOINTER; break;
55 case 'v': mask |= _RT_THREAD; break;
56 case 'x': mask |= _RT_INSTANCE; break;
57 case 'y': mask |= _RT_CLASS; break;
58 case 'r': mask |= _RT_WEAKREF; break;
59 case '.': mask = -1; res.push_back( mask ); i++; mask = 0; continue;
60 case ' ': i++; continue; //ignores spaces
61 default:
62 return false;
63 }
64 i++;
65 if ( typemask[i] == '|' ) {
66 i++;
67 if ( typemask[i] == 0 )
68 return false;
69 continue;
70 }
71 res.push_back( mask );
72 mask = 0;
73
74 }
75 return true;
76 }
77
CreateDefaultDelegate(SQSharedState * ss,SQRegFunction * funcz)78 SQTable *CreateDefaultDelegate( SQSharedState *ss, SQRegFunction *funcz ) {
79 SQInteger i = 0;
80 SQTable *t = SQTable::Create( ss, 0 );
81 while ( funcz[i].name != 0 ) {
82 SQNativeClosure *nc = SQNativeClosure::Create( ss, funcz[i].f );
83 nc->_nparamscheck = funcz[i].nparamscheck;
84 nc->_name = SQString::Create( ss, funcz[i].name );
85 if ( funcz[i].typemask && !CompileTypemask( nc->_typecheck, funcz[i].typemask ) )
86 return NULL;
87 t->NewSlot( SQString::Create( ss, funcz[i].name ), nc );
88 i++;
89 }
90 return t;
91 }
92
Init()93 void SQSharedState::Init() {
94 _scratchpad = NULL;
95 _scratchpadsize = 0;
96 #ifndef NO_GARBAGE_COLLECTOR
97 _gc_chain = NULL;
98 #endif
99 sq_new( _stringtable, StringTable );
100 sq_new( _metamethods, SQObjectPtrVec );
101 sq_new( _systemstrings, SQObjectPtrVec );
102 sq_new( _types, SQObjectPtrVec );
103 _metamethodsmap = SQTable::Create( this, MT_LAST - 1 );
104 //adding type strings to avoid memory trashing
105 //types names
106 newsysstring( _SC( "null" ) );
107 newsysstring( _SC( "table" ) );
108 newsysstring( _SC( "array" ) );
109 newsysstring( _SC( "closure" ) );
110 newsysstring( _SC( "string" ) );
111 newsysstring( _SC( "userdata" ) );
112 newsysstring( _SC( "integer" ) );
113 newsysstring( _SC( "float" ) );
114 newsysstring( _SC( "userpointer" ) );
115 newsysstring( _SC( "function" ) );
116 newsysstring( _SC( "generator" ) );
117 newsysstring( _SC( "thread" ) );
118 newsysstring( _SC( "class" ) );
119 newsysstring( _SC( "instance" ) );
120 newsysstring( _SC( "bool" ) );
121 //meta methods
122 newmetamethod( MM_ADD );
123 newmetamethod( MM_SUB );
124 newmetamethod( MM_MUL );
125 newmetamethod( MM_DIV );
126 newmetamethod( MM_UNM );
127 newmetamethod( MM_MODULO );
128 newmetamethod( MM_SET );
129 newmetamethod( MM_GET );
130 newmetamethod( MM_TYPEOF );
131 newmetamethod( MM_NEXTI );
132 newmetamethod( MM_CMP );
133 newmetamethod( MM_CALL );
134 newmetamethod( MM_CLONED );
135 newmetamethod( MM_NEWSLOT );
136 newmetamethod( MM_DELSLOT );
137 newmetamethod( MM_TOSTRING );
138
139 _constructoridx = SQString::Create( this, _SC( "constructor" ) );
140 _refs_table = SQTable::Create( this, 0 );
141 _registry = SQTable::Create( this, 0 );
142 _table_default_delegate = CreateDefaultDelegate( this, _table_default_delegate_funcz );
143 _array_default_delegate = CreateDefaultDelegate( this, _array_default_delegate_funcz );
144 _string_default_delegate = CreateDefaultDelegate( this, _string_default_delegate_funcz );
145 _number_default_delegate = CreateDefaultDelegate( this, _number_default_delegate_funcz );
146 _closure_default_delegate = CreateDefaultDelegate( this, _closure_default_delegate_funcz );
147 _generator_default_delegate = CreateDefaultDelegate( this, _generator_default_delegate_funcz );
148 _thread_default_delegate = CreateDefaultDelegate( this, _thread_default_delegate_funcz );
149 _class_default_delegate = CreateDefaultDelegate( this, _class_default_delegate_funcz );
150 _instance_default_delegate = CreateDefaultDelegate( this, _instance_default_delegate_funcz );
151 _weakref_default_delegate = CreateDefaultDelegate( this, _weakref_default_delegate_funcz );
152
153 }
154
~SQSharedState()155 SQSharedState::~SQSharedState() {
156 _constructoridx = _null_;
157 _table( _refs_table )->Finalize();
158 _table( _registry )->Finalize();
159 _table( _metamethodsmap )->Finalize();
160 _refs_table = _null_;
161 _registry = _null_;
162 _metamethodsmap = _null_;
163 while ( !_systemstrings->empty() ) {
164 _systemstrings->back() = _null_;
165 _systemstrings->pop_back();
166 }
167 _thread( _root_vm )->Finalize();
168 _root_vm = _null_;
169 _table_default_delegate = _null_;
170 _array_default_delegate = _null_;
171 _string_default_delegate = _null_;
172 _number_default_delegate = _null_;
173 _closure_default_delegate = _null_;
174 _generator_default_delegate = _null_;
175 _thread_default_delegate = _null_;
176 _class_default_delegate = _null_;
177 _instance_default_delegate = _null_;
178 _weakref_default_delegate = _null_;
179
180 #ifndef NO_GARBAGE_COLLECTOR
181
182
183 SQCollectable *t = _gc_chain;
184 SQCollectable *nx = NULL;
185 while ( t ) {
186 t->_uiRef++;
187 t->Finalize();
188 nx = t->_next;
189 if ( --t->_uiRef == 0 )
190 t->Release();
191 t = nx;
192 }
193 assert( _gc_chain == NULL ); //just to proove a theory
194 while ( _gc_chain ) {
195 _gc_chain->_uiRef++;
196 _gc_chain->Release();
197 }
198 #endif
199 sq_delete( _types, SQObjectPtrVec );
200 sq_delete( _systemstrings, SQObjectPtrVec );
201 sq_delete( _metamethods, SQObjectPtrVec );
202 sq_delete( _stringtable, StringTable );
203 if ( _scratchpad )SQ_FREE( _scratchpad, _scratchpadsize );
204 }
205
206
GetMetaMethodIdxByName(const SQObjectPtr & name)207 SQInteger SQSharedState::GetMetaMethodIdxByName( const SQObjectPtr &name ) {
208 if ( squirrel_type( name ) != OT_STRING )
209 return -1;
210 SQObjectPtr ret;
211 if ( _table( _metamethodsmap )->Get( name, ret ) ) {
212 return _integer( ret );
213 }
214 return -1;
215 }
216
217 #ifndef NO_GARBAGE_COLLECTOR
218
MarkObject(SQObjectPtr & o,SQCollectable ** chain)219 void SQSharedState::MarkObject( SQObjectPtr &o, SQCollectable **chain ) {
220 switch ( squirrel_type( o ) ) {
221 case OT_TABLE: _table( o )->Mark( chain );break;
222 case OT_ARRAY: _array( o )->Mark( chain );break;
223 case OT_USERDATA: _userdata( o )->Mark( chain );break;
224 case OT_CLOSURE: _closure( o )->Mark( chain );break;
225 case OT_NATIVECLOSURE: _nativeclosure( o )->Mark( chain );break;
226 case OT_GENERATOR: _generator( o )->Mark( chain );break;
227 case OT_THREAD: _thread( o )->Mark( chain );break;
228 case OT_CLASS: _class( o )->Mark( chain );break;
229 case OT_INSTANCE: _instance( o )->Mark( chain );break;
230 }
231 }
232
233
CollectGarbage(SQVM * vm)234 SQInteger SQSharedState::CollectGarbage( SQVM *vm ) {
235 SQInteger n = 0;
236 SQCollectable *tchain = NULL;
237 SQVM *vms = _thread( _root_vm );
238
239 vms->Mark( &tchain );
240 SQInteger x = _table( _thread( _root_vm )->_roottable )->CountUsed();
241 MarkObject( _refs_table, &tchain );
242 MarkObject( _registry, &tchain );
243 MarkObject( _metamethodsmap, &tchain );
244 MarkObject( _table_default_delegate, &tchain );
245 MarkObject( _array_default_delegate, &tchain );
246 MarkObject( _string_default_delegate, &tchain );
247 MarkObject( _number_default_delegate, &tchain );
248 MarkObject( _generator_default_delegate, &tchain );
249 MarkObject( _thread_default_delegate, &tchain );
250 MarkObject( _closure_default_delegate, &tchain );
251 MarkObject( _class_default_delegate, &tchain );
252 MarkObject( _instance_default_delegate, &tchain );
253 MarkObject( _weakref_default_delegate, &tchain );
254
255 SQCollectable *t = _gc_chain;
256 SQCollectable *nx = NULL;
257 while ( t ) {
258 t->_uiRef++;
259 t->Finalize();
260 nx = t->_next;
261 if ( --t->_uiRef == 0 )
262 t->Release();
263 t = nx;
264 n++;
265 }
266
267 t = tchain;
268 while ( t ) {
269 t->UnMark();
270 t = t->_next;
271 }
272 _gc_chain = tchain;
273 SQInteger z = _table( _thread( _root_vm )->_roottable )->CountUsed();
274 assert( z == x );
275 return n;
276 }
277 #endif
278
279 #ifndef NO_GARBAGE_COLLECTOR
AddToChain(SQCollectable ** chain,SQCollectable * c)280 void SQCollectable::AddToChain( SQCollectable **chain, SQCollectable *c ) {
281 c->_prev = NULL;
282 c->_next = *chain;
283 if ( *chain ) ( *chain )->_prev = c;
284 *chain = c;
285 }
286
RemoveFromChain(SQCollectable ** chain,SQCollectable * c)287 void SQCollectable::RemoveFromChain( SQCollectable **chain, SQCollectable *c ) {
288 if ( c->_prev ) c->_prev->_next = c->_next;
289 else *chain = c->_next;
290 if ( c->_next )
291 c->_next->_prev = c->_prev;
292 c->_next = NULL;
293 c->_prev = NULL;
294 }
295 #endif
296
GetScratchPad(SQInteger size)297 SQChar* SQSharedState::GetScratchPad( SQInteger size ) {
298 SQInteger newsize;
299 if ( size > 0 ) {
300 if ( _scratchpadsize < size ) {
301 newsize = size + ( size >> 1 );
302 _scratchpad = ( SQChar * )SQ_REALLOC( _scratchpad, _scratchpadsize, newsize );
303 _scratchpadsize = newsize;
304
305 } else if ( _scratchpadsize >= ( size << 5 ) ) {
306 newsize = _scratchpadsize >> 1;
307 _scratchpad = ( SQChar * )SQ_REALLOC( _scratchpad, _scratchpadsize, newsize );
308 _scratchpadsize = newsize;
309 }
310 }
311 return _scratchpad;
312 }
313
314 //////////////////////////////////////////////////////////////////////////
315 //StringTable
316 /*
317 * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
318 * http://www.lua.org/copyright.html#4
319 * http://www.lua.org/source/4.0.1/src_lstring.c.html
320 */
321
Next(const SQObjectPtr & refpos,SQObjectPtr & outkey,SQObjectPtr & outval)322 SQInteger SQString::Next( const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval ) {
323 SQInteger idx = ( SQInteger )TranslateIndex( refpos );
324 while ( idx < _len ) {
325 outkey = ( SQInteger )idx;
326 outval = SQInteger( _val[idx] );
327 //return idx for the next iteration
328 return ++idx;
329 }
330 //nothing to iterate anymore
331 return -1;
332 }
333
StringTable()334 StringTable::StringTable() {
335 AllocNodes( 4 );
336 _slotused = 0;
337 }
338
~StringTable()339 StringTable::~StringTable() {
340 SQ_FREE( _strings, sizeof( SQString* )*_numofslots );
341 _strings = NULL;
342 }
343
AllocNodes(SQInteger size)344 void StringTable::AllocNodes( SQInteger size ) {
345 _numofslots = size;
346 //_slotused=0;
347 _strings = ( SQString** )SQ_MALLOC( sizeof( SQString* ) * _numofslots );
348 memset( _strings, 0, sizeof( SQString* )*_numofslots );
349 }
350
Add(const SQChar * news,SQInteger len)351 SQString *StringTable::Add( const SQChar *news, SQInteger len ) {
352 if ( len < 0 )
353 len = scstrlen( news );
354 SQHash h = ::_hashstr( news, len ) & ( _numofslots - 1 );
355 SQString *s;
356 for ( s = _strings[h]; s; s = s->_next ) {
357 if ( s->_len == len && ( !memcmp( news, s->_val, rsl( len ) ) ) )
358 return s; //found
359 }
360
361 SQString *t = ( SQString * )SQ_MALLOC( rsl( len ) + sizeof( SQString ) );
362 new ( t ) SQString;
363 memcpy( t->_val, news, rsl( len ) );
364 t->_val[len] = _SC( '\0' );
365 t->_len = len;
366 t->_hash = ::_hashstr( news, len );
367 t->_next = _strings[h];
368 _strings[h] = t;
369 _slotused++;
370 if ( _slotused > _numofslots ) /* too crowded? */
371 Resize( _numofslots*2 );
372 return t;
373 }
374
Resize(SQInteger size)375 void StringTable::Resize( SQInteger size ) {
376 SQInteger oldsize = _numofslots;
377 SQString **oldtable = _strings;
378 AllocNodes( size );
379 for ( SQInteger i = 0; i < oldsize; i++ ) {
380 SQString *p = oldtable[i];
381 while ( p ) {
382 SQString *next = p->_next;
383 SQHash h = p->_hash & ( _numofslots - 1 );
384 p->_next = _strings[h];
385 _strings[h] = p;
386 p = next;
387 }
388 }
389 SQ_FREE( oldtable, oldsize*sizeof( SQString* ) );
390 }
391
Remove(SQString * bs)392 void StringTable::Remove( SQString *bs ) {
393 SQString *s;
394 SQString *prev = NULL;
395 SQHash h = bs->_hash & ( _numofslots - 1 );
396
397 for ( s = _strings[h]; s; ) {
398 if ( s == bs ) {
399 if ( prev )
400 prev->_next = s->_next;
401 else
402 _strings[h] = s->_next;
403 _slotused--;
404 SQInteger slen = s->_len;
405 s->~SQString();
406 SQ_FREE( s, sizeof( SQString ) + rsl( slen ) );
407 return;
408 }
409 prev = s;
410 s = s->_next;
411 }
412 assert( 0 );//if this fail something is wrong
413 }
414