[Vm-dev] Materializing BlockClosure's outerContext?
eliot.miranda at gmail.com
Sat Jan 5 03:47:41 UTC 2019
On Fri, Jan 4, 2019 at 5:30 PM Ben Coman <btc at openinworld.com> wrote:
> On Sat, 5 Jan 2019 at 03:08, Eliot Miranda <eliot.miranda at gmail.com>
>> Hi Fabio, Hi All,
>> On Fri, Jan 4, 2019 at 9:11 AM Fabio Niephaus <lists at fniephaus.com>
>>> Hi all,
>>> I'm trying to understand when the outerContext of a BlockClosure is
>>> materialized in Cog. I'm assuming Cog does much better than materializing
>>> the context at allocation time of the BlockClosure, but I wasn't able to
>>> find that out by browsing VMMaker code.
>> Unless Sista is being used then the outer context is always materialized
>> whenever a closure is created. In the StackInterpreter the two methods
>> called by the actual bytecode routines
>> are pushClosureNumArgs:copiedValues:blockSize:
>> and pushFullClosureNumArgs:copiedValues:compiledBlock:receiverIsOnStack:ignoreContext:.
>> You'll see that the first thing pushClosureNumArgs:copiedValues:blockSize:
>> does is ensure the current frame is married, i.e. it materializes the
>> context if it isn't already. In
>> the first thing that happens is the same unless the ignoreContext flag has
>> been set, in which case the outerContext will be nil.
>> In Cog the JIT generates code to materialize as quickly as possible.
>> See CogObjectRepresentationForSpur>>#genGetActiveContextLarge:inBlock:
>> which is sent four times to create four trampolines ceSmallMethodContext,
>> ceSmallBlockContext, ceSmallFullBlockContext, and ceLargeMethodContext.
>> These are used in turn by
>> which is used by
>> which generates the JIT code that parallels the StackInterpreter bytecodes.
>> Some rationale:
>> In VW there is no adaptive optimization and so no closure4 inlining.
>> Instead there are three different kinds of blocks:
>> clean: created at compile time, no copied values, only arguments, and
>> hence no need for an outer context. If in a clean closure in a debugger
>> there is no information as to where the closure was activated; only its
>> static method name is known.
>> copying: created at run-time, but since there is no up-arrow return there
>> is no need to create an outer context. If in a copying closure in a
>> debugger there is no information as to where the closure was activated;
>> only its static method name is known.
>> full: created at run-time; requires the outerContext to be materialized
>> When I came to add closures to Squeak (good in itself but also essential
>> in implementing a sane context-to-stack mapping scheme) there were only 8
>> unused bytecodes, and two of these were already being used in a Newspeak
>> implementation I had affection for. Qwaq wanted to keep things as simple
>> as possible, as did I. Therefore the logical thing to do was to only
>> provide closures that always had an outerContext; KISS. Implementing
>> closures used 5 bytecodes (create closure, create indirection vector,
>> push/store/pop indirect), leaving three to spare (at this time I had no
>> idea about a Sista bytecode set or about multiple bytecode sets). Knowing
>> that at some stage adaptive optimization would be a much better approach
>> than simply micro-optimizing closure creation, with all the extra
>> complexity and infidelity in the debugger, and that I could optimize
>> materialization aggressively, I think I made the right decision. We can
>> still implement the equivalent of clean blocks in the compiler (and indeed
>> someone has done this in Pharo, and with full blocks it would be easy to do
>> in Squeak). But much more interesting is to finish Sista/Scorch. To this
>> end I'm currently frustrated by not being able to load Clément's tonel
>> Scorch repository into Squeak.
>> Why do I want too be able to load Sista in Squeak right now? (Forgive me
>> if I've already told you this). Clément has been developing Scorch (Sista
>> is the name for the overall architecture, Scorch is the name of the
>> image-level optimizing compiler) in a live Pharo image. That means any
>> bugs crash his system and progress is slow. But the simulator can be
>> modified to intercept the counter callback and instead of delivering it
>> into the image being simulated can deliver it to Scorch in the current
>> image. The simulator can provide "facade" proxy context objects for
>> contexts in the simulation. These appear to be contexts, but are actually
>> proxies for objects in the simulation (we do the same for methods so we can
>> use InstructionPrinter, StackDepthFinder et al on methods in the
>> simulation). And we can rewrite the back end of Scorch, the part that
>> installs methods into method dictionaries, to use a mirror object. Then we
>> can substitute a mirror that materializes a method in the simulation and
>> invokes code in the simulation to install the method there-in.
>> So this allows Scorch to be developed as intended, in the current image,
>> but have it affect only the simulation, and therefore be immune from
>> crashing the current system. This should speed up productization a lot,
>> and will allow Sophie and I to work on register allocation in the Sista
>> So any energy anyone can put into getting Scorch to load into Squeak
>> would be much appreciated.
> What is the work breakdown required for this?
Basically get the following to work in 64-bit Squeak trunk. For me none of
the Scorch load attempts work.
(Smalltalk classNamed: #Metacello) new
repository: 'github://j4yk/tonel:squeak'; "Loads Jakob's squeak branch"
githubUser: 'clementbera' project: 'Scorch' commitish: 'master' path:
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Vm-dev