Since variable break/continue is gone, we don't need this jonx anymore,
since the target of any break or continue is statically known. The
regular break/continue handling deals with this case appropriately.
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.
When object support was first added to HHVM, a class named "Instance"
was introduced (deriving from ObjectData) to represent instances of user
defined classes. Since then, things have evolved and HPHPc and HPHPi have
been retired, and now there really is no needed to have ObjectData and
Instance be separate classes anymore.
This diff moves all of the functionality from the Instance class to the
ObjectData and removes the Instance class. In the process, I got rid of
a bunch of dead methods and fixed some indentation and other style issues.
When object support was first added to HHVM, a class named "Instance"
was introduced (deriving from ObjectData) to represent instances of user
defined classes. Since then, things have evolved and HPHPc and HPHPi have
been retired, and now there really is no needed to have ObjectData and
Instance be separate classes anymore.
As a first step towards merging ObjectData and Instance together, this diff
puts their definitions in the same .h file and puts their implementations
in the same .cpp file. A few small changes were necessary to fix issues
with cyclical includes: (1) Repo/emitter related parts of class.cpp and
class.h were moved to class-emit.cpp and class-emit.h; (2) the contents of
"vm/core_types.h" was moved to "base/types.h"; and (3) a few functions that
didn't appear to be hot were moved from .h files and the corresponding .cpp
files.
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).
After a run command, breakpoints in systemlib did not fire because systemlib.php does not get reloaded. Now get the run command to reapply the breakpoints. Also fixed the caching of the source of systemlib.php to not check for the debugger flag before the flag has been set. Finally, fixed a race condition where compiling a string/file to a unit will fail to update the repo with the unit because another thread has already written a unit with the same hash to the repo. In such cases, the losing unit is unable to retrieve source information because that only lives in the repo.
PackCont opcode is always followed by ContExit so let's join them into ContSuspend. ContResume counterpart may come later (replacing ContNext/Send/Raise/Enter).
Replace NameDef with a new struct of runtime-resolved typedef
information. This needs to include more than Class* or Typedef*,
because we might have nullable type aliases, or a non-nullable alias
to a nullable typedef, or vice versa. Switch to the new
TypeAnnotation stuff in TypedefStatement instead of just strings so
support for this isn't weird (shapes are outside of this for now
though---see the hack in parser.cpp). Also fixes support for type
aliases to mixed.
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.
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.
Adds support for checking ?Foo type hints in VerifyParamType.
The parameter must have type Foo or null. Failing to pass the hint is
reported as a warning instead of a recoverable error for now for
migration reasons---we'll want to convert it to be the same as normal
type hints later.
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.
I noticed that directorty structure of hphp/system was a bit scattered, so
I consolidated things to reduce the total number of folders and to put
related things together with each other.
This diff moves the contents of "hphp/system/classes_hhvm" into
"hphp/system", it moves the contents of "hphp/system/lib" into
"hphp/system", moves "hphp/idl" to "hphp/system/idl", and moves the
contents of "hphp/system/globals" into "hphp/system/idl".
This stuff almost is an abstraction layer, but it's in a
strange place. Also, the layout of TypedValue isn't something we've
been using through an abstraction layer, and if we want to later I
think we won't want to do so using this one.
This is gone as of Zend 5.4: as far as I can tell, anything other than a
positive integer literal is a parse error (including constants, "1 + 1",
etc.) Let's get rid of it. The mere fact that this construct ever
existed in any programming language is deeply horrifying.
This lets us get rid of all the goofy code that subtracts 1 from the top
value on the stack, does IterFree if needed, and jumps to the next
level. Now, we can hardcode the necessary IterFrees and do a single
jump, right where the break/continue actually is.
The error message for using a non-integer expression is less helpful
than Zend's (Zend says "non-constant operand not supported"; ours is
"unexpected T_VARIABLE" or whatever). It wouldn't be that hard to do in
our parser, if we think that's helpful. I don't think it matters,
though.
The value of m_feMap is never used. Keys are used to assert when there
is an attempt to define a function with already existing name. It does
this job poorly because it is not an authoritative source of existing
function names. When the top-level function is defined, setCached() is
called, which already checks for duplicates, so let's rely on it.
This reverts commit 2e9677b7c3f37e9627b9cbc9a6ddec82a10e7215.
Third time is the charm. I hid it from reflection, but I missed `get_class_methods`.
The diff betweenn this and what was reverted is https://phabricator.fb.com/P2217891 and then I did https://phabricator.fb.com/P2217904 because it looked like it should be done.
We were using BuiltinSymbols at runtime to identify
potential FCallBuiltin sites. Instead, we can lookup the Func*,
which already has all the information we need.
Save 8 bytes of m_args and its initialization for Continuations without
func_get_args() call (does not save real memory due to 16-byte alignment).
Store variable arguments in optional local.
I need to walk a live eval stack, handling FPI regions and
generators, and duplicating that logic in yet another place seems
wrong. This makes the Stack::toString stuff use a reusable one---at
some point I'll see if the unwinder can use it as well, but it works
also for my use case. Also, Stack::toString was broken for mutable
array iterators---fixes that. And use a union now for struct Iter.
And don't include bytecode.h from func.h.
EmitterVisitor::m_methLabels is used for 2 purposes:
- avoid emitting generator body twice
- fatal at the import time when file contains already defined function
The labels themselves are not used as labels, comments suggests it used
to be used for fast calls.
Replace them with 2 dedicated sets: m_generatorEmitted flag for generator bodies, m_topMethodEmitted for functions.
After Variant::Variant(NullInit) was made explicit, passing
Variant::nullInit to a function expecting CVarRef, or Variant
would actually call Variant(0), with ensuing hilarity.
Make NullInit an enum class to prevent such issues.
runtime/eval is a relic of a bygone era. As long as we're cleaning up
our directory structure, let's move FileRepository (the only remaining
thing in runtime/eval/runtime) to where it makes sense.
runtime/eval still contains the debugger, which would probably make more
sense as runtime/debugger, but I don't want to throw a wrench in the
works for @mikemag and @hermanv unnecessarily.
This was barely a demonstrable win in sandbox mode when I first wrote
it and it's not even used in hhir. It's probably been bitrotting and is causing
crashes for some people. Time to say goodbye.
Functions like array_filter and array_map need "withRef" semantics,
and while it can be simulated in php via copy-on-write, doing so
is very inefficient.
This adds
SetWithRefLM
SetWithRefRM
- similar to SetM but binds the value if it was a reference. L reads a local, R reads a return value
WIterInit
WIterInitK
WIterNext
WIterNextK
- essentially the same as the corresponding opcodes without W, but the value local is set by reference if the array element was a reference.
Will be needed for array_filter/array_map etc
This sets things up so that if we define a builtin in systemlib, we rename
the corresponding c++ builtin with the prefix __builtin_, so its still available
(in case the php builtin wants to delegate some edge cases, and to make
it easy to run comparisons between the php and c++ implementations).
Also did a little reorganization to get rid of Func::isPHPBuiltin,
and use an Attr to identify functions as builtins. C++ builtins can
still be identified by checking the Func::info() method. This is needed
to allow builtin methods defined in php (such as array_map) to lookup their
arguments in the correct context.
Closures and generators are really hard to reason about in backtraces.
For generators, I took the exact name of the method and put ##$continuation##. I put it at the end so it reads exactly like a method name since in WWW we use them almost the same as the method itself.
For closures, I named the class ##Closue$Class::method#num## where num is an optional autoincrementing number.
I decided to stop prefixing the methods with ##0## which is breaking the reflection tests.
This basically redoes D782498 and D750608 but it works in repo mode.
If the original function has a variable that the generator does not,
we create a varenv. Its not clear that that should ever happen, but
it *was* happening because:
- closures get a magic variable called 0Closure, but generators
from closures did not.
- unused parameters didnt get put into the variable table, so
generators with unused parameters got a varenv
The Func*'s in the native func unit are all persistent, which means
that we can strip them, and skip the Unit::merge call on every
request. But we didnt set the flag to compact the unit if the only
things that needed stripping were Func*'s. Fixed that, and also fixed
it so all the builtins are marked persistent even in non-repo-auth
mode (funcs are not if rename function is enabled, because we implement
fb_rename_function by swapping target cache entries).
I'm committing my work on HphpArray in bite-sized pieces for easier review. This piece replaces calls to NEW with a factory method. There are many problems with operator new, starting with the fact that the allocator cannot communicate properly with the constructor.
The newly introduced factory method should return ArrayData but that causes many issues right now, so I left that step to a future diff.