/** * @callback_method_impl{FNRTSTRSPACECALLBACK, Destroys RTMANIFESTENTRY.} */ static DECLCALLBACK(int) rtManifestDestroyEntry(PRTSTRSPACECORE pStr, void *pvUser) { PRTMANIFESTENTRY pEntry = RT_FROM_MEMBER(pStr, RTMANIFESTENTRY, StrCore); RTStrSpaceDestroy(&pEntry->Attributes, rtManifestDestroyAttribute, pvUser); RTMemFree(pEntry); return 0; }
/** * Destroys the current scope. * * @returns nothing. * @param pThis The interpreter context. */ static void vdScriptInterpreterScopeDestroyCurr(PVDSCRIPTINTERPCTX pThis) { AssertMsgReturnVoid(pThis->pFnCallCurr->pScopeCurr != &pThis->pFnCallCurr->ScopeRoot, ("Current scope is root scope of function call\n")); PVDSCRIPTINTERPSCOPE pScope = pThis->pFnCallCurr->pScopeCurr; pThis->pFnCallCurr->pScopeCurr = pScope->pParent; RTStrSpaceDestroy(&pScope->hStrSpaceVar, vdScriptInterpreterVarSpaceDestroy, NULL); RTMemFree(pScope); }
/** * Releases a reference to the manifest handle. * * @returns The new reference count, 0 if free. UINT32_MAX is returned if the * handle is invalid. * @param hManifest The handle to release. * NIL is quietly ignored (returns 0). */ RTDECL(uint32_t) RTManifestRelease(RTMANIFEST hManifest) { RTMANIFESTINT *pThis = hManifest; if (pThis == NIL_RTMANIFEST) return 0; AssertPtrReturn(pThis, UINT32_MAX); AssertReturn(pThis->u32Magic == RTMANIFEST_MAGIC, UINT32_MAX); uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); Assert(cRefs < _1M); if (!cRefs) { ASMAtomicWriteU32(&pThis->u32Magic, ~RTMANIFEST_MAGIC); RTStrSpaceDestroy(&pThis->Entries, rtManifestDestroyEntry,pThis); RTStrSpaceDestroy(&pThis->SelfEntry.Attributes, rtManifestDestroyAttribute, pThis); RTMemFree(pThis); } return cRefs; }
/** * Evaluate interpreter control statement. * * @returns VBox status code. * @param pThis The interpreter context. * @param pCtrl The control entry to evaluate. */ static int vdScriptInterpreterEvaluateCtrlEntry(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTINTERPCTRL pCtrl) { int rc = VINF_SUCCESS; Assert(!pCtrl->fEvalAst); switch (pCtrl->Ctrl.enmCtrlType) { case VDSCRIPTINTERPCTRLTYPE_FN_CALL: { PVDSCRIPTFN pFn = pCtrl->Ctrl.FnCall.pFn; vdScriptStackPop(&pThis->StackCtrl); rc = vdScriptInterpreterFnCall(pThis, pFn); break; } case VDSCRIPTINTERPCTRLTYPE_FN_CALL_CLEANUP: { vdScriptStackPop(&pThis->StackCtrl); /* Delete function call entry. */ AssertPtr(pThis->pFnCallCurr); PVDSCRIPTINTERPFNCALL pFnCallFree = pThis->pFnCallCurr; pThis->pFnCallCurr = pFnCallFree->pCaller; Assert(pFnCallFree->pScopeCurr == &pFnCallFree->ScopeRoot); RTStrSpaceDestroy(&pFnCallFree->ScopeRoot.hStrSpaceVar, vdScriptInterpreterVarSpaceDestroy, NULL); RTMemFree(pFnCallFree); break; } case VDSCRIPTINTERPCTRLTYPE_COMPOUND: { if (!pCtrl->Ctrl.Compound.pStmtCurr) { /* Evaluated last statement, cleanup and remove the control statement from the stack. */ vdScriptInterpreterScopeDestroyCurr(pThis); vdScriptStackPop(&pThis->StackCtrl); } else { /* Push the current statement onto the control stack and move on. */ rc = vdScriptInterpreterPushAstEntry(pThis, &pCtrl->Ctrl.Compound.pStmtCurr->Core); if (RT_SUCCESS(rc)) { pCtrl->Ctrl.Compound.pStmtCurr = RTListGetNext(&pCtrl->Ctrl.Compound.pStmtCompound->Compound.ListStmts, pCtrl->Ctrl.Compound.pStmtCurr, VDSCRIPTASTSTMT, Core.ListNode); } } break; } case VDSCRIPTINTERPCTRLTYPE_LOOP: { PVDSCRIPTASTSTMT pLoopStmt = (PVDSCRIPTASTSTMT)pCtrl->Ctrl.pAstNode; /* Check whether the condition passed. */ VDSCRIPTARG Cond; vdScriptInterpreterPopValue(pThis, &Cond); AssertMsg(Cond.enmType == VDSCRIPTTYPE_BOOL, ("Value on stack is not of boolean type\n")); if (Cond.f) { /* Execute the loop another round. */ if (pLoopStmt->enmStmtType == VDSCRIPTSTMTTYPE_WHILE) { rc = vdScriptInterpreterPushAstEntry(pThis, &pLoopStmt->While.pCond->Core); if (RT_SUCCESS(rc)) { rc = vdScriptInterpreterPushAstEntry(pThis, &pLoopStmt->While.pStmt->Core); if (RT_FAILURE(rc)) vdScriptStackPop(&pThis->StackCtrl); } } else { AssertMsg(pLoopStmt->enmStmtType == VDSCRIPTSTMTTYPE_FOR, ("Not a for statement\n")); rc = vdScriptInterpreterPushAstEntry(pThis, &pLoopStmt->For.pExprCond->Core); if (RT_SUCCESS(rc)) { rc = vdScriptInterpreterPushAstEntry(pThis, &pLoopStmt->For.pExpr3->Core); if (RT_SUCCESS(rc)) { rc = vdScriptInterpreterPushAstEntry(pThis, &pLoopStmt->For.pStmt->Core); if (RT_FAILURE(rc)) vdScriptStackPop(&pThis->StackCtrl); } if (RT_FAILURE(rc)) vdScriptStackPop(&pThis->StackCtrl); } } } else vdScriptStackPop(&pThis->StackCtrl); /* Remove loop control statement. */ break; } case VDSCRIPTINTERPCTRLTYPE_IF: { PVDSCRIPTASTSTMT pIfStmt = (PVDSCRIPTASTSTMT)pCtrl->Ctrl.pAstNode; vdScriptStackPop(&pThis->StackCtrl); /* Remove if control statement. */ /* Check whether the condition passed. */ VDSCRIPTARG Cond; vdScriptInterpreterPopValue(pThis, &Cond); AssertMsg(Cond.enmType == VDSCRIPTTYPE_BOOL, ("Value on stack is not of boolean type\n")); if (Cond.f) { /* Execute the true branch. */ rc = vdScriptInterpreterPushAstEntry(pThis, &pIfStmt->If.pTrueStmt->Core); } else if (pIfStmt->If.pElseStmt) rc = vdScriptInterpreterPushAstEntry(pThis, &pIfStmt->If.pElseStmt->Core); break; } default: AssertMsgFailed(("Invalid evaluation control type on the stack: %d\n", pCtrl->Ctrl.enmCtrlType)); } return rc; }
/** * Evaluate a function call. * * @returns VBox status code. * @param pThis The interpreter context. * @param pFn The function execute. */ static int vdScriptInterpreterFnCall(PVDSCRIPTINTERPCTX pThis, PVDSCRIPTFN pFn) { int rc = VINF_SUCCESS; if (!pFn->fExternal) { PVDSCRIPTASTFN pAstFn = pFn->Type.Internal.pAstFn; /* Add function call cleanup marker on the stack first. */ rc = vdScriptInterpreterPushNonDataCtrlEntry(pThis, VDSCRIPTINTERPCTRLTYPE_FN_CALL_CLEANUP); if (RT_SUCCESS(rc)) { /* Create function call frame and set it up. */ PVDSCRIPTINTERPFNCALL pFnCall = (PVDSCRIPTINTERPFNCALL)RTMemAllocZ(sizeof(VDSCRIPTINTERPFNCALL)); if (pFnCall) { pFnCall->pCaller = pThis->pFnCallCurr; pFnCall->ScopeRoot.pParent = NULL; pFnCall->ScopeRoot.hStrSpaceVar = NULL; pFnCall->pScopeCurr = &pFnCall->ScopeRoot; /* Add the variables, remember order. The first variable in the argument has the value at the top of the value stack. */ PVDSCRIPTASTFNARG pArg = RTListGetFirst(&pAstFn->ListArgs, VDSCRIPTASTFNARG, Core.ListNode); for (unsigned i = 0; i < pAstFn->cArgs; i++) { PVDSCRIPTINTERPVAR pVar = (PVDSCRIPTINTERPVAR)RTMemAllocZ(sizeof(VDSCRIPTINTERPVAR)); if (pVar) { pVar->Core.pszString = pArg->pArgIde->aszIde; pVar->Core.cchString = pArg->pArgIde->cchIde; vdScriptInterpreterPopValue(pThis, &pVar->Value); bool fInserted = RTStrSpaceInsert(&pFnCall->ScopeRoot.hStrSpaceVar, &pVar->Core); Assert(fInserted); } else { rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory creating a variable"); break; } pArg = RTListGetNext(&pAstFn->ListArgs, pArg, VDSCRIPTASTFNARG, Core.ListNode); } if (RT_SUCCESS(rc)) { /* * Push compount statement on the control stack and make the newly created * call frame the current one. */ rc = vdScriptInterpreterPushAstEntry(pThis, &pAstFn->pCompoundStmts->Core); if (RT_SUCCESS(rc)) pThis->pFnCallCurr = pFnCall; } if (RT_FAILURE(rc)) { RTStrSpaceDestroy(&pFnCall->ScopeRoot.hStrSpaceVar, vdScriptInterpreterVarSpaceDestroy, NULL); RTMemFree(pFnCall); } } else rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory creating a call frame"); } } else { /* External function call, build the argument list. */ if (pFn->cArgs) { PVDSCRIPTARG paArgs = (PVDSCRIPTARG)RTMemAllocZ(pFn->cArgs * sizeof(VDSCRIPTARG)); if (paArgs) { for (unsigned i = 0; i < pFn->cArgs; i++) vdScriptInterpreterPopValue(pThis, &paArgs[i]); rc = pFn->Type.External.pfnCallback(paArgs, pFn->Type.External.pvUser); RTMemFree(paArgs); } else rc = vdScriptInterpreterError(pThis, VERR_NO_MEMORY, RT_SRC_POS, "Out of memory creating argument array for external function call"); } else rc = pFn->Type.External.pfnCallback(NULL, pFn->Type.External.pvUser); } return rc; }