Beginnings of the "pass everything using a native type wrapper" console code.

- ConsoleValue class is now the base value class.
- ConsoleValueRef is now used to supply function parameters. Values are disposable.
- Script functions return values instead of just strings where possible.
- Variables can be disposable strings
- Bytecode changed

Fix the issues with console method parameters and fields which prevented missions from loading.
This commit is contained in:
James Urquhart 2012-09-23 09:59:48 +01:00
parent 394d87cd54
commit 38c8e52c1d
68 changed files with 1511 additions and 529 deletions

View file

@ -35,6 +35,44 @@
//#define DEBUG_SPEW
Dictionary::Entry smLocalDictionaryEntryStack[4096*4];
Dictionary::Entry *smLocalDictionaryEntryStackHead = NULL;
void setupDictionaryStack()
{
smLocalDictionaryEntryStackHead = &smLocalDictionaryEntryStack[0];
for (int i=0; i<4096*4; i++) {
(smLocalDictionaryEntryStackHead + i)->mNext = i == (4096*4)-1 ? NULL : smLocalDictionaryEntryStackHead + (i+1);
}
}
Dictionary::Entry * getDictionaryStackEntry()
{
Dictionary::Entry *entry = smLocalDictionaryEntryStackHead;
AssertFatal(entry, "No more local variables");
entry->reset();
Dictionary::Entry *next = entry->mNext;
smLocalDictionaryEntryStackHead = next;
entry->mNext = NULL;
return entry;
}
void disposeDictionaryStackEntry(Dictionary::Entry *entry)
{
Dictionary::Entry *prevHead = smLocalDictionaryEntryStackHead;
smLocalDictionaryEntryStackHead = entry;
smLocalDictionaryEntryStackHead->mNext = prevHead;
}
#define ST_INIT_SIZE 15
static char scratchBuffer[1024];
@ -168,13 +206,13 @@ void Dictionary::exportVariables(const char *varString, const char *fileName, bo
for(s = sortList.begin(); s != sortList.end(); s++)
{
switch((*s)->type)
switch((*s)->value.type)
{
case Entry::TypeInternalInt:
dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->ival, cat);
case ConsoleValue::TypeInternalInt:
dSprintf(buffer, sizeof(buffer), "%s = %d;%s", (*s)->name, (*s)->value.ival, cat);
break;
case Entry::TypeInternalFloat:
dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->fval, cat);
case ConsoleValue::TypeInternalFloat:
dSprintf(buffer, sizeof(buffer), "%s = %g;%s", (*s)->name, (*s)->value.fval, cat);
break;
default:
expandEscape(expandBuffer, (*s)->getStringValue());
@ -228,13 +266,13 @@ void Dictionary::exportVariables( const char *varString, Vector<String> *names,
if ( values )
{
switch ( (*s)->type )
switch ( (*s)->value.type )
{
case Entry::TypeInternalInt:
values->push_back( String::ToString( (*s)->ival ) );
case ConsoleValue::TypeInternalInt:
values->push_back( String::ToString( (*s)->value.ival ) );
break;
case Entry::TypeInternalFloat:
values->push_back( String::ToString( (*s)->fval ) );
case ConsoleValue::TypeInternalFloat:
values->push_back( String::ToString( (*s)->value.fval ) );
break;
default:
expandEscape( expandBuffer, (*s)->getStringValue() );
@ -284,10 +322,13 @@ Dictionary::Entry *Dictionary::lookup(StringTableEntry name)
Dictionary::Entry *Dictionary::add(StringTableEntry name)
{
// Try to find an existing match.
//printf("Add Variable %s\n", name);
Entry* ret = lookup( name );
if( ret )
if( ret ) {
//printf("Found Variable %s (named %s)\n", name, ret->name);
return ret;
}
// Rehash if the table get's too crowded. Be aware that this might
// modify a table that we don't own.
@ -296,6 +337,7 @@ Dictionary::Entry *Dictionary::add(StringTableEntry name)
if( hashTable->count > hashTable->size * 2 )
{
// Allocate a new table.
printf("Re-hashing dictionary...\n");
const U32 newTableSize = hashTable->size * 4 - 1;
Entry** newTableData = new Entry*[ newTableSize ];
@ -307,7 +349,10 @@ Dictionary::Entry *Dictionary::add(StringTableEntry name)
for( Entry* entry = hashTable->data[ i ]; entry != NULL; )
{
Entry* next = entry->nextEntry;
S32 index = HashPointer( entry->name ) % newTableSize;
U32 index = HashPointer( entry->name ) % newTableSize;
//printf(" Variable(%s) in bucket %i moved to bucket %i\n", entry->name, i, index);
entry->nextEntry = newTableData[ index ];
newTableData[ index ] = entry;
@ -328,9 +373,10 @@ Dictionary::Entry *Dictionary::add(StringTableEntry name)
// Add the new entry.
ret = hashTable->mChunker.alloc();
constructInPlace( ret, name );
S32 idx = HashPointer(name) % hashTable->size;
ret = getDictionaryStackEntry();//hashTable->mChunker.alloc();
ret->name = name;
//constructInPlace( ret, name );
U32 idx = HashPointer(name) % hashTable->size;
ret->nextEntry = hashTable->data[idx];
hashTable->data[idx] = ret;
@ -350,8 +396,8 @@ void Dictionary::remove(Dictionary::Entry *ent)
*walk = (ent->nextEntry);
destructInPlace( ent );
hashTable->mChunker.free( ent );
disposeDictionaryStackEntry( ent );
//hashTable->mChunker.free( ent );
hashTable->count--;
}
@ -412,13 +458,13 @@ void Dictionary::reset()
while( walk )
{
Entry* temp = walk->nextEntry;
destructInPlace( walk );
disposeDictionaryStackEntry( walk );
walk = temp;
}
}
dMemset( ownHashTable.data, 0, ownHashTable.size * sizeof( Entry* ) );
ownHashTable.mChunker.freeBlocks( true );
//ownHashTable.mChunker.freeBlocks( true );
ownHashTable.count = 0;
hashTable = NULL;
@ -454,7 +500,7 @@ char *typeValueEmpty = "";
Dictionary::Entry::Entry(StringTableEntry in_name)
{
name = in_name;
type = TypeInternalString;
value.type = ConsoleValue::TypeInternalString;
notify = NULL;
nextEntry = NULL;
mUsage = NULL;
@ -462,17 +508,12 @@ Dictionary::Entry::Entry(StringTableEntry in_name)
// NOTE: This is data inside a nameless
// union, so we don't need to init the rest.
ival = 0;
fval = 0;
sval = typeValueEmpty;
bufferLen = 0;
value.init();
}
Dictionary::Entry::~Entry()
{
if ( type <= TypeInternalString &&
sval != typeValueEmpty )
dFree(sval);
value.cleanup();
if ( notify )
delete notify;
@ -497,15 +538,11 @@ const char *Dictionary::getVariable(StringTableEntry name, bool *entValid)
return "";
}
void Dictionary::Entry::setStringValue(const char * value)
void ConsoleValue::setStringValue(const char * value)
{
if( mIsConstant )
{
Con::errorf( "Cannot assign value to constant '%s'.", name );
return;
}
if (value == NULL) value = typeValueEmpty;
if(type <= TypeInternalString)
if(type <= ConsoleValue::TypeInternalString)
{
// Let's not remove empty-string-valued global vars from the dict.
// If we remove them, then they won't be exported, and sometimes
@ -519,6 +556,15 @@ void Dictionary::Entry::setStringValue(const char * value)
return;
}
*/
if (value == typeValueEmpty) {
if (sval && sval != typeValueEmpty && type != TypeInternalStackString) dFree(sval);
sval = typeValueEmpty;
bufferLen = 0;
fval = 0.f;
ival = 0;
type = TypeInternalString;
return;
}
U32 stringLen = dStrlen(value);
@ -537,25 +583,89 @@ void Dictionary::Entry::setStringValue(const char * value)
ival = 0;
}
type = TypeInternalString;
// may as well pad to the next cache line
U32 newLen = ((stringLen + 1) + 15) & ~15;
if(sval == typeValueEmpty)
if(sval == typeValueEmpty || type == TypeInternalStackString)
sval = (char *) dMalloc(newLen);
else if(newLen > bufferLen)
sval = (char *) dRealloc(sval, newLen);
type = TypeInternalString;
bufferLen = newLen;
dStrcpy(sval, value);
}
else
Con::setData(type, dataPtr, 0, 1, &value, enumTable);
}
// Fire off the notification if we have one.
if ( notify )
notify->trigger();
void ConsoleValue::setStackStringValue(const char * value)
{
if (value == NULL) value = typeValueEmpty;
if(type <= ConsoleValue::TypeInternalString)
{
if (value == typeValueEmpty) {
if (sval && sval != typeValueEmpty && type != ConsoleValue::TypeInternalStackString) dFree(sval);
sval = typeValueEmpty;
bufferLen = 0;
fval = 0.f;
ival = 0;
type = TypeInternalString;
return;
}
U32 stringLen = dStrlen(value);
if(stringLen < 256)
{
fval = dAtof(value);
ival = dAtoi(value);
}
else
{
fval = 0.f;
ival = 0;
}
type = TypeInternalStackString;
sval = (char*)value;
bufferLen = stringLen;
}
else
Con::setData(type, dataPtr, 0, 1, &value, enumTable);
}
S32 Dictionary::getIntVariable(StringTableEntry name, bool *entValid)
{
Entry *ent = lookup(name);
if(ent)
{
if(entValid)
*entValid = true;
return ent->getIntValue();
}
if(entValid)
*entValid = false;
return 0;
}
F32 Dictionary::getFloatVariable(StringTableEntry name, bool *entValid)
{
Entry *ent = lookup(name);
if(ent)
{
if(entValid)
*entValid = true;
return ent->getFloatValue();
}
if(entValid)
*entValid = false;
return 0;
}
void Dictionary::setVariable(StringTableEntry name, const char *value)
@ -582,19 +692,19 @@ Dictionary::Entry* Dictionary::addVariable( const char *name,
Entry *ent = add(StringTable->insert(name));
if ( ent->type <= Entry::TypeInternalString &&
ent->sval != typeValueEmpty )
dFree(ent->sval);
if ( ent->value.type <= ConsoleValue::TypeInternalString &&
ent->value.sval != typeValueEmpty && ent->value.type != ConsoleValue::TypeInternalStackString )
dFree(ent->value.sval);
ent->type = type;
ent->dataPtr = dataPtr;
ent->value.type = type;
ent->value.dataPtr = dataPtr;
ent->mUsage = usage;
// Fetch enum table, if any.
ConsoleBaseType* conType = ConsoleBaseType::getType( type );
AssertFatal( conType, "Dictionary::addVariable - invalid console type" );
ent->enumTable = conType->getEnumTable();
ent->value.enumTable = conType->getEnumTable();
return ent;
}
@ -1031,6 +1141,8 @@ void Namespace::init()
mGlobalNamespace->mName = NULL;
mGlobalNamespace->mNext = NULL;
mNamespaceList = mGlobalNamespace;
setupDictionaryStack();
}
Namespace *Namespace::global()
@ -1268,7 +1380,7 @@ void Namespace::markGroup(const char* name, const char* usage)
extern S32 executeBlock(StmtNode *block, ExprEvalState *state);
const char *Namespace::Entry::execute(S32 argc, const char **argv, ExprEvalState *state)
const char *Namespace::Entry::execute(S32 argc, ConsoleValueRef *argv, ExprEvalState *state)
{
if(mType == ConsoleFunctionType)
{