File: StackCall.h

package info (click to toggle)
storm-lang 0.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,028 kB
  • sloc: ansic: 261,471; cpp: 140,432; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (58 lines) | stat: -rw-r--r-- 2,581 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#pragma once
#include "Stack.h"
#include "UThread.h"
#include "FnCall.h"

namespace os {

	// Internal function written in ASM that does the heavy lifting.
	extern "C" void doStackCall(Stack *current, Stack *callOn, const void *fn, const FnCallRaw *fnCall, bool member, void *result);

	// Internal helper of common code for both functions.
	inline void stackCallI(Stack *callOn, const void *fn, const FnCallRaw *fnCall, bool member, void *result) {
		dbg_assert(OFFSET_OF(Stack, desc) == sizeof(void *)*2, L"Invalid layout of the Stack object.");
		dbg_assert(OFFSET_OF(Stack, detourTo) == sizeof(void *)*4, L"Invalid layout of the Stack object.");

		callOn->clear();

		UThreadData *data = UThread::current().threadData();
		try {
			doStackCall(&data->stack, callOn, fn, fnCall, member, result);
			callOn->clear();
		} catch (...) {
			// Unlink the stack. Otherwise, it will still be scanned at a later point. This is
			// likely slightly too late, but it is the best we can do right now (stack has probably
			// already been unwound from "callOn", which means that there is a window where the GC
			// will make wrong assumptions). This case is handled in the GC scanning code.
			atomicWrite(data->stack.detourTo, (Stack *)null);
			callOn->clear();
			throw;
		}
	}

	// Run a function on a particular stack. Like a normal function call, but switches the stack
	// before the call. This is a bit similar to a detour, with the difference that the stack we're
	// using is not supposed to be used for other purposes. Due to this, this operation is slightly
	// cheaper than using the regular detour mechanisms.
	// NOTE: Exceptions do not work on Windows at the time being. I.e., if the called function throws
	// and exception that is to be thrown through this function, we will crash. Currently, we don't
	// need this feature on Windows, so it is fine for now.
	template <class Result, int params>
	Result stackCall(Stack &callOn, const void *fn, const FnCall<Result, params> &fnCall, bool member) {
		dbg_assert(OFFSET_OF(Stack, desc) == sizeof(void *)*2, L"Invalid layout of the Stack object.");
		dbg_assert(OFFSET_OF(Stack, detourTo) == sizeof(void *)*4, L"Invalid layout of the Stack object.");

		byte result[sizeof(Result)];
		stackCallI(&callOn, fn, &fnCall, member, result);
		Result *resPtr = (Result *)(void *)result;
		Result tmp = *resPtr;
		resPtr->~Result();
		return tmp;
	}

	template <int params>
	void stackCall(Stack &callOn, const void *fn, const FnCall<void, params> &fnCall, bool member) {
		stackCallI(&callOn, fn, &fnCall, member, null);
	}

}