How is stack-allocated data in the "middle" of the stack accessed? - stack

Consider the following pseudocode:
x = 10
y = 20
print(x)
print(y)
For the sake of argument, let's say that x and y are allocated to the stack in the order they appear. That is, our stack looks something like this:
y: [20] <- stack pointer
x: [10]
---- <- stack origin
In order to print (i.e. access) x, we first need to pop y off the stack, peek at x, and then push y back on. In between popping and pushing y, its value needs to be temporarily stored somewhere other than the stack. We can't simply discard y, since we need to print it later.
More generally, if we want to access a value that's N bytes below the stack pointer, we need to temporarily store those top N bytes somewhere in case they need to be accessed later.
My question is, how is this done in practice? While we are accessing a value in the middle of the stack, where is all the data on top stored?

Related

What do the square brackets and numbers mean in Lua's documentation?

What does the [x, y, z] section mean in the Lua docs? You see it on every C function.
For example, lua_gettop says:
int lua_gettop (lua_State *L);
[-0, +0, –]
Returns the index of the top element in the stack. Because indices start at 1, this result is equal to the number of elements in the stack; in particular, 0 means an empty stack.
What does [-0, +0, –] mean?
The [-0, +0, –] section tells you how that function manipulates the Lua argument stack. There's an explanation in the Functions and Types section, but their wall of text is a bit hard to parse. I'll summarize.
Given:
[-o, +p, x]
Those elements mean:
o: how many elements the function pops from the stack.
mnemonic: - because it reduces the size of the stack.
-0 means it pops nothing.
p: how many elements the function pushes onto the stack.
mnemonic: + because it increases the size of the stack.
+0 means it pushes nothing.
Any function always pushes its results after popping its arguments.
the form x|y means the function can push or pop x or y elements, depending on the situation;
? means that we cannot know how many elements the function pops/pushes by looking only at its arguments. (For instance, they may depend on what is in the stack.)
x: whether the function may raise errors:
- means the function never raises any error;
m means the function may raise only out-of-memory errors;
v means the function may raise the errors explained in the text;
e means the function can run arbitrary Lua code, either directly or through metamethods, and therefore may raise any errors.

erlang has no shared memory. So what happens with the sum function for example?

Erlang has no shared memory. Look at the sum function,
sum(H|T)->H+sum(T);
sum([])->0
So
sum([1,2,3])=1+2+3+0
Now what happens? Does erlang creates an array with [1,1+2,1+2+3,1+2+3+0]?
This is what happens:
sum([1,2,3]) = 1 + sum([2,3])
=> sum[2, 3] = 2 + sum([3])
=> sum([3]) = 3 + sum([])
=> sum([]) = 0
Now sum([3]) can be evaluated:
sum([3]) = 3 + sum([]) = 3 + 0 = 3
which means that sum([2, 3]) can be evaluated:
sum([2, 3]) = 2 + sum([3]) = 2 + 3 = 5
which means that sum([1, 2, 3]) can be evaluated:
sum([1,2,3]) = 1 + sum([2,3]) = 1 + 5 = 6
Response to comment:
Okay, I figured what you were really asking about was immutable variables. Suppose you have the following C code:
int x = 0;
x += 1;
Does that code somehow demonstrate shared memory? If not, then C does not use shared memory for int variables...and neither does erlang.
In C you introduce a variable, sum, give it an initial value, 0, and
after that you add values to it. Erlang does not do this. What does
Erlang do?
Erlang allocates a new frame on the stack for each recursive function call. Each frame stores the local variables and their values, e.g. the parameter variables, for that particular function call. There can be multiple frames on the stack each storing a variable named X, but they are separate variables, so none of the X variables is ever mutated--instead a new X variable is created for each new frame, and the new X is given a new value.
Now, if the stack really worked like that in erlang, then a recursive function that executed millions of times would add millions of frames to the stack and in the process would probably use up its allocated memory and crash your program. To avoid using excessive amounts of memory, erlang employs tail call optimization, which allows the amount of memory that a function uses to remain constant. Tail call optimization allows erlang to replace the first frame on the stack with a subsequent frame of the same size, which keeps the memory usage constant. In addition, even when a function is not defined in a tail recursive format, like your sum() function, erlang can optimize the code so that it uses constant memory (see the Seven Myths of Erlang Performance).
In your sum() function, no variables are mutated and no memory is shared. In effect, though, function parameter variables do act like mutable variables.
My first diagram above is a representation of the stack adding a new frame for each recursive function call. If you redefine sum() to be tail recursive, like this:
sum(List)->
sum(List, 0).
sum([H|T], Total) ->
sum(T, Total+H);
sum([], Total)->
Total.
then below is a diagram of a recursive function executing that represents frames being replaced on the stack to keep the memory usage constant:
sum([1, 2, 3]) => sum([1, 2, 3], 0) [H=1, T=[2,3], Total=0]
=> sum([2,3], 1) [H=2, T=[3], Total=1]
=> sum([3], 3]) [H=3, T=[], Total=3]
=> sum([], 6) [Total=6]
=> 6
you're making recursive calls. the scope for every function body is not terminated until it returns something. so the invariable variable H for every call will be kept till the base case happen.
it could be tail recursive with the help of an accumulator in the function arguments, which is lighter on memory by calculating the H part first and then calling the successor recursive and giving the calculated value to the successor as the accumulator.
so in both ways there's nothing used outside of your function scopes.

Lowering memory usage in HashMap in Rust

I'm trying to parse a very long file by using a fixed-size sliding window over it. For each such window I'd like to either insert it to a HashMap as the key with custom struct as value, or modify existing value for the window. My main problem is memory usage, since it should scale into very large quantities (up to several billions of distinct windows) and I want to reuse existing keys.
I would like to append windows (or more specifically bytes) to a vector and use the index as a key in the HashMap, but use the window under index for hash computation and key comparison. Because windows are overlapping, I will append only the part of the window which is new (if I have an input AAAB and size 3 I would have 2 windows: AAA and AAB, but would only store 4 bytes - AAAB; windows would have indices 0 and 1 respectively), which is the reason behind not keying the HM with window itself.
Here's the simplified pseudo-code, in which I omitted the minimal-input problem:
let file = // content of the file on which i can call windows()
let vec = Rc::new(RefCell::new(Vec::new())); // RefCell allows me to store Rc in the hashmap while mutating the underlying vector
let hm: HashMap<KeyStruct, ValueStruct> = HashMap::new();
for i in file.windows(FIXED_SIZE) {
let idx = vec.len();
vec.borrow_mut().push(i);
if hm.contains_key(KeyStruct::new(idx)) {
// get the key associated with i
// modify the value associated with i
// do something with the key
vec.borrow_mut().pop(); // window is already in the vector
}
else {
hm.insert(KeyStruct::new(idx), ValueStruct::new(...));
}
}
I have came up with 2 different approaches: either modifying the existing HashMap implementation so that it works as intended, or using a custom struct as key to the HashMap. Since I would only use one vector in order to store windows, I could store a Rc to it in the HashMap and then use that for lookups.
I could also create a struct which would hold both a Rc and index, using it as a key to the HashMap. The latter solution works with a vanilla HashMap, but stores a lot of redundant Rcs to the same vector. I also thought about storing a static pointer to Rc and then get Rc in unsafe blocks, but I would have to guarantee that the position of the Rc on the stack never changes and I'm not sure if I can guarantee that.
I tried to implement the first approach (custom HashMap), but it turns out that Buckets use a lot of features which are gated, and I can't compile the project using the stable compiler.
What's even worse is that I would like to get the key that is already in the HashMap on a successful lookup (because different indices can store the same window, for which the hash/cmp would be identical) and use it inside the value structure. I couldn't find a way to do this using the provided API for HashMap - the closest I get is by using entry(), which can contain an OccupiedEntry, but it doesn't have any way to retrieve the key, and there's no way to get it by unsafe memory lookups, because documentation on repr() says that the order in structs is not guaranteed in the default representation. I can store the key (or only the index) in the value struct, but that adds yet another size_of::<usize>() bytes per entry, only to store the index/key in a reachable manner, which is kept with that entry either way.
My questions are:
Is it possible to compile/reuse parts of std::collections which are not pub, such that I could modify few methods of HashMap and compile the whole project?
Is there any way of getting the key after successful lookup in the HashMap? (I even found out that libs team decided against implementing method over Entry which would allow me to get the key...)
Can you see any alternative to solutions that I mentioned?
EDIT
To clarify the problem let's consider a simple example - input ABABCBACBC and window size of 2. We should give index as a key to the HashMap, and it should get the window-size number of bytes as window starting from that index: with vector [A, A, C], index 1 and window-size 2 HashMap should try to find a hash/key for AC.
We get windows like this:
AB -> BA -> AB -> BC -> CB -> BA -> AC -> CB -> BC
First pair is AB, we append it into the empty vector and give it an index of 0.
vec = [A, B]
hm = [(0, val)]
The next pair is BA:
start with vec = [A, B]
using algorithm not shown here, I know that I have a common part between last inserted window (AB) and current window (BA), namely B
append part of the window to the existing vector, so we have vec = [A, B, A]
perform a lookup using index 1 as the index of window
it has not been found so the new key, val is inserted to HashMap
vec = [A, B, A]
hm = [(0, val0), (1, val1)]
Next up is window AB:
once again we have a common part - A
append: vec = [A, B, A, B]
lookup using index 2
it is successful, so I should delete the newly inserted part of window and get the index of the window inside vector - in this case 0
modify value, do something with the key etc...
vec = [A, B, A]
hm = [(0, val0_modified), (1, val1)]
After looping over this input i should end up with:
vec = [A, B, A, B, C, B, A, C]
and indices for pairs could be represented as: [(AB, 0), (BA, 1), (BC, 3), (CB, 4), (AC, 6)]
I do not want to modify keys. I also don't want to modify the vector with the exception of pushing/popping the window during lookup/insertion.
Sidenote: even though I still have redundant information in this particular example after putting everything into vector, it won't be the case while working with the original data.

How to pop Nth item in the stack [Befunge-93]

If you have the befunge program 321&,how would you access the first item (3) without throwing out the second two items?
The instruction \ allows one to switch the first two items, but that doesn't get me any closer to the last one...
The current method I'm using is to use the p command to write the entire stack to the program memory in order to get to the last item. For example,
32110p20p.20g10g#
However, I feel that this isn't as elegant as it could be... There's no technique to pop the first item on the stack as N, pop the Nth item from the stack and push it to the top?
(No is a perfectly acceptable answer)
Not really.
Your code could be shortened to
32110p\.10g#
But if you wanted a more general result, something like the following might work. Below, I am using Befunge as it was meant to be used (at least in my opinion): as a functional programming language with each function getting its own set of rows and columns. Pointers are created using directionals and storing 1's and 0's determine where the function was called. One thing I would point out though is that the stack is not meant for storage in nearly any language. Just write the stack to storage. Note that 987 overflows off a stack of length 10.
v >>>>>>>>>>>12p:10p11pv
1 0 v<<<<<<<<<<<<<<<<<<
v >210gp10g1-10p^
>10g|
>14p010pv
v<<<<<<<<<<<<<<<<<<<<<<<<
v >210g1+g10g1+10p^
>10g11g-|
v g21g41<
v _ v
>98765432102^>. 2^>.#
The above code writes up to and including the n-1th item on the stack to 'memory', writes the nth item somewhere else, reads the 'memory', then pushes the nth item onto the stack.
The function is called twice by the bottom line of this program.
I propose a simpler solution:
013p 321 01g #
☺
It "stores" 3 in the program at position ☺ (0, 1) (013p), removing it from the stack, and then puts things on the stack, and gets back ☺ on top of the stack (01g). The # ensures that the programs finishes.

Run-time Stack of C code

I don't know if the title of my question is right, but I'm studying run-time stacks and I have the following C code:
int main() {
int a, b, c , x;
a = 4;
b = 5
c = 6
x = func(a, b, c);
return;
}
int func(int x, int y, int z) {
int p, q, r;
p = x*x;
q = y/z;
r = p + q;
return r;
}
This is compiled and loaded in location x3000.
I'm dealing with simulated computer called lc3. I need to find out how the run-time stack would look when this code is executed. My understanding of the topic is too limited in order to actually solve this, but here is how I think it should look:
x0000
(I don't know how the return should look either)
(Assignments that I don't know how to interpret)
r
q
p
main's frame pointer
Return address to main
Return value to main
x a
y b
z c
(I don't know the assignments should look in the run-time stack)
x
c
b
a
xEFFF
I hope someone can offer me some clarity in this subject. Thank you in advance.
Ok, this all depends on the ABI you are using. If it is anything similar to SystemV x86 Abi (the one in 32-bit linuxes). It should look like what you have described. (I have modified my answer to match what the wikipedia describes for LC-3)
first of all, you reach main(), and have 4 local variables, each of one is an int. (Assuming each int is 4 bytes, and stack aligned to 4 bytes), they will be stored in:
0xEFFC: a
0xEFF8: b
0xEFF4: c
0xEFF0: x
Then you call a function, namely func(). The LC-3 abi says that the parameters must be passed on the stack, from rigth to left:
0xEFEC: z --> c
0xEFE8: y --> b
0xEFE4: x --> a
Then you should save space for the return value, put the return address, and save your R5:
0xEFE0: Return value
0xEFDC: Return address to main
0xEFD8: Space for R5
Local variables again:
0xEFD4: p
0xEFD0: q
0xEFCC: r
On modern systems, the return value can be passed in registers (like EAX). It depends on your ABI where to pass it. Probably it can be returned on the stack too.
Another thing is that each function can create an stack frame, pushing into the stack the parent's Base Stack Address, and assuming their stack starts from that address.
You should probably have a document in where all these things are defined.

Resources