Такая ситуация — есть нативная функция которая возвращает объект скажем objX
у объекта objX есть свойство массив arr, в который складываются объекты objY
Выглядит примерно так:
tiscript::object_ref objX(pVM);
tiscript::array_ref arr (pVM);
objX.create();
arr. create();
for (int i = 0; i < 10; i++)
{
tiscript::object_ref objY(pVM);
objY.create();
objY.set("ID", tiscript::v_int(i));
objY.set("prop2", tiscript::v_int(i * 2));
arr.push(objY);
}
objX.set("arr", arr);
return objX;
При попытке обратится к свойству объекта objY из массива arr Получил:
Error: Object BrokenHeart([object BrokenHeart]) has no property — ID
Я так полагаю дело в порядке утановки свойств или в чем ?
Есть такое предложение — сделать функцию GCLock(BOOL bLock) — чтобы она блокировала GC полностью, возможно ли такое ?
Здравствуйте, kuzbas22, Вы писали:
K>При попытке обратится к свойству объекта objY из массива arr Получил:
K>Error: Object BrokenHeart([object BrokenHeart]) has no property — ID
K>Я так полагаю дело в порядке утановки свойств или в чем ?
Я не вижу в твоем коде "попытку обратится к свойству объекта objY из массива arr". Как точно это сделано?
BrokenHeart это индикация того что объект был удален в процессе GC. Как правило лечится использованием pinned variables.
Скрорее всего у тебя где-то используется naked value типа:
value t = ...;
arr.push( t ); // may cause GC
get_prop(t,...); // may cry "BrokenHeart" here as t is not a valid object handle anymore.
K>Есть такое предложение — сделать функцию GCLock(BOOL bLock) — чтобы она блокировала GC полностью, возможно ли такое ?
В твоей функции идет активная аллокация объектов. Если при этом происходит переполнение heap то вызывается GC.
Т.е. не ясно что именно должен делать эта GCLock если памяти не хватат. Генерить exception? Что ты будешь с ним делать?
Здравствуйте, c-smile, Вы писали:
CS>Я не вижу в твоем коде "попытку обратится к свойству объекта objY из массива arr". Как точно это сделано?
Это делается из TIS
CS>BrokenHeart это индикация того что объект был удален в процессе GC. Как правило лечится использованием pinned variables.
CS>Скрорее всего у тебя где-то используется naked value типа:
CS>CS>value t = ...;
CS>arr.push( t ); // may cause GC
CS>get_prop(t,...); // may cry "BrokenHeart" here as t is not a valid object handle anymore.
CS>
Даже если t — v_int ?
K>>Есть такое предложение — сделать функцию GCLock(BOOL bLock) — чтобы она блокировала GC полностью, возможно ли такое ?
Вот функция целиком:
tiscript::value CModulePref::GetGameStatePacket(tiscript::VM* pVM)
{
tiscript::object_ref valRet(pVM);
valRet.create();
valRet.set("State", tiscript::v_int(m_GameState.state.eState));
valRet.set("ActiveUserID", tiscript::v_int(m_GameState.state.nActiveUserID));
valRet.set("TableID", tiscript::v_int(m_GameState.state.nTableID));
PrefGameState pgs = CPrefLogic::ToGameState(m_GameState.state);
CPrefLogic pl(pgs);
tiscript::array_ref valSitOrder(pVM);
valSitOrder.create();
for (int i = 0; i < SIZE_OF(m_GameState.state.nSitOrder); i++)
{
valSitOrder.push(tiscript::v_int(m_GameState.state.nSitOrder[i]));
}
valRet.set("SitOrder", valSitOrder);
tiscript::array_ref valWidow(pVM);
valWidow.create();
for (int i = 0; i < SIZE_OF(m_GameState.state.widow); i++)
{
valWidow.push(tiscript::v_int(m_GameState.state.widow[i]));
}
valRet.set("Widow", valWidow);
tiscript::array_ref valUserCards(pVM);
valUserCards.create();
BYTE* pCards = pl.GetUserCards(GetUserID());
if (pCards)
{
for (int i = 0; i < PREF_MAX_CARDS_PER_USER; i++)
{
if (pCards[i])
valUserCards.push(tiscript::v_int(pCards[i]));
}
}
valRet.set("Cards", valUserCards);
tiscript::array_ref valUsersState(pVM);
valUsersState.create();
UserState us[PREF_MAX_USERS_PER_TABLE];
memset(us, 0, sizeof(us));
if (m_GameState.state.nSitOrder[0])
{
for (int i = 0; i < SIZE_OF(m_GameState.state.nSitOrder); i++)
{
int nID = m_GameState.state.nSitOrder[i];
for (int j = 0; j < SIZE_OF(m_GameState.state.usersState); j++)
{
if (m_GameState.state.usersState[j].nID == nID)
{
memcpy(us + i, m_GameState.state.usersState + j, sizeof(UserState));
}
}
}
for (int i = 0; i < SIZE_OF(us); i++)
{
if (us[i].nID == GetUserID())
{
rshift(us, SIZE_OF(us), i);
break;
}
}
//memcpy(m_GameState.state.usersState, us, sizeof(m_GameState.state.usersState));
}
else
{
memcpy(us, m_GameState.state.usersState, sizeof(us));
}
for (int i = 0; i < SIZE_OF(us); i++)
{
if (!m_GameState.state.usersState[i].nID)
continue;
tiscript::object_ref valUserState(pVM);
valUserState.create();
valUserState.set("ID", tiscript::v_int(us[i].nID));
valUserState.set("State", tiscript::v_int(us[i].eState));
valUsersState.push(valUserState);
}
valRet.set("Users", valUsersState);
valRet.set("DealerID", tiscript::v_int(m_GameState.state.nDealerID));
valRet.set("TradeWinnerID", tiscript::v_int(m_GameState.state.nTradeWinnerID));
tiscript::array_ref valWhoDeal(pVM);
valWhoDeal.create();
BYTE wd[PREF_MAX_USERS_PER_TABLE] = { 0 };
for (int i = 0; i < SIZE_OF(us); i++)
{
for (int j = 0; j < SIZE_OF(m_GameState.state.usersState); j++)
{
if (m_GameState.state.usersState[j].nID == us[i].nID)
{
wd[i] = m_GameState.state.whodeal[j];
break;
}
}
}
rshift(wd, SIZE_OF(wd), 1);
for (int i = 0; i < SIZE_OF(wd); i++)
{
if (wd[i])
valWhoDeal.push(tiscript::v_int(wd[i]));
}
valRet.set("WhoDeal", valWhoDeal);
tiscript::array_ref valMisereCards(pVM);
valMisereCards.create();
for (int i = 0; i < SIZE_OF(m_GameState.state.misereCards); i++)
{
valMisereCards.push( tiscript::v_int(m_GameState.state.misereCards[i]) );
}
valRet.set("MisereCards", valMisereCards);
valRet.set("Card4th", tiscript::v_int(m_GameState.state.n4thCard));
return valRet;
}
Есть еще обертка для этой функции, которая экспортируется в TIS, вот она, на всякий:
tiscript::value TISAPI tisGetPrefGameState(tiscript::VM* pVM)
{
tiscript::pinned retVal(pVM);
retVal = tiscript::v_undefined();
tiscript::value valRoot;
try
{
tiscript::args(pVM)
>> tiscript::args::skip // skip 'this' as this is a global function.
>> tiscript::args::skip // skip 'super'
>> valRoot;
}
catch(tiscript::args::error &e)
{
tiscript::throw_error(pVM, e.msg());
return retVal;
}
HELEMENT hRoot = tiscript::get_native_data(valRoot);
ASSERT(hRoot);
if (hRoot)
{
CAppWnd* pWnd = (CAppWnd*)CAppWnd::GetByRoot(hRoot);
ASSERT(pWnd);
if (pWnd)
{
ASSERT(pWnd->GetTEP()->GetModule() == E_SM_PREF);
if (pWnd->GetTEP()->GetModule() == E_SM_PREF)
{
CModulePref* pMod = (CModulePref*)pWnd->GetTEP();
retVal = pMod->GetGameStatePacket(pVM);
}
}
}
return retVal;
}
И вот TIS:
function updateUsers()
{
var packet = GetPrefGameState(view.root);
var n = 0;
var elUserInfos = [ self.$(.userPanelL), self.$(.userPanelR) ];
var elNames = [ self.$(#idU1Name), self.$(#idU2Name) ];
var elStatus = [ self.$(p.status_l), self.$(p.status_r) ];
var status_img = [ "url(../img/status_l.png)", "url(../img/status_r.png)" ];
var statusi_img = [ "url(../img/statusi_l.png)", "url(../img/statusi_r.png)"];
for (var el in elUserInfos)
{
el.style#foreground-image = "url(../img/ava_empty.png)";
}
for (var el in elStatus )
{
el.style#display = "none";
}
for (var i = 0; i < packet.Users.length; i++)
{
if (packet.Users[i].ID != GetCurrentUserID())
Последняя строчка — то место на которое указывает инфа из exception
Причем var packet = GetPrefGameState(view.root); я очень активно использую внутри скрипта, практически в каждой функции оно есть.
И что самое странное — поймал я этот exception всего единожды.
CS>В твоей функции идет активная аллокация объектов. Если при этом происходит переполнение heap то вызывается GC.
CS>Т.е. не ясно что именно должен делать эта GCLock если памяти не хватат. Генерить exception? Что ты будешь с ним делать?
С этим все ясно
Вроде удалось решить проблему добавив pinned в array_ref::push сл. образом:
bool push(value value)
{
pinned pinned_val(vm, value);
assert(is_set());
unsigned l = length();
val = ni()->set_array_size(vm,val,l + 1);
return ni()->set_elem(vm,val,l,pinned_val);
}
Вопрос: можно ли делать pin 2 раза, т.е. если сюда придет который уже запинен, не вызовет ли это каких либо казусов? я просто предположил что pin работает аналогично AddRef..
Если все ок, то может быть внесете эти изменения?
Здравствуйте, kuzbas22, Вы писали:
K>Вопрос: можно ли делать pin 2 раза, т.е. если сюда придет который уже запинен, не вызовет ли это каких либо казусов? я просто предположил что pin работает аналогично AddRef..
K>Если все ок, то может быть внесете эти изменения?
Забареи отсюда:
http://code.google.com/p/tiscript/source/browse/trunk/sdk/include/tiscript.hpp
Здравствуйте, kuzbas22, Вы писали:
K>Вопрос: можно ли делать pin 2 раза, т.е. если сюда придет который уже запинен, не вызовет ли это каких либо казусов? я просто предположил что pin работает аналогично AddRef..
Можно делать 2 и более раз.
pinned это структура следующего вида:
struct pinned
{
pinned* prev, next;
object* val;
}
т.е. это элемент списка memory locations которые содержат указатели на объекты.
Когда GC перемещает объекты он в том числе идет по этому списку и обновляет значения val.
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, kuzbas22, Вы писали:
K>>Вопрос: можно ли делать pin 2 раза, т.е. если сюда придет который уже запинен, не вызовет ли это каких либо казусов? я просто предположил что pin работает аналогично AddRef..
CS>Можно делать 2 и более раз.
CS>pinned это структура следующего вида:
CS>CS>struct pinned
CS>{
CS> pinned* prev, next;
CS> object* val;
CS>}
CS>
CS>т.е. это элемент списка memory locations которые содержат указатели на объекты.
CS>Когда GC перемещает объекты он в том числе идет по этому списку и обновляет значения val.
Спасибо.