113 karma · joined July 3, 2011
https://blogs.msdn.microsoft.com/larryosterman/2004/11/08/ho...
[1] https://github.com/lewischeng-ms/sscli/tree/master/pal/unix
[2] https://github.com/lewischeng-ms/sscli/blob/adbd6bbad0816f65...
1. The memory that holds the resource. 2. The resource itself.
C++ RAII lets you control the lifetime of both. In a GCd language, the GC takes control over (1) but can't, over (2). Instead it gives you the ability to do 2 yourself (much like C++ does using custom destructors) using finalizers. Due to the way a GC works though, it is hard to be able to say when (or in the context of which thread) your finalizer would run. Now, the GC does what it does so it can guarantee that you are never able to hold a pointer to something that some other part of your application has deemed dead. While it is impossible to take over (1), you could imagine a world where (2), in a GCd environment is still up to the programmer, and is exposed (say) as a language destructor. In the presence of such a feature you run the risk of committing errors such as (say) closing a socket twice - but it isn't much different from say, code calling a poorly implemented Close (IDisposable) on an object twice.
The CPU doesn't know about the persistence of local state in that it doesn't know (in this case), the significance of anything that is being pushed onto / restored from a frame around a call. It knows that a "PUSH R9" writes the value of R9 onto the region in the stack being currently pointed to by the stack pointer (RSP). It however doesn't know that this is being done because, the current frame has a live value in R9, which, per the ABI, the function being called is allowed to trash, as it is considered a volatile, callee saved register. Like I'd said earlier, these are just agreed upon conventions that might even change across compilers.
I'd used the term "naked" the way the VC++ compiler uses it. A "naked" function is one without a prolog or an epilog [2].
[1] https://pdos.csail.mit.edu/6.828/2008/readings/i386/LGDT.htm
1. As you'd pointed out, the language in question might not let you generate certain instructions. For instance how do you express LGDT in C? You can't. You'd instead write it in assembly (or inline assembly) and expose it to the C world as a function (or in a compiler that supports it, an intrinsic) that it can call.
2. A CPU's understanding of state is defined around the notion of registers and memory. A programming language however exposes a higher level abstraction. For instance, a function call in C is an abstraction that defines both transfer of control (which the CPU knows about) and persistence of local state (saving and restoring registers, stack pointer etc., which the CPU knows nothing about). This is called the ABI and is merely a previously agreed upon convention. Higher level languages (say Java) are able to provide richer abstractions than merely an ABI as their "agreed upon conventions" are defined at a much higher level than in terms of a CPU (registers and memory). Java, for instance even defines a virtual architecture in terms of which facilities offered in the language are defined. User code written in one of these higher level languages depends on these facilities being available to them at any time. This is what makes it unsuitable for writing certain sections of OS code. For instance, the CPU expects the OS to save and restore register state around an interrupt handler. If said handler was written in C (as a function) though, it'd expect its first six arguments in certain registers etc. - conventions, the CPU knows nothing about. You can think of the CPU as exposing its own, simple ABI which can only be implemented by writing certain sections of code in assembly (This is not entirely true though, as one might be able to mimic something like this in certain compilers, especially C compilers, that let the programmer write "naked" function bodies and custom prolog / epilog code). This is also why most parts of the OS, that don't directly interact with the CPU, can and are written in a higher level language. For e.g. The Singularity OS by MSR was written in C# and assembly.
[1] https://github.com/Microsoft/ChakraCore/blob/7587147fac16654...
[1] http://research.microsoft.com/en-us/projects/singularity/ [2] https://en.wikipedia.org/wiki/Bartok_(compiler)
Optimizing code written in a dynamically typed language is a pretty well understood problem (now) thanks to the SELF research at SUN and more recently the V8 Javascript engine. Both VMs employ type profiling at runtime to figure out what the compiler should assume the type of a dynamically typed variable should be. It can then emit code that treats a variable like it always has the profiled type - like a C++ compiler would. When such an assumption is broken at runtime, implementations typically fallback to an unoptimized version of the code (V8) to execute the rest of the continuation. Well written code is expected to achieve type stability pretty fast making the fallback overhead insignificant.
Chakra uses the bottom most bit to distinguish SMIs from pointers.