We had two similar-but-different functions for getting a notification from the VM about an exception. Cleaned that up by using the proper one for a thrown exception where appropriate, and moving the old one into a hook (like the other VM->debugger hooks) specifically for error messages.
When we get an UPLOAD_ERROR_C, record the filename and the size
as usual.
I've not been able to test this - I can't get a partial uplaod,
even by quitting from firefox during the upload. I seem to either
get a full upload, or nothing at all.
The code for reading in the personalized debugger options, always wrote out the file to account for the case where there may not be a file in the first place. This is not necessary and can lead to the file being changed when running various kinds of debugger tests. Since the tests use a checked in file, it is not desirable for the file to change as a result of a test run. With this change, the file will only be written out when it is missing in the first place. There are still some scenarios where it is possible to write a test that will change the file. Currently no such tests exist. Also, in those scenarios, the test may well want to verify that the file is changed, so more work will needed later on. Right now, that can wait.
Currently the debugger config file is always expected to be at ~/.hphpd.hdf, except when the debugger is controlled via the API, in which case the API client can specify the path. With these changes the path can now also be specified via the command line. Also, the test runner has been modified to look for an hphpd.hdf file and specify the path to it as a command line option. If present, this file also indicates that tests in the directory must be run in debugger mode, making the .opt files redundant. Note that it is important for tests to be able to control the contents of the config file since debugger output is controlled by it and tests will be brittle unless the config is part of the suite and not controlled by the user running the tests
For converting Transl -> JIT. We either do this or convert all the other `Trace` calls to `HPHP::Trace` which seemed worse. This also niecly mirrors `IRInstruction`.
A precursor to moving the Transl namespace to JIT. We have an IR opcode `Call` and this would conflict. Those should probably be in another namespace, but this is easier.
This was way easier to do in a compiled language :)
There were multiple issues with flow control when exceptions occur. Fixed these by ditching the reliance on the exception thrown interrupt and introduce an exception handler interrupt, which indicates control is about to pass to a catch clause. This gives us much better insight into how execution is flowing and how we might need to adjust an in-flight stepping operation.
The debugger prompt string depends on user/machine specific configuration settings, which makes its inclusion in expected test output problematic. There is already an option in (the user controlled) ~/.hphpd.hdf to turn off the prompt. Now there is an option in normal config files to do the same.
Users of m_localsOffset used this offset to calculate pointer where
local variables starts. Since they are stored in the reverse order, the
equation was:
cont_ptr + m_localsOffset + num_locals - local_id - 1
We are already storing pointer to ActRec (m_arPtr), which is equal to:
cont_ptr + m_localsOffset + num_locals
This diffs kills m_localsOffset and uses m_arPtr to simplify
calculations. Continuation fields were rearranged so that
sizeof(c_Continuation) is reduced by 16 bytes.
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.
Contains some structures to use for communicating between
compilation region selectors and the JIT. For now includes two
debugging-oriented region selectors, one that uses a single HHBC
opcode at a time, and one that blindly pushes in the whole CFG for a
method using the Verifier::GraphBuilder.
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.
The assembler recorded the offset to FPI regions based on the
stack depth before the instruction executed. This is trivially wrong
for instructions like FPushCtorD, but also breaks in nested FPI
regions. The assembler is tracking fdescDepth independently of the
eval stack, so as long as we continue to require that all FPush* ops
logically push the ActRec *after* all their other pops and pushes,
this fix should work. It might be nice to some day reword the
bytecode.specification stuff to include ActRecs as part of the eval
stack, though, so it isn't ambigious which order they happen for the
FPIEnt offsets.
Each closure instance carries its own set of static variables. Multiple
generators created using the same closure instance should share their
static variables.
This was not the case and static variables in closure generators behaved
like normal local variables. Let's fix it by referencing closure and
using its static locals.
Pointer to the closure is located in the local following original input
arguments. These are shifted by one, as Continuation occupies local 0.
This also frees 8 bytes from c_Continuation (or 16 if you count 16-byte
alignment).
m_obj in c_Continuation is redundant. It is only used at the time
Continuation is created. First, it is set in init() call. Few
instructions later, it is read so that $this in the Continuation's
ActRec can be populated.
Kill it.
nvSet() only casts the value from TypedValue* to const Variant&; do it
at callsites. Inlined array_setm_ik1_v0() and array_setm_s0k1_v0() into
their only remaining callsites in translator-runtime.cpp.
If a continuation in a closure needed a $this variable,
hhir would fail to initialize it, resulting in reads reporting
null.
This didn't come up much, because usually we dont need a variable;
we can typically use This or BareThis. Its only cases where $this
might be passed by reference, or there are dynamic variables that
actually require a local $this.
The in-situ allocation case can be easily detected by checking m_data == m_inline_data.slots. Therefore there's no need for two distinct flags to track current and future allocation strategy.
This is the first results from profiling callsites of
StringData::initLiteral. This diff converts a handful more
string literals to StaticString, removes overloaded Variant
comparison operators (operator==, etc), and avoids
constructing new strings in a few cases in tvCastToString
and tvCastToStringInPlace.
Alerts users that comparators should be in the
style of functions passed to e.g. C qsort (i.e. returning
-1, 0, or 1) rather than STL-style boolean comparators (i.e.
true for less-than).
Throws the aliased class into a target cache slot for the new
name. Handles errors when you try to re-alias a class, but doesn't
restrict a few other cases zend does:
- If you implement an interface twice, zend complains (one of the
alias tests checks this). I tried turning it on, but we violate
it in systemlib currently so I left it off.
- class_alias_014.php does some namespace stuff I don't quite grok.
(@ptarjan let me know what to do if it's easy).
- inter_007.php uses class_alias, but is testing a warning that
happens even with out it. (We don't raise this warning.)
- zend raises a warning if you try to class_alias a non-user-defined
class; I left this out.
We were being too conservative in determining whether to use
the static property cache when accessing a property from outside the
class. In fact we'd never use it in that case, because we required
that the class not need initialization (and any class with static
properties needs initialization!).
We can relax this restriction to just enforce that the class not
define sinit or pinit methods -- scalar properties are fine.
Now that contbuild summaries work, it is so much nicer.
I'm trying to use the property in a child. Either a keep the data around or make the parent's protected.
The codebase had several namespace-level static data definitions and function definitions. Using namespace-level "static" in a .h file is near-always a bad idea, as follows:
- for simple types, static is implied. Example: "const int x = 42;" is the same as "static const int x = 42;"
- for aggregate types, static linkage implies that a copy of the aggregate will appear in every compilation unit that includes the header.
- for functions, static means the function will have a separate body generated in each compilation unit including the header.
- in several places functions were defined 'static inline', which is just as bad. 'inline' is just a hint which means the function may end up having a body (and actually more due to 'static').
True, gnu's linker has means to remove duplicate definition, but that's not always guaranteed or possible (think e.g. static functions that define static data inside, ouch). So static is useless at best and pernicious at worst. We should never, ever use static at namespace level in headers. I will create a bootcamp task for a lint rule.
I expected the performance to be neutral after the change, but in fact there's a significant drop in instruction count and therefore a measurable reduction in CPU time: https://our.intern.facebook.com/intern/perflab/details.php?eq_id=431903
In some circumstances, the label associated with a branch
doesn't get set, and the corresponding branch target ends up pointing
to one byte before the start of the unit's bytecode.
In that case, we were crashing when trying to dump the bytecode.
Func's are allocated using Util::low_malloc, so need to be
free'd with Util::low_free, rather than boost::checked_deleter.
In addition, there is some munging of the Func address going on,
so we really need to call Func::destroy instead.
It's better to have some checks than none. The only checks
failing in systemlib are iterator lifetime things, which it seems like
we're not about to fix. Run the verifier on systemlib but only in
debug builds.
Currently the debugger prints the line where an exception has been thrown, along with the type exception. Then it prints the source listing of the exception. Then it prints a serialization of the exception, which includes a full stack trace. Since the debugger has a command for printing stack traces, the latter bit information seems completely redundant when stopped in the command line client. This diff suppresses the stack trace in that case. It also suppresses redundant diagnostics that get generated during the debugger's attempt to find and print the source code in response to a list command. Finally, the quit command was too eager to let the client die after notifying the proxy, causing the proxy to get a pipe closed exception rather than the quit command, which often allowed the program to carry on running after the client has already quit. The quit command now waits for an acknowledgement from the proxy before shutting down.
- smart::make_unique, returns a unique pointer to smart allocated
data.
- Support forwarding in our allocator's construct, so
smart::vector<foo::unique_ptr<>> works.
- Move smart containers to their own header.
After my rewrite to use the FunctionnEnter hook to implement
intercept, there was a potential problem.
If an intercept handler was intercepted, and we hadn't yet jitted
the prolog for the intercept handler, and we lost the race to jit it,
and the intercept handler threw an exception, the unwinder could skip
some c++ frames, and fail to unwind a re-entry.
This was caused by attempting to emulate the previous intercept
behavior, where the original function is not included in the backtrace.
I don't think thats necessary; for one thing, the intercept handler
has always appeared in the backtrace, even though its (generally) not the
replacement function, but a function that forwards to the replacement
function. So this diff just leaves the original function's fraem in place.
If the backtraces *do* turn out to be problematic, I'll fix it later in
debugBacktrace.
Add reasonable behavior for stepping within continuations (generators). Stepping over a yield now does what one would expect. When the generator is driven from a C++ extension like ASIO, the next logical execution point is after the yield statement, and that's where we'll stop now. When driven from PHP, say in a loop calling send(), the next execution point is in fact the call site of send(), so we go there. Stepping off the end of the generator function, goes to the caller of send(), or the caller of the C++ extension. Stepping _out_ of a generator driven by a C++ extension ensures that we go to the caller and not back into the generator again. The logic for both cases is exactly the same. The difference comes from the fact that we don't actually debug C++ extensions.
This also fixes a long-standing problem where breakpoints would interfere with control flow cmds on the same source line. This caused funny behavior, like taking multiple steps to get off of a breakpoint.