1 /*
2    AngelCode Scripting Library
3    Copyright (c) 2003-2017 Andreas Jonsson
4 
5    This software is provided 'as-is', without any express or implied
6    warranty. In no event will the authors be held liable for any
7    damages arising from the use of this software.
8 
9    Permission is granted to anyone to use this software for any
10    purpose, including commercial applications, and to alter it and
11    redistribute it freely, subject to the following restrictions:
12 
13    1. The origin of this software must not be misrepresented; you
14       must not claim that you wrote the original software. If you use
15       this software in a product, an acknowledgment in the product
16       documentation would be appreciated but is not required.
17 
18    2. Altered source versions must be plainly marked as such, and
19       must not be misrepresented as being the original software.
20 
21    3. This notice may not be removed or altered from any source
22       distribution.
23 
24    The original version of this library can be located at:
25    http://www.angelcode.com/angelscript/
26 
27    Andreas Jonsson
28    andreas@angelcode.com
29 */
30 
31 
32 //
33 // as_typeinfo.cpp
34 //
35 
36 
37 #include "as_config.h"
38 #include "as_typeinfo.h"
39 #include "as_scriptengine.h"
40 
41 BEGIN_AS_NAMESPACE
42 
asCTypeInfo()43 asCTypeInfo::asCTypeInfo()
44 {
45 	externalRefCount.set(0);
46 	internalRefCount.set(1); // start with one internal ref-count
47 	engine = 0;
48 	module = 0;
49 	size = 0;
50 	flags = 0;
51 	typeId = -1; // start as -1 to signal that it hasn't been defined
52 
53 	scriptSectionIdx = -1;
54 	declaredAt = 0;
55 
56 	accessMask = 0xFFFFFFFF;
57 	nameSpace = 0;
58 }
59 
asCTypeInfo(asCScriptEngine * in_engine)60 asCTypeInfo::asCTypeInfo(asCScriptEngine *in_engine)
61 {
62 	externalRefCount.set(0);
63 	internalRefCount.set(1); // start with one internal ref count
64 	engine = in_engine;
65 	module = 0;
66 	size = 0;
67 	flags = 0;
68 	typeId = -1; // start as -1 to signal that it hasn't been defined
69 
70 	scriptSectionIdx = -1;
71 	declaredAt = 0;
72 
73 	accessMask = 0xFFFFFFFF;
74 	nameSpace = engine->nameSpaces[0];
75 }
76 
~asCTypeInfo()77 asCTypeInfo::~asCTypeInfo()
78 {
79 }
80 
81 // interface
AddRef() const82 int asCTypeInfo::AddRef() const
83 {
84 	return externalRefCount.atomicInc();
85 }
86 
87 // interface
Release() const88 int asCTypeInfo::Release() const
89 {
90 	int r = externalRefCount.atomicDec();
91 
92 	if (r == 0)
93 	{
94 		// There are no more external references, if there are also no
95 		// internal references then it is time to delete the object type
96 		if (internalRefCount.get() == 0)
97 		{
98 			// If the engine is no longer set, then it has already been
99 			// released and we must take care of the deletion ourselves
100 			asDELETE(const_cast<asCTypeInfo*>(this), asCTypeInfo);
101 		}
102 	}
103 
104 	return r;
105 }
106 
AddRefInternal()107 int asCTypeInfo::AddRefInternal()
108 {
109 	return internalRefCount.atomicInc();
110 }
111 
ReleaseInternal()112 int asCTypeInfo::ReleaseInternal()
113 {
114 	int r = internalRefCount.atomicDec();
115 
116 	if (r == 0)
117 	{
118 		// There are no more internal references, if there are also no
119 		// external references then it is time to delete the object type
120 		if (externalRefCount.get() == 0)
121 		{
122 			// If the engine is no longer set, then it has already been
123 			// released and we must take care of the deletion ourselves
124 			asDELETE(const_cast<asCTypeInfo*>(this), asCTypeInfo);
125 		}
126 	}
127 
128 	return r;
129 }
130 
131 // interface
GetModule() const132 asIScriptModule *asCTypeInfo::GetModule() const
133 {
134 	return module;
135 }
136 
SetUserData(void * data,asPWORD type)137 void *asCTypeInfo::SetUserData(void *data, asPWORD type)
138 {
139 	// As a thread might add a new new user data at the same time as another
140 	// it is necessary to protect both read and write access to the userData member
141 	ACQUIREEXCLUSIVE(engine->engineRWLock);
142 
143 	// It is not intended to store a lot of different types of userdata,
144 	// so a more complex structure like a associative map would just have
145 	// more overhead than a simple array.
146 	for (asUINT n = 0; n < userData.GetLength(); n += 2)
147 	{
148 		if (userData[n] == type)
149 		{
150 			void *oldData = reinterpret_cast<void*>(userData[n + 1]);
151 			userData[n + 1] = reinterpret_cast<asPWORD>(data);
152 
153 			RELEASEEXCLUSIVE(engine->engineRWLock);
154 
155 			return oldData;
156 		}
157 	}
158 
159 	userData.PushLast(type);
160 	userData.PushLast(reinterpret_cast<asPWORD>(data));
161 
162 	RELEASEEXCLUSIVE(engine->engineRWLock);
163 
164 	return 0;
165 }
166 
GetUserData(asPWORD type) const167 void *asCTypeInfo::GetUserData(asPWORD type) const
168 {
169 	// There may be multiple threads reading, but when
170 	// setting the user data nobody must be reading.
171 	ACQUIRESHARED(engine->engineRWLock);
172 
173 	for (asUINT n = 0; n < userData.GetLength(); n += 2)
174 	{
175 		if (userData[n] == type)
176 		{
177 			RELEASESHARED(engine->engineRWLock);
178 			return reinterpret_cast<void*>(userData[n + 1]);
179 		}
180 	}
181 
182 	RELEASESHARED(engine->engineRWLock);
183 
184 	return 0;
185 }
186 
187 // interface
GetName() const188 const char *asCTypeInfo::GetName() const
189 {
190 	return name.AddressOf();
191 }
192 
193 // interface
GetNamespace() const194 const char *asCTypeInfo::GetNamespace() const
195 {
196 	if( nameSpace )
197 		return nameSpace->name.AddressOf();
198 
199 	return 0;
200 }
201 
202 // interface
GetFlags() const203 asDWORD asCTypeInfo::GetFlags() const
204 {
205 	return flags;
206 }
207 
208 // interface
GetSize() const209 asUINT asCTypeInfo::GetSize() const
210 {
211 	return size;
212 }
213 
214 // interface
GetTypeId() const215 int asCTypeInfo::GetTypeId() const
216 {
217 	if (typeId == -1)
218 	{
219 		// We need a non const pointer to create the asCDataType object.
220 		// We're not breaking anything here because this function is not
221 		// modifying the object, so this const cast is safe.
222 		asCTypeInfo *ot = const_cast<asCTypeInfo*>(this);
223 
224 		// The engine will define the typeId for this object type
225 		engine->GetTypeIdFromDataType(asCDataType::CreateType(ot, false));
226 	}
227 
228 	return typeId;
229 }
230 
231 // interface
GetEngine() const232 asIScriptEngine *asCTypeInfo::GetEngine() const
233 {
234 	return engine;
235 }
236 
237 // interface
GetConfigGroup() const238 const char *asCTypeInfo::GetConfigGroup() const
239 {
240 	asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(this);
241 	if (group == 0)
242 		return 0;
243 
244 	return group->groupName.AddressOf();
245 }
246 
247 // interface
GetAccessMask() const248 asDWORD asCTypeInfo::GetAccessMask() const
249 {
250 	return accessMask;
251 }
252 
253 // interface
GetProperty(asUINT index,const char ** out_name,int * out_typeId,bool * out_isPrivate,bool * out_isProtected,int * out_offset,bool * out_isReference,asDWORD * out_accessMask,int * out_compositeOffset,bool * out_isCompositeIndirect) const254 int asCTypeInfo::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const
255 {
256 	UNUSED_VAR(index);
257 	if (out_name) *out_name = 0;
258 	if (out_typeId) *out_typeId = 0;
259 	if (out_isPrivate) *out_isPrivate = false;
260 	if (out_isProtected) *out_isProtected = false;
261 	if (out_offset) *out_offset = 0;
262 	if (out_isReference) *out_isReference = false;
263 	if (out_accessMask) *out_accessMask = 0;
264 	if (out_compositeOffset) *out_compositeOffset = 0;
265 	if (out_isCompositeIndirect) *out_isCompositeIndirect = false;
266 	return -1;
267 }
268 
269 // internal
CastToObjectType(asCTypeInfo * ti)270 asCObjectType *CastToObjectType(asCTypeInfo *ti)
271 {
272 	// Allow call on null pointer
273 	if (ti == 0) return 0;
274 
275 	// TODO: type: Should List pattern have its own type class?
276 	if ((ti->flags & (asOBJ_VALUE | asOBJ_REF | asOBJ_LIST_PATTERN)) && !(ti->flags & asOBJ_FUNCDEF))
277 		return reinterpret_cast<asCObjectType*>(ti);
278 
279 	return 0;
280 }
281 
282 // internal
CastToEnumType(asCTypeInfo * ti)283 asCEnumType *CastToEnumType(asCTypeInfo *ti)
284 {
285 	// Allow call on null pointer
286 	if (ti == 0) return 0;
287 
288 	if (ti->flags & (asOBJ_ENUM))
289 		return reinterpret_cast<asCEnumType*>(ti);
290 
291 	return 0;
292 }
293 
294 // internal
CastToTypedefType(asCTypeInfo * ti)295 asCTypedefType *CastToTypedefType(asCTypeInfo *ti)
296 {
297 	// Allow call on null pointer
298 	if (ti == 0) return 0;
299 
300 	if (ti->flags & (asOBJ_TYPEDEF))
301 		return reinterpret_cast<asCTypedefType*>(ti);
302 
303 	return 0;
304 }
305 
306 // internal
CastToFuncdefType(asCTypeInfo * ti)307 asCFuncdefType *CastToFuncdefType(asCTypeInfo *ti)
308 {
309 	// Allow call on null pointer
310 	if (ti == 0) return 0;
311 
312 	if (ti->flags & (asOBJ_FUNCDEF))
313 		return reinterpret_cast<asCFuncdefType*>(ti);
314 
315 	return 0;
316 }
317 
318 // internal
CleanUserData()319 void asCTypeInfo::CleanUserData()
320 {
321 	asASSERT(engine);
322 	for (asUINT n = 0; n < userData.GetLength(); n += 2)
323 	{
324 		if (userData[n + 1])
325 		{
326 			for (asUINT c = 0; c < engine->cleanTypeInfoFuncs.GetLength(); c++)
327 				if (engine->cleanTypeInfoFuncs[c].type == userData[n])
328 					engine->cleanTypeInfoFuncs[c].cleanFunc(this);
329 		}
330 	}
331 	userData.SetLength(0);
332 }
333 
334 // internal
IsShared() const335 bool asCTypeInfo::IsShared() const
336 {
337 	// Types that can be declared by scripts need to have the explicit flag asOBJ_SHARED
338 	if (flags & (asOBJ_SCRIPT_OBJECT | asOBJ_ENUM)) return flags & asOBJ_SHARED ? true : false;
339 
340 	// Otherwise we assume the type to be shared
341 	return true;
342 }
343 
344 ////////////////////////////////////////////////////////////////////////////////////////
345 
~asCEnumType()346 asCEnumType::~asCEnumType()
347 {
348 	asUINT n;
349 	for (n = 0; n < enumValues.GetLength(); n++)
350 	{
351 		if (enumValues[n])
352 			asDELETE(enumValues[n], asSEnumValue);
353 	}
354 	enumValues.SetLength(0);
355 }
356 
357 // interface
GetEnumValueCount() const358 asUINT asCEnumType::GetEnumValueCount() const
359 {
360 	return enumValues.GetLength();
361 }
362 
363 // interface
GetEnumValueByIndex(asUINT index,int * outValue) const364 const char *asCEnumType::GetEnumValueByIndex(asUINT index, int *outValue) const
365 {
366 	if (outValue)
367 		*outValue = 0;
368 
369 	if (index >= enumValues.GetLength())
370 		return 0;
371 
372 	if (outValue)
373 		*outValue = enumValues[index]->value;
374 
375 	return enumValues[index]->name.AddressOf();
376 }
377 
378 //////////////////////////////////////////////////////////////////////////////////////////
379 
~asCTypedefType()380 asCTypedefType::~asCTypedefType()
381 {
382 	DestroyInternal();
383 }
384 
DestroyInternal()385 void asCTypedefType::DestroyInternal()
386 {
387 	if (engine == 0) return;
388 
389 	// Release the object types held by the alias
390 	if (aliasForType.GetTypeInfo())
391 			aliasForType.GetTypeInfo()->ReleaseInternal();
392 
393 	aliasForType = asCDataType::CreatePrimitive(ttVoid, false);
394 
395 	CleanUserData();
396 
397 	// Remove the type from the engine
398 	if (typeId != -1)
399 		engine->RemoveFromTypeIdMap(this);
400 
401 	// Clear the engine pointer to mark the object type as invalid
402 	engine = 0;
403 }
404 
405 // interface
GetTypedefTypeId() const406 int asCTypedefType::GetTypedefTypeId() const
407 {
408 	return engine->GetTypeIdFromDataType(aliasForType);
409 }
410 
411 //////////////////////////////////////////////////////////////////////////////////////////
412 
asCFuncdefType(asCScriptEngine * en,asCScriptFunction * func)413 asCFuncdefType::asCFuncdefType(asCScriptEngine *en, asCScriptFunction *func) : asCTypeInfo(en)
414 {
415 	asASSERT(func->funcType == asFUNC_FUNCDEF);
416 	asASSERT(func->funcdefType == 0);
417 
418 	// A function pointer is special kind of reference type
419 	flags       = asOBJ_REF | asOBJ_FUNCDEF | (func->IsShared() ? asOBJ_SHARED : 0);
420 	name        = func->name;
421 	nameSpace   = func->nameSpace;
422 	module      = func->module;
423 	accessMask  = func->accessMask;
424 	funcdef     = func; // reference already counted by the asCScriptFunction constructor
425 	parentClass = 0;
426 
427 	func->funcdefType = this;
428 }
429 
~asCFuncdefType()430 asCFuncdefType::~asCFuncdefType()
431 {
432 	DestroyInternal();
433 }
434 
DestroyInternal()435 void asCFuncdefType::DestroyInternal()
436 {
437 	if (engine == 0) return;
438 
439 	// Release the funcdef
440 	if( funcdef )
441 		funcdef->ReleaseInternal();
442 	funcdef = 0;
443 
444 	// Detach from parent class
445 	if (parentClass)
446 	{
447 		parentClass->childFuncDefs.RemoveValue(this);
448 		parentClass = 0;
449 	}
450 
451 	CleanUserData();
452 
453 	// Remove the type from the engine
454 	if (typeId != -1)
455 		engine->RemoveFromTypeIdMap(this);
456 
457 	// Clear the engine pointer to mark the object type as invalid
458 	engine = 0;
459 }
460 
461 // interface
GetFuncdefSignature() const462 asIScriptFunction *asCFuncdefType::GetFuncdefSignature() const
463 {
464 	return funcdef;
465 }
466 
467 // interface
GetParentType() const468 asITypeInfo *asCFuncdefType::GetParentType() const
469 {
470 	return parentClass;
471 }
472 
473 END_AS_NAMESPACE
474 
475 
476