// internal void asCScriptFunction::JITCompile() { if( funcType != asFUNC_SCRIPT ) return; asASSERT( scriptData ); asIJITCompiler *jit = engine->GetJITCompiler(); if( !jit ) return; // Release the previous function, if any if( scriptData->jitFunction ) { engine->jitCompiler->ReleaseJITFunction(scriptData->jitFunction); scriptData->jitFunction = 0; } // Compile for native system int r = jit->CompileFunction(this, &scriptData->jitFunction); if( r < 0 ) { asASSERT( scriptData->jitFunction == 0 ); } }
void asCConfigGroup::ValidateNoUsage(asCScriptEngine *engine, asCObjectType *type) { for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) { asCScriptFunction *func = engine->scriptFunctions[n]; if( func == 0 ) continue; // Ignore factory, list factory, and members if( func->name == "_beh_2_" || func->name == "_beh_3_" || func->objectType == type ) continue; asASSERT( func->returnType.GetObjectType() != type ); for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ ) { asASSERT(func->parameterTypes[p].GetObjectType() != type); } } // TODO: Check also usage of the type in global variables // TODO: Check also usage of the type in local variables in script functions // TODO: Check also usage of the type as members of classes // TODO: Check also usage of the type as sub types in other types }
asCScriptObject::~asCScriptObject() { if( weakRefFlag ) { weakRefFlag->Release(); weakRefFlag = 0; } // The engine pointer should be available from the objectType asCScriptEngine *engine = objType->engine; // Destroy all properties // In most cases the members are initialized in the order they have been declared, // so it's safer to uninitialize them from last to first. The order may be different // depending on the use of inheritance and or initialization in the declaration. // TODO: Should the order of initialization be stored by the compiler so that the // reverse order can be guaranteed during the destruction? for( int n = (int)objType->properties.GetLength()-1; n >= 0; n-- ) { asCObjectProperty *prop = objType->properties[n]; if( prop->type.IsObject() ) { // Destroy the object asCObjectType *propType = prop->type.GetObjectType(); if( prop->type.IsReference() || propType->flags & asOBJ_REF ) { void **ptr = (void**)(((char*)this) + prop->byteOffset); if( *ptr ) { FreeObject(*ptr, propType, engine); *(asDWORD*)ptr = 0; } } else { // The object is allocated inline. As only POD objects may be allocated inline // it is not a problem to call the destructor even if the object may never have // been initialized, e.g. if an exception interrupted the constructor. asASSERT( propType->flags & asOBJ_POD ); void *ptr = (void**)(((char*)this) + prop->byteOffset); if( propType->beh.destruct ) engine->CallObjectMethod(ptr, propType->beh.destruct); } } } objType->Release(); objType = 0; // Something is really wrong if the refCount is not 0 by now asASSERT( refCount.get() == 0 ); }
// This function should prepare system functions so that it will be faster to call them int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine * /*engine*/) { asASSERT(internal->callConv == ICC_GENERIC_METHOD || internal->callConv == ICC_GENERIC_FUNC); // Calculate the size needed for the parameters internal->paramSize = func->GetSpaceNeededForArguments(); // Prepare the clean up instructions for the function arguments internal->cleanArgs.SetLength(0); int offset = 0; for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) { asCDataType &dt = func->parameterTypes[n]; if( dt.IsObject() && !dt.IsReference() ) { asSTypeBehaviour *beh = &dt.GetObjectType()->beh; if( dt.GetObjectType()->flags & asOBJ_REF ) { asASSERT( (dt.GetObjectType()->flags & asOBJ_NOCOUNT) || beh->release ); if( beh->release ) { asSSystemFunctionInterface::SClean clean; clean.op = 0; // call release clean.ot = dt.GetObjectType(); clean.off = short(offset); internal->cleanArgs.PushLast(clean); } } else { asSSystemFunctionInterface::SClean clean; clean.op = 1; // call free clean.ot = dt.GetObjectType(); clean.off = short(offset); // Call the destructor then free the memory if( beh->destruct ) clean.op = 2; // call destruct, then free internal->cleanArgs.PushLast(clean); } } if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) offset += AS_PTR_SIZE; else offset += dt.GetSizeOnStackDWords(); } return 0; }
eTokenType asCTokenizer::GetToken(const char *source, size_t sourceLength, size_t *tokenLength, asETokenClass *tc) const { asASSERT(source != 0); asASSERT(tokenLength != 0); eTokenType tokenType; size_t tlen; asETokenClass t = ParseToken(source, sourceLength, tlen, tokenType); if( tc ) *tc = t; if( tokenLength ) *tokenLength = tlen; return tokenType; }
// internal void asCScriptFunction::JITCompile() { if( funcType != asFUNC_SCRIPT ) return; asASSERT( scriptData ); asIJITCompiler *jit = engine->GetJITCompiler(); if( !jit ) return; // Make sure the function has been compiled with JitEntry instructions // For functions that has JitEntry this will be a quick test asUINT length; asDWORD *byteCode = GetByteCode(&length); asDWORD *end = byteCode + length; bool foundJitEntry = false; while( byteCode < end ) { // Determine the instruction asEBCInstr op = asEBCInstr(*(asBYTE*)byteCode); if( op == asBC_JitEntry ) { foundJitEntry = true; break; } // Move to next instruction byteCode += asBCTypeSize[asBCInfo[op].type]; } if( !foundJitEntry ) { asCString msg; msg.Format(TXT_NO_JIT_IN_FUNC_s, GetDeclaration()); engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); } // Release the previous function, if any if( scriptData->jitFunction ) { engine->jitCompiler->ReleaseJITFunction(scriptData->jitFunction); scriptData->jitFunction = 0; } // Compile for native system int r = jit->CompileFunction(this, &scriptData->jitFunction); if( r < 0 ) asASSERT( scriptData->jitFunction == 0 ); }
// internal asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate) { asASSERT( flags & asOBJ_SCRIPT_OBJECT ); asASSERT( dt.CanBeInstanciated() ); asASSERT( !IsInterface() ); // Store the properties in the object type descriptor asCObjectProperty *prop = asNEW(asCObjectProperty); if( prop == 0 ) { // Out of memory return 0; } prop->name = name; prop->type = dt; prop->isPrivate = isPrivate; int propSize; if( dt.IsObject() ) { propSize = dt.GetSizeOnStackDWords()*4; if( !dt.IsObjectHandle() ) prop->type.MakeReference(true); } else propSize = dt.GetSizeInMemoryBytes(); // Add extra bytes so that the property will be properly aligned if( propSize == 2 && (size & 1) ) size += 1; if( propSize > 2 && (size & 3) ) size += 4 - (size & 3); prop->byteOffset = size; size += propSize; properties.PushLast(prop); // Make sure the struct holds a reference to the config group where the object is registered asCConfigGroup *group = engine->FindConfigGroupForObjectType(prop->type.GetObjectType()); if( group != 0 ) group->AddRef(); // Add reference to object types asCObjectType *type = prop->type.GetObjectType(); if( type ) type->AddRef(); return prop; }
// internal int asCModule::AddImportedFunction(int id, const char *name, const asCDataType &returnType, asCDataType *params, asETypeModifiers *inOutFlags, int paramCount, int moduleNameStringID) { asASSERT(id >= 0); // Store the function information asCScriptFunction *func = asNEW(asCScriptFunction)(engine, this); func->funcType = asFUNC_IMPORTED; func->name = name; func->id = id; func->returnType = returnType; for( int n = 0; n < paramCount; n++ ) { func->parameterTypes.PushLast(params[n]); func->inOutFlags.PushLast(inOutFlags[n]); } func->objectType = 0; importedFunctions.PushLast(func); sBindInfo info; info.importedFunction = -1; info.importFrom = moduleNameStringID; bindInformations.PushLast(info); return 0; }
// interface int asCModule::Build() { asASSERT( contextCount.get() == 0 ); // Only one thread may build at one time int r = engine->RequestBuild(); if( r < 0 ) return r; engine->PrepareEngine(); if( engine->configFailed ) { engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); engine->BuildCompleted(); return asINVALID_CONFIGURATION; } InternalReset(); if( !builder ) { engine->BuildCompleted(); return asSUCCESS; } // Store the section names for( size_t n = 0; n < builder->scripts.GetLength(); n++ ) { asCString *sectionName = asNEW(asCString)(builder->scripts[n]->name); scriptSections.PushLast(sectionName); } // Compile the script r = builder->Build(); asDELETE(builder,asCBuilder); builder = 0; if( r < 0 ) { // Reset module again InternalReset(); isBuildWithoutErrors = false; engine->BuildCompleted(); return r; } isBuildWithoutErrors = true; JITCompile(); engine->PrepareEngine(); engine->BuildCompleted(); // Initialize global variables if( r >= 0 && engine->ep.initGlobalVarsAfterBuild ) r = ResetGlobalVars(); return r; }
void asCThreadManager::Unprepare() { asASSERT(threadManager); if( threadManager == 0 ) return; // It's necessary to protect this section so no // other thread attempts to call AddRef or Release // while clean up is in progress. ENTERCRITICALSECTION(threadManager->criticalSection); if( --threadManager->refCount == 0 ) { // Make sure the local data is destroyed, at least for the current thread CleanupLocalData(); // As the critical section will be destroyed together // with the thread manager we must first clear the global // variable in case a new thread manager needs to be created; asCThreadManager *mgr = threadManager; threadManager = 0; // Leave the critical section before it is destroyed LEAVECRITICALSECTION(mgr->criticalSection); asDELETE(mgr,asCThreadManager); } else LEAVECRITICALSECTION(threadManager->criticalSection); }
asCFuncdefType::asCFuncdefType(asCScriptEngine *en, asCScriptFunction *func) : asCTypeInfo(en) { asASSERT(func->funcType == asFUNC_FUNCDEF); asASSERT(func->funcdefType == 0); // A function pointer is special kind of reference type flags = asOBJ_REF | asOBJ_FUNCDEF | (func->isShared ? asOBJ_SHARED : 0); name = func->name; nameSpace = func->nameSpace; module = func->module; accessMask = func->accessMask; funcdef = func; // reference already counted by the asCScriptFunction constructor parentClass = 0; func->funcdefType = this; }
// interface const char *asCScriptFunction::GetDeclaration(bool includeObjectName) const { asASSERT(threadManager); asCString *tempString = &threadManager->GetLocalData()->string; *tempString = GetDeclarationStr(includeObjectName); return tempString->AddressOf(); }
// internal int asCModule::AddScriptFunction(int sectionIdx, int id, const char *name, const asCDataType &returnType, asCDataType *params, asETypeModifiers *inOutFlags, int paramCount, bool isInterface, asCObjectType *objType, bool isConstMethod, bool isGlobalFunction) { asASSERT(id >= 0); // Store the function information asCScriptFunction *func = asNEW(asCScriptFunction)(engine, this, isInterface ? asFUNC_INTERFACE : asFUNC_SCRIPT); func->name = name; func->id = id; func->returnType = returnType; func->scriptSectionIdx = sectionIdx; for( int n = 0; n < paramCount; n++ ) { func->parameterTypes.PushLast(params[n]); func->inOutFlags.PushLast(inOutFlags[n]); } func->objectType = objType; func->isReadOnly = isConstMethod; // The script function's refCount was initialized to 1 scriptFunctions.PushLast(func); engine->SetScriptFunction(func); // Compute the signature id if( objType ) func->ComputeSignatureId(); // Add reference if( isGlobalFunction ) { globalFunctions.PushLast(func); func->AddRef(); } return 0; }
eTokenType asCTokenizer::GetToken(const char *source, size_t sourceLength, size_t *tokenLength, asETokenClass *tc) { asASSERT(source != 0); asASSERT(tokenLength != 0); this->source = source; this->sourceLength = sourceLength; asETokenClass t = ParseToken(); if( tc ) *tc = t; // Copy the output to the token *tokenLength = this->tokenLength; return tokenType; }
void asCGarbageCollector::GCEnumCallback(void *reference) { // This function will only be called within the critical section gcCollecting asASSERT(isProcessing); if( detectState == countReferences_loop ) { // Find the reference in the map asSMapNode<void*, asSIntTypePair> *cursor = 0; if( gcMap.MoveTo(&cursor, reference) ) { // Decrease the counter in the map for the reference gcMap.GetValue(cursor).i--; } } else if( detectState == detectGarbage_loop2 ) { // Find the reference in the map asSMapNode<void*, asSIntTypePair> *cursor = 0; if( gcMap.MoveTo(&cursor, reference) ) { // Add the object to the list of objects to mark as alive liveObjects.PushLast(reference); } } }
// internal asCScriptFunction::~asCScriptFunction() { // Clean user data if( userData && engine->cleanFunctionFunc ) engine->cleanFunctionFunc(this); // Imported functions are not reference counted, nor are dummy // functions that are allocated on the stack asASSERT( funcType == asFUNC_DUMMY || funcType == asFUNC_IMPORTED || refCount.get() == 0 ); ReleaseReferences(); // Tell engine to free the function id if( funcType != -1 && funcType != asFUNC_IMPORTED && id ) engine->FreeScriptFunctionId(id); for( asUINT n = 0; n < variables.GetLength(); n++ ) { asDELETE(variables[n],asSScriptVariable); } if( sysFuncIntf ) { asDELETE(sysFuncIntf,asSSystemFunctionInterface); } for( asUINT p = 0; p < defaultArgs.GetLength(); p++ ) { if( defaultArgs[p] ) asDELETE(defaultArgs[p], asCString); } }
// internal int asCModule::AddImportedFunction(int id, const char *name, const asCDataType &returnType, asCDataType *params, asETypeModifiers *inOutFlags, int paramCount, const asCString &moduleName) { asASSERT(id >= 0); // Store the function information asCScriptFunction *func = asNEW(asCScriptFunction)(engine, this, asFUNC_IMPORTED); func->name = name; func->id = id; func->returnType = returnType; for( int n = 0; n < paramCount; n++ ) { func->parameterTypes.PushLast(params[n]); func->inOutFlags.PushLast(inOutFlags[n]); } func->objectType = 0; sBindInfo *info = asNEW(sBindInfo); info->importedFunctionSignature = func; info->boundFunctionId = -1; info->importFromModule = moduleName; bindInformations.PushLast(info); // Add the info to the array in the engine engine->importedFunctions.PushLast(info); return 0; }
asCScriptObject &asCScriptObject::operator=(const asCScriptObject &other) { if( &other != this ) { asASSERT( other.objType->DerivesFrom(objType) ); asCScriptEngine *engine = objType->engine; // Copy all properties for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) { asCObjectProperty *prop = objType->properties[n]; if( prop->type.IsObject() ) { void **dst = (void**)(((char*)this) + prop->byteOffset); void **src = (void**)(((char*)&other) + prop->byteOffset); if( !prop->type.IsObjectHandle() ) CopyObject(*src, *dst, prop->type.GetObjectType(), engine); else CopyHandle((asDWORD*)src, (asDWORD*)dst, prop->type.GetObjectType(), engine); } else { void *dst = ((char*)this) + prop->byteOffset; void *src = ((char*)&other) + prop->byteOffset; memcpy(dst, src, prop->type.GetSizeInMemoryBytes()); } } } return *this; }
void asCGarbageCollector::ReturnNode(asSMapNode_t *node) { // This function will only be called within the critical section gcCollecting asASSERT(isProcessing); if( node ) freeNodes.PushLast(node); }
// internal void asCScriptFunction::EnumReferences(asIScriptEngine *) { asASSERT( funcType == asFUNC_DELEGATE ); // Delegate if( objForDelegate ) engine->GCEnumCallback(objForDelegate); }
void asCGlobalProperty::SetInitFunc(asCScriptFunction *in_initFunc) { // This should only be done once asASSERT( initFunc == 0 ); initFunc = in_initFunc; initFunc->AddRefInternal(); }
void asCGlobalProperty::SetInitFunc(asCScriptFunction *initFunc) { // This should only be done once asASSERT( this->initFunc == 0 ); this->initFunc = initFunc; this->initFunc->AddRef(); }
// If base is 0 the string should be prefixed by 0x, 0d, 0o, or 0b to allow the function to automatically determine the radix asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned) { asASSERT(base == 10 || base == 16 || base == 0); const char *end = string; asQWORD res = 0; if( base == 10 ) { while( *end >= '0' && *end <= '9' ) { res *= 10; res += *end++ - '0'; } } else { if( base == 0 && string[0] == '0') { // Determine the radix from the prefix switch( string[1] ) { case 'b': case 'B': base = 2; break; case 'o': case 'O': base = 8; break; case 'd': case 'D': base = 10; break; case 'x': case 'X': base = 16; break; } end += 2; } asASSERT( base ); if( base ) { for( int nbr; (nbr = asCharToNbr(*end, base)) >= 0; end++ ) res = res * base + nbr; } } if( numScanned ) *numScanned = end - string; return res; }
// interface int asCScriptFunction::Release() const { gcFlag = false; asASSERT( funcType != asFUNC_IMPORTED ); int r = refCount.atomicDec(); if( r == 0 && funcType != -1 ) // Dummy functions are allocated on the stack and cannot be deleted asDELETE(const_cast<asCScriptFunction*>(this),asCScriptFunction); return r; }
// internal // TODO: cleanup: This method should probably be a member of the engine asCGlobalProperty *asCScriptFunction::GetPropertyByGlobalVarPtr(void *gvarPtr) { asSMapNode<void*, asCGlobalProperty*> *node; if( engine->varAddressMap.MoveTo(&node, gvarPtr) ) { asASSERT(gvarPtr == node->value->GetAddressOfValue()); return node->value; } return 0; }
bool asCDataType::IsEnumType() const { // Do a sanity check on the objectType, to verify that we aren't trying to access memory after it has been released asASSERT(typeInfo == 0 || typeInfo->name.GetLength() < 100); if (typeInfo && (typeInfo->flags & asOBJ_ENUM)) return true; return false; }
void asCScriptObject::CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *objType, asCScriptEngine *engine) { // asOBJ_NOCOUNT doesn't have addref or release behaviours asASSERT( (objType->flags & asOBJ_NOCOUNT) || (objType->beh.release && objType->beh.addref) ); if( *dst && objType->beh.release ) engine->CallObjectMethod(*(void**)dst, objType->beh.release); *dst = *src; if( *dst && objType->beh.addref ) engine->CallObjectMethod(*(void**)dst, objType->beh.addref); }
// interface const char *asCModule::GetImportedFunctionDeclaration(int index) { asCScriptFunction *func = GetImportedFunction(index); if( func == 0 ) return 0; asASSERT(threadManager); asCString *tempString = &threadManager->GetLocalData()->string; *tempString = func->GetDeclarationStr(); return tempString->AddressOf(); }
// internal void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *) { asASSERT( funcType == asFUNC_DELEGATE ); // Release paramaters // Delegate if( objForDelegate ) engine->ReleaseScriptObject(objForDelegate, funcForDelegate->GetObjectType()); objForDelegate = 0; }
// interface const char *asCScriptFunction::GetVarDecl(asUINT index) const { if( index >= variables.GetLength() ) return 0; asASSERT(threadManager); asCString *tempString = &threadManager->GetLocalData()->string; *tempString = variables[index]->type.Format(); *tempString += " " + variables[index]->name; return tempString->AddressOf(); }