No emitted bytecode relies on Continuation being stored in local 0
anymore. Stop using local 0 for this purpose and compute offset
to the Continuation at JIT time. 16 bytes of memory freed.
At this point all locals of Continuation construction wrapper share the
same indices with their respective locals of Continuation body, which
should allow further optimizations.
This diff renames the Tracelet -> RegionDesc conversion mode to
"legacy" (since it's going away eventually) and changes "tracelet" to use the
new region selection mode. It attempts to select a region that will be the same
length as what Translator::analyze would come up with, using HhbcTranslator for
all of the type flow logic. It generates longer tracelets in some cases due to
more precise type information. Once this new mode is no longer a perf
regression it can become the new default, replacing all the code in
Translator::analyze and the "legacy" region mode. This version doesn't support
inlining or tracking of known Func*s; those will come in later diffs.
This diff creates IRTranslator, which creates and uses an
HhbcTranslator to implement the translate* methods. It can be used
independently of Translator or TranslatorX64 (it isn't yet but my next
region compiler diff uses it). I also moved a bunch of methods out of
inappropriate classes and changed the type guard/assert methods in
HhbcTranslator to use RegionDesc::Location instead of Transl::Location
and fixes a local tracking issue in translateRegion.
For PhpFiles, there was a mixed management system, where references from
translated code were held until the code was made unreachable, while
references from interpreted code were held for the duration of the
current request. Under the new scheme, PhpFiles are always treadmilled.
They are owned by the FileRepository, and so need to be ref-counted
because the FileRepository can have the same PhpFile under multiple
paths. But we don't ref-count the *uses* of PhpFiles anymore.
Classes still need to be ref-counted, but as soon as their Unit
goes away, most of their internals can be freed. We just need to
hold onto them if derived classes are referencing them. Even in
that case, the next time we try to instantiate the derived class,
we can kill any that reference this Class.
There were also lots of holes where references were not dropped,
or owned data structures were not destroyed. eg a Class's methods
were not destroyed when the Class was destroyed; there were
several paths where an entry was erased from the file map, but the
corresponding PhpFile was not decRef'd - or worse, a null entry
was left in the map (something we had asserts to check for).
This tries to make the handling more consistent.
Added IR opcodes to perform MIter* instructions in JIT. Added IterBreakV bytecode
operation to break out of multiple loops containing iterators. Emitter and assembler
were modified to support such use.
Updates continuations to allow yielding of a key-value
pair from a generator. Adds bytecode instructions (PackContK,
ContKey) for using the new feature, and adds IR instructions
(ContUpdateIdx, ContIncKey) to help get it down to the metal
(in particular, ContIncKey attempts to keep the current use-cases
as fast as possible).
This diff removes the Marker opcode, replacing it with a BCMarker
struct in each IRInstruction. This gives us fewer redundant lines in IRTrace
dumps and allows for more straightforward control of which IRInstructions are
associated with which bytecodes. I took this opportunity to do some more
cleanup of ir dumps as well, and it's now possible to interpOne every codegen
punt.
PackCont opcode is always followed by ContExit so let's join them into ContSuspend. ContResume counterpart may come later (replacing ContNext/Send/Raise/Enter).
Continuation's m_received field is used to transfer values and
exceptions to the Continuation by send() and raise() methods. It has a
valid value only for a short duration of time, between
ContNext/ContSend/ContRaise and UnpackCont opcodes, when no other
operations could possibly occur. Let's free these 16 bytes of memory and
pass the value thru the VM stack.
To achieve this goal, ContEnter was modified to accept a value to be
transferred on the stack. The existence of the value on the stack is
then acknowledged by the UnpackCont opcode, which is the first opcode
executed after ContEnter enters the continuation body.
ContNext then becomes a trivial Null and is thus removed, ContSend just
teleports the value from local 0 to the stack (I will experiment in a
follow up diff with replacing ContSent by CGetL+UnsetL). ContRaise has
to update the label, but the eventual plan is to enter into unwinder
directly from the raise() method.
Add ContCheck opcode that moves away responsibility of checking
Continuation status from Cont{Next,Send,Raise} opcodes.
This check needs to run outside of try/catch in next()/send()/raise()
methods and moving it to a separate opcode lets us merge
Cont{Next,Send,Raise} with ContEnter.
This was going to be easy, but then it wasn't. The existing
interpOne relied heavily on the outputs of NormalizedInstruction, and
those are only populated by code that we want to kill soon. It also
didn't properly deal with bytecodes that wrote to more than one local,
or more than one stack cell. So the bulk of this diff is rewriting
interpOne to not rely on the NI outputs, then it was simple to hook it
into the region translator. I also cleaned things up so we don't
attempt to translate instructions that have no hope of succeeding; we
just interp them on the first try now.
This diff stops the region translator from punting on
instructions that may be prepped by ref (FPass*) or Tracelets with
reffiness guards. It increased coverage and exposed a few more
bugs. The only significant one was that some Tracelets depend on type
prediction for their length, so I had to hook it into translateRegion
to avoid generating worse code (or punting).
Because stronger types are better types, and this will make
future refactoring easier. I considered trying to purge the Opcode
type from the codebase too but that would be a much bigger project.
C++11 cleanup (clean up easy enums)
This is for runtime/base/... and ended up touching a lot of files
because it turns out we have a lot of reasonably behaved enums.
This converter enables much more thorough testing of the
region translator. It currently passes all tests, though it does punt
on one or more Tracelets in roughly 1/6th of them. The two big
unimplemented features for the whole pipeline are interpOne (should be
pretty easy) and parameter reffiness checks (probably
nontrivial). I'll attack those in separate diffs next.
I got stuck while trying to kill the `Transl` namespace, but these were the 'by-hand' changes I did before I got stuck. They get us closer so I think doing them will be helpful regardless.
Most were making longer names, but I also had to kill `Immed` (since there was another `Immed`in the other namespace). Originally I renamed it, but since them someone killed the last use of it.
This diff adds a very, very basic region translator. Together with
-vEval.JitRegionSelector=method, it is capable of translating very simple
methods without using a Tracelet. It takes in a RegionDesc struct and creates
NormalizedInstructions on the stack to drive the translate* methods in
irtranslator.cpp. I started trying to get all tests passing with
JitRegionSelector=method (by replacing lots of asserts with punts) but decided
it's not worth it right now.
I'm planning on writing a Tracelet -> RegionDesc converter next and expanding
translateRegion to handle everything that throws at it.
specialized the IR instruction CGetM/SetM/IssetM for Vector and Map. IR now generates specialized code in those situation similar to what is done with Array.
This is a bunch of cleanup I've done for my work on the
region translator that isn't strictly releated to the region
translator.
- Move irTranslate* methods up to Translator and rename them
translate*.
- Remove a bunch of friend declarations from TranslatorX64.
- Remove emitVariantGuards. We don't translate pseudomains so it was
never doing anything anyway.
- Remove the unused REQ_BIND_REQUIRE.
I was going to #include translator.h in a header I had for
talking to the region selector thing and decided to just get this over
with instead. (It shouldn't need to #include that.) Found a few
other unused things to remove while at it.
Previously it returned a bool to say whether or not it had
succeeded, but always initialized the iter. The other iterators
branch on failure.
This adds the branch target which brings it closer to the other
iterators, and avoids the need to do a (pointless) CIterFree on
the failure path just to keep the validator happy.
I've also added a translation for it.