| 1387 | } |
| 1388 | |
| 1389 | int asCContext::PushState() |
| 1390 | { |
| 1391 | // Only allow the state to be pushed when active |
| 1392 | // TODO: Can we support a suspended state too? So the reuse of |
| 1393 | // the context can be done outside the Execute() call? |
| 1394 | if( m_status != asEXECUTION_ACTIVE ) |
| 1395 | { |
| 1396 | // TODO: Write message. Wrong usage |
| 1397 | return asERROR; |
| 1398 | } |
| 1399 | |
| 1400 | // Allocate space on the callstack for at least two states |
| 1401 | if (m_callStack.GetLength() >= m_callStack.GetCapacity() - 2*CALLSTACK_FRAME_SIZE) |
| 1402 | { |
| 1403 | if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE) |
| 1404 | { |
| 1405 | // The call stack is too big to grow further |
| 1406 | // If an error occurs, no change to the context should be done |
| 1407 | return asOUT_OF_MEMORY; |
| 1408 | } |
| 1409 | |
| 1410 | // Allocate space for 10 call states at a time to save time |
| 1411 | m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10 * CALLSTACK_FRAME_SIZE, true); |
| 1412 | } |
| 1413 | |
| 1414 | // Push the current script function that is calling the system function |
| 1415 | // This cannot fail, since the memory was already allocated above |
| 1416 | PushCallState(); |
| 1417 | |
| 1418 | // Push the system function too, which will serve both as a marker and |
| 1419 | // informing which system function that created the nested call |
| 1420 | m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE); |
| 1421 | |
| 1422 | // Need to push m_initialFunction as it must be restored later |
| 1423 | asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; |
| 1424 | tmp[0] = 0; |
| 1425 | tmp[1] = (asPWORD)m_callingSystemFunction; |
| 1426 | tmp[2] = (asPWORD)m_initialFunction; |
| 1427 | tmp[3] = (asPWORD)m_originalStackPointer; |
| 1428 | tmp[4] = (asPWORD)m_argumentsSize; |
| 1429 | |
| 1430 | // Need to push the value of registers so they can be restored |
| 1431 | tmp[5] = (asPWORD)asDWORD(m_regs.valueRegister); |
| 1432 | tmp[6] = (asPWORD)asDWORD(m_regs.valueRegister>>32); |
| 1433 | tmp[7] = (asPWORD)m_regs.objectRegister; |
| 1434 | tmp[8] = (asPWORD)m_regs.objectType; |
| 1435 | |
| 1436 | // Decrease stackpointer to prevent the top value from being overwritten |
| 1437 | m_regs.stackPointer -= 2; |
| 1438 | |
| 1439 | // Clear the initial function so that Prepare() knows it must do all validations |
| 1440 | m_initialFunction = 0; |
| 1441 | |
| 1442 | // After this the state should appear as if uninitialized |
| 1443 | m_callingSystemFunction = 0; |
| 1444 | |
| 1445 | m_regs.objectRegister = 0; |
| 1446 | m_regs.objectType = 0; |
no test coverage detected