Skip to content

Bug: ManuallyPushCall doesn't nest #8

Description

@MineRobber9000

Bug

Calling a function using ManuallyPushCall that, itself, uses ManuallyPushCall (for example, using import to import a file which imports other files) causes the outside call to fail (in the case of import, causing it to return the library name, with the results of the actual import lost).

Why it happens

When you call VM::ManuallyPushCall, the VM does some stack/CallInfo setup and then sets some variables related to pending manual calls:

	public void ManuallyPushCall(Int32 intrinsicCalleeBase, FuncDef importMain) {
		// Module frame sits just above the import intrinsic's 2-register frame (r0 + libname).
		Int32 calleeBase = intrinsicCalleeBase + 2;
		if (!EnsureFrame(calleeBase, importMain.MaxRegs)) return;
		for (Int32 i = 0; i < importMain.MaxRegs; i++) {
			stack[calleeBase + i] = Value.Null;
			names[calleeBase + i] = Value.Null;
		}

		if (callStackTop >= callStack.Count) callStack.Add(new CallInfo(0, 0, null));
		callStack[callStackTop] = new CallInfo(PC, BaseIndex, CurrentFunction);
		callStackTop++;

		BaseIndex = calleeBase;
		CurrentFunction = importMain;
		PC = 0;

		_hasPendingManualCall = true;
		_pendingManualCallDepth = callStackTop;
		ManualCallResult = Value.Null;
	}

Inside the VM, when we execute a return opcode, we check to see if we're returning from a manually pushed call, and if so, we save the return value in vm.ManualCallResult and exit RunInner:

					// Detect return from a manually-pushed call (e.g. import module).
					// Save the result and exit RunInner so Run() re-invokes the callback.
					if (_hasPendingManualCall && callStackTop == _pendingManualCallDepth - 1) {
						ManualCallResult = val;
						_hasPendingManualCall = false;
						cyclesLeft = 0;
					}

This works if the last pending manual call is the only manual pending call, but if there was another pending call before this one, we've now lost it. This means that RunInner will continue on as if the outer call weren't even there.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions