1819 Commits

Autor SHA1 Mensagem Data
Sara Golemon ee8da60efa Releasing HipHop 2.1.0 2013-07-12 11:00:55 -07:00
Sean Cannella 61d58af783 fix compilation on Ubuntu 13.04
- missing inline generates warnings on Ubuntu which seems to
make compiler very unhappy

Closes #848
2013-07-11 17:25:02 -07:00
Sara Golemon b010c70f17 Bump gcc required version to 4.6.0 2013-07-11 17:16:13 -07:00
Sara Golemon 86b00778e3 Add skeleton.sh script for making extension skeletons from idl.json files 2013-07-11 16:00:06 -07:00
Jordan DeLong 9584995bec Fix (disable) reporting of extended typehints via reflection
Right now (on trunk, not release), a function with a ?int
typehint tells the reflection API its typehint is just "int".  For
now, just turn this off.  (If we want this later we'll probably have
to add a new API or something?)
2013-07-11 15:12:09 -07:00
Jordan DeLong da32bc9d88 Turn off extended type hint checks 2013-07-11 15:12:06 -07:00
Eric Caruso fa04bcb180 Trace declared instance properties of objects
Instance properties were being completely ignored,
so the heap graph was missing a lot of information.
2013-07-11 15:11:13 -07:00
Eric Caruso b94ab7709f Translate FPushFuncU
We were punting on this, but it's a pretty easy
translation, and it makes calling functions from inside namespaces
much faster.

Closes #814
2013-07-11 15:11:13 -07:00
Sara Golemon a2139988d0 Update url_raw_encode() to ignore '~' characters
Per Bug#53248, tilde characters should
not be encoded.
2013-07-11 15:11:12 -07:00
mwilliams 47970e99d7 Fix url rewriting
Only apply pathTranslation if a path hasn't been rewritten
(they're always relative paths), or if the rewritten path
didn't begin with '/'.
2013-07-11 15:11:12 -07:00
Sara Golemon ca02e9e482 Update php_base64_decode() to cover Bug52327
Strict mode should fail on padding characters mid-stream.
2013-07-11 15:11:12 -07:00
Mike Magruder 3a750ae5ac Add client connect info to the debugger usage log.
Update the connect usage log message to include details of the client that is connecting to a proxy, or to state if it's a connection due to script debugging.
2013-07-11 15:11:12 -07:00
Guilherme Ottoni 244d4da93a Replace _ with - in file names under runtime/vm/jit/
Makes things more consistent, at least within this directory.
2013-07-11 15:11:11 -07:00
mwilliams 01b67654a6 Revert "Fix duplicate HTTP headers"
This reverts commit e265247f34572eedd087ee01c8e43bdab319b322.
2013-07-11 15:11:10 -07:00
Jordan DeLong d2c4442980 Translate some trivial cases of IncDecL
These are easy, so why not.
2013-07-11 15:11:09 -07:00
Jordan DeLong 524cbb5d3e Implement shift operators outside of Variant 2013-07-11 15:11:09 -07:00
Jordan DeLong dec333dd14 Implement most bitwise arithmetic outside of Variant
Everything except unary bitwise not.
2013-07-11 15:11:09 -07:00
Jordan DeLong 049e1d585e Remove Variant unary negation and unary plus @override-unit-failures
These are only used for constant folding in the frontend.
Change stuff to do it there the way we actually implement them at
runtime.
2013-07-11 15:11:09 -07:00
Sara Golemon f9da9970d2 Pass OS determination from CMake into gen-ext-hhvm.sh 2013-07-10 20:25:50 -07:00
Sara Golemon bd88f6bccd Explicitly link libjemalloc into folly 2013-07-10 20:25:50 -07:00
Sara Golemon a2a9f88dd8 Don't double / file paths, it confuses poor CMake 2013-07-10 20:25:50 -07:00
Sara Golemon ccb3060ae9 Test's cpp files are moved to hphp/test/ext
Also create missing test_ext.inc
2013-07-10 20:25:32 -07:00
Guilherme Ottoni b64942b1f3 Move hopt_preparable.php to test/vm-perf
The goal of this benchmark was to measure performance, so increase the
number of iterations and move it out of test/quick.
2013-07-10 12:22:22 -07:00
Daniel Sloof 948040f7d8 OSX changes, next round
- fix merge issues
- remove platform-specific neo defines that were getting pulled in everywhere
- fix asm alignment directive on OSX
2013-07-10 12:22:18 -07:00
bsimmers 5dd304c0f8 Clean up VectorEffects::init
This is my attempt to clean up and simplify the logic in here
a bit. It also fixes a bug that we were hitting in the region
compiler: setting an element of a StaticStr may promote it to a
CountedStr.
2013-07-10 11:16:53 -07:00
Guilherme Ottoni a4c445dbfb Allow JIT-time known boxed types for source operand in cgCheckType
In the region JIT, we may end up with a CheckType on a source with a
known type that is boxed but different from the boxed type parameter
of CheckType.  We still want to keep such CheckType instruction to
communicate the type of its dest to the following code. However, that
instruction doesn't need to generate any code since the inner types
are checked at the uses (via LdRef).
2013-07-10 11:16:53 -07:00
Mike Magruder d1553bda9e Add simple functions to determine if a debugger is attached
Added two simple functions to determine if a debugger is attached, and to provide info about where the debugger is connected from. Also fixed a minor bug in ext_socket where the name for an unbound AF_UNIX socket would come back from getsocketname()/getpeername() as garbage.
2013-07-10 11:16:52 -07:00
bsimmers 182ced3575 Remove operator==(Op, Opcode) and friends
I added them to ease the transition but since Opcode is just
uint8_t, they remove a lot of the safety of making Op an enum class.
2013-07-10 11:16:52 -07:00
Drew Paroski 84b9d9a3a2 Separate resources from objects, part 1
In HHVM (and HPHPc before it) we've been piggybacking resources on the
KindOfObject machinery. At the language level, resource is considered to
be a different type than object, and there are a number of differences
in behavior between objects and resources (ex. resources don't allow for
dynamic properties, resources don't work with the clone operator, the
"(object)" cast behaves differently for resources vs. objects, etc).

Piggybacking resources on the KindOfObject machinery has some downsides.
Code that deals with KindOfObject values often needs to check if the value
is a resource and go down a different code path. This makes things harder
to maintain and harder to keep parity with Zend. Also, these extra branches
hurt performance a little, and they make it harder for the JIT to do a good
job in some cases when its generating machine code that operates on objects.

This diff prepares the code base for a new KindOfResource type by adding a
new "Resource" smart pointer type (currently a typedef for the Object smart
pointer type) and it updates the C++ code and the idl files appropriately.
This diff is essentially a cosmetic change and should not impact run time
behavior. In the next diff (part 2) we'll actually add a new KindOfResource
type, detach ResourceData from the ObjectData inheritence hierarchy, and
provide a real implementation for the Resource smart pointer type (instead
of just aliasing the Object smart pointer type).
2013-07-10 11:16:33 -07:00
Edwin Smith 46f2eb82a5 Delete some dead code in NameValueTableWrapper and SharedMap 2013-07-10 11:16:33 -07:00
Alexandru Suhan c330882232 Combine IssetM and EmptyM implementations 2013-07-10 11:16:32 -07:00
Jordan DeLong 6e4e52197e Implement +=, -=, *=, /= and %= outside of Variant 2013-07-10 11:16:32 -07:00
Sean Cannella 9bdd5805b3 More OSX fixes
readelf -> gobjdump
folly exclusions
undef GNU_SOURCE
2013-07-10 09:38:34 -07:00
Paul Saab ac91741c0f Fix duplicate HTTP headers
When the same header is passed in, Apache/PHP will comma delimit
all header values for the returned values in apache_request_headers
and $_SERVER['HTTP_*'].
2013-07-09 13:45:41 -07:00
Guilherme Ottoni 85f3ccbd01 ContSuspendK should break tracelets
It's a control-flow instruction.
2013-07-09 13:45:40 -07:00
Guilherme Ottoni 679c1a2f99 Fix tools/reduce
The runtime option used by this script was renamed. Also, stop
retranslating as soon as JitGlobalTranslationLimit is reached.
2013-07-09 13:45:40 -07:00
Guilherme Ottoni 1a8d77f1db Allow AssertType of Cls
We need this with the region JIT.
2013-07-09 13:45:40 -07:00
Kyle Delong 772c0cef17 Fix native Exception::setPreviousChain() fatal
Fixes a fatal in native Exception, which is missing parentheses on this method call.
2013-07-09 13:45:39 -07:00
Daniel Sloof d71433a966 get HHVM to compile on OSX
This is a squash of https://github.com/danslo/hiphop-php/compare/osx-review
2013-07-09 13:45:35 -07:00
Dario Russi 54b8a31c6f relax guard change to allow for specialized guards
Unified code for relax and specialize guards and removed type propagation on relaxation
2013-07-09 12:24:22 -07:00
Guilherme Ottoni d4c2b60537 Mark CheckType non-CSEable
It's a control-flow instruction, and we don't support eliminating
control-flow yet.

This got exposed by the region/trace JIT.
2013-07-09 12:24:22 -07:00
Sara Golemon f487b96cf8 Move SessionModule class to ext_session's header
So that other extensions can register their own
Session Modules.
2013-07-09 12:24:21 -07:00
Eric Caruso c3d067f65c Optimize InstanceOfD when rhs is unique interface
We would normally have to load the class and do
a whole bunch of other noise. Now we don't.
2013-07-09 12:24:21 -07:00
Sara Golemon 06da48df2d Modify PHP's ext/standard/math/tests/(pow|abs).phpt to be HHVM friendly
HHVM's arithmetic operators do not promote to double.
Use double-casted LONG_MIN/MAX to track this behavior.
2013-07-09 12:24:21 -07:00
Sara Golemon 65e4672ea1 Update folly 2013-07-09 12:20:45 -07:00
Sean Cannella ce9837db9a emitTLSLoad doesn't work on OSX with emulated TLS
- Provide a TLS solution that works on OSX with __emutls_*
2013-07-08 10:30:58 -07:00
mwilliams 795aa1309c Cleanup lifetime management for translation units
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.
2013-07-08 10:30:58 -07:00
mwilliams f704123389 Retry fsockopen
It only fails very occasionally, so add some retrys

Facbook:

I logged into a contbuild machine where it had failed. 3 out of the 4
runs had actually succeeded. In the one run where it failed,
it was the ssl connection. So I tried running just that 1000 times, and
got no failures. Seems likely that the retries will help.
2013-07-08 10:30:58 -07:00
mwilliams bc5778169e Fix a DateTime leak
D860568 fixed a double free, but introduced a leak. If no
timezone is specified in the input string, timelib_fill_holes
would clone the one from m_time. Since we unconditionally cloned
*that* into m_tz, the clone from timelib_fill_holes was leaked.

The contract seems to be that m_time doesn't own it's tz_info, but
that it should be owned by a smart pointer somewhere. So we can tell
timelib_fill_holes *not* to clone the tz_info from its second parameter,
and at the same time optimize for the usual case where that timezone
is already the current timezone.
2013-07-08 10:30:57 -07:00
Drew Paroski d336b46cc7 Merge ObjectData and Instance together, part 2
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.
2013-07-08 10:30:57 -07:00
Edwin Smith 5b512b77b6 Devirtualize nvGetCell()
ArrayData::nvGetCell was only called from one place in vectortranslator.cpp
so hand-inline it there using nvGet(), which is already virtual.
2013-07-08 10:30:57 -07:00
Drew Paroski 9edc07112b Merge ObjectData and Instance together, part 1
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.
2013-07-06 11:12:29 -07:00
Edwin Smith 29b1fb3cf0 Consolidate more ArrayData methods: getKey, getValue, and nvGetValueRef
getKey wraps nvGetKey
getValue and nvGetValueRef wrap getValueRef
2013-07-06 11:12:29 -07:00
Jordan DeLong 59b2a173d2 Fix varCopy 2013-07-06 11:12:29 -07:00
Jordan DeLong 7be051d7e6 Check key types for KindOfInt64 instead of using isNumeric 2013-07-06 11:12:29 -07:00
Jordan DeLong 42bab0c57f Remove unused ArrayData param for setWithRefHelper
Mark said this used to do something related to avoiding a
recursive array, but I don't quite understand it and it's unused now.
2013-07-06 11:12:28 -07:00
mwilliams 0b0741103e Set proper timeouts for SSLSocket
If no timeout was specified in fsockopen, we passed in 0.0,
which was then used as the actual timeout, meaning that while the
socket opened, it almost always failed to open in ssl mode due to
timeout, and then read garbage data from the socket.

We also failed to pass in the specified timeout for non-ssl sockets,
but there we did use the default timeout rather than 0.0. I've changed
that to use the passed in timeout instead.
2013-07-06 11:12:28 -07:00
mwilliams 8f6224d194 Fix cfi directives in enterTCHelper
Right now, if you don't have gdb symbols enabled for
jitted code, its impossible to get a backtrace in gdb that
crosses enterTCHelper (I'm not entirely sure why it works when
symbols *are* enabled, but still).

With the .cfi directives brought up to date, a gdb backtrace
walks across enterTCHelper just like any other function.
2013-07-06 11:12:28 -07:00
Paul Bissonnette 0d5d5bca72 Added IterBreakV, MIter{Init,InitK,Next,NextK,Free} and fixed memory tracking bug.
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.
2013-07-06 11:12:28 -07:00
mwilliams 083b1d32ad Fix SpillStack's argument validation
It was asserting that the input to a SpillStack is
a subtype of one of Gen, Cls or None, rather than subtype of
Gen|Cls or None.

Added a new type Type::StackElem, and used it.
2013-07-06 11:12:27 -07:00
mwilliams fa0d20a58a Don't hang if socket fails to open
feof($f) returns false if $f is invalid, so if the
socket failed to open we spun forever, causing the tests to
eventually timeout. The test will still fail, but at least
we get meaningful results for the rest.
2013-07-06 11:12:27 -07:00
Jordan DeLong 5371743d9d Convert tv_comparisons/tv_conversions by-pointer TypedValue/Cells to by value
If we're not going to mutate the Cell, it might make sense to
pass it by value rather than pointer to const.  Do folks like this
better?  I can see a couple arguments various ways.  But it does seem
like even if we want to pass it by pointer at the hardware level we
would ideally passing by const reference at the language level, so
this choice would be transparent at callsite code.  This diff doesn't
change anything in tv_helpers.h for now.
2013-07-06 11:12:27 -07:00
Kyle Delong 9108d3523d XHP comment syntax
XML comment syntax for XHP is one of the top wishlist items within the UIE group (+ some other people).

Currently, the only way to have comments inside XHP blocks is to use expressions and block comments, e.g.

  <div>{/* comment */}</div>

After this change, you can use the more familiar syntax. This syntax is limited to XHP child contexts:

  // Only single-line, doc, block comments work outside XHP
  $xhp =
    <div>
      <!--XML comments only work within XHP children contexts-->
    </div>;

Based on http://www.w3.org/TR/REC-xml/#sec-comments - except we ignore the rule about double hyphens ('--') within a comment because we don't care about SGML.
2013-07-06 11:12:26 -07:00
Drew Paroski 1ee3810e21 Small cleanup for ObjectData and a few other things
This diff addresses most of the diff review feedback from D740016.
2013-07-06 11:12:24 -07:00
mwilliams 8075c39588 Fix incorrect assert
An assert was recently added that every local in the
origFunc was also a local in the genFunc, but its not necessarily
true. Also fix the usage to not corrupt the ActRec in this case.
2013-07-06 11:12:23 -07:00
mwilliams a61c47e801 Fix refCounts for SetM on strings
When we throw an InvalidSetMException, we need to incRef the value we
throw.
2013-07-06 11:12:23 -07:00
Stephen Chen d4de02ba16 Get rid of Synchronized<hphp_hash_map> from service_data
We can get rid of all the lock contention by using
tbb::concurrent_hash_map. Unfortunately tbb::concurrent_hash_map doesn't let us
iterate over it while we concurrently do inserts. Work around this limitation by
keeping a copy of all the counter keys in a concurrent_vector which does let us
concurrently insert and iterate.

On lookup / insert, we first look into concurrent_hash_map for the key. If key
already exists, return the value. Otherwise, we insert into both the map and the
list.

On export, we iterate over the list and look up each key from the map.
2013-07-06 11:12:23 -07:00
Eric Caruso 6eba57f898 Make func_get_args and friends work with namespaces
func_get_args would only return declared parameters
when used inside of namespaces. This allows it to work correctly
in that case.

Closes #832
2013-07-06 11:12:23 -07:00
Mike Magruder f4bed8899a Initialize all fields of Static{Result|Exception}WaitHandle
We force users to use the create() methods of StaticResultWaitHandle and StaticExceptionWaitHandle, which properly set m_resultOrException. However, deserialization will use the normal constructor which was failing to initialize the field. The destructor, then, would operate on random data. This broke hphpd when a stack trace had one of these objects on it somewhere. The 'where' command would succeed, but the next command (which deletes the stack trace), would segfault in the wait handle's destructor.

I think it's fair to not serialize this member. It's not exposed thru PHP except via joining with the wait handle, and I think an argument can be made that it's just plain wrong to join with a deserialized copy of a wait handle. So I've just initialized it to a reasonable default.
2013-07-06 11:12:22 -07:00
Stephen Chen fd5d218e8e HPHP: Drop the request when it's been sitting on the select queue longer than the virtual host timeout allows for.
Drop the request when it's been sitting on the select queue longer than the
virtual host timeout allows for. This is orthogonal to the expiration timeout on
the queue itself.

This can be useful if we ever allow select queue timeout to be configured to be
higher than the virtual host request timeout.
2013-07-06 11:12:22 -07:00
Stephen Chen bacd44b43f Add runtime options for fb303 server.
Add runtime options for fb303 server. These go into the open source tree, but
masked off by #ifdef FACEBOOK.
2013-07-06 11:12:22 -07:00
Scott MacVicar 14125f4b06 Allow \ in the LHS of the hdf config file.
The autoload_map.hdf doesn't support backslashes when it's on the LHS.
This broke an intern build last week when we pushed out namespace
support for third-party.

Looked like:
```functions {
  GlobalNamespace\Class = flib/intern/third-party/test.php
}```
2013-07-06 11:12:22 -07:00
Dario Russi ef99ac3445 Allow parameter promotion in constructors
Extend PHP to allow constructor paramters to be promoted to fields. Reduce plumbing of class declaration and helps productivity.
2013-07-06 11:12:21 -07:00
Edwin Smith 047ef325bb Consolodate ArrayData position-based iterator methods
Implement these all in ArrayData, using iter_begin, advance,
rewind, and iter_end virtual methods.  Only SharedMap didn't
override the iter_* methods, so moved ArrayData's implementation
to SharedMap and tailored it a bit.  Fetch SharedMap's size at
construction time to avoid calls to SharedMap::vsize().
Removed HphpArray and NameValueTableWrapper implementations of
these methods.
2013-07-06 11:12:18 -07:00
Curran Kaushik 43c35ba61c Scrape logs for information on completely processed HLog files.
First step towards detecting skipping of HLogs. Scrapes the log files in
the directory given by env variable LOGS_HOME and extracts the
timestamp, filename, and final offset from the lines indicating a file
'IS REALLY complete'. Converts to data to JSON to be passed to later
subprocess.
2013-07-06 11:12:18 -07:00
mwilliams b2f7473aeb Fix var_export for resources
Debug builds hit an assert, and release builds would output
something like array(}.
2013-07-06 11:12:17 -07:00
Sean Cannella f0443bba23 more OSX warnings
- fix more OSX warnings
2013-07-06 11:12:17 -07:00
Eric Caruso 24a131117f Improvements to graph dumping in heap trace command
This abstracts the file format a bit, so that we can
dump to multiple formats. Currently, GraphViz and GML are
supported. GML was added at @edwinsmith's request (and it's much
nicer than GraphViz anyway...)
2013-07-06 11:12:17 -07:00
Eric Caruso 5c486012c9 Basic heap tracing framework + debugger command
Adds an extension command to the debugger which provides
heap tracing functionality, and adds the framework needed to get
heap traces. The heaptrace command can dump the current heap to the
debugger session or it can save a GraphViz specification to a file.

I'm hoping to add a backend which can put the graph in GML format,
so it can be explored interactively. I also hope at some point to
see this integrated into FBIDE if we can do that.
2013-07-06 11:12:16 -07:00
Edwin Smith 47b1915f07 Remove dead ArrayData::nvGet() functions.
They were dead.
2013-07-06 11:12:16 -07:00
Eric Caruso 8d85957d57 Fixing OpMod emission not to trigger assert in simplifier
If you tried to mod something where the denominator
was cns(0), things would go horribly, horribly wrong.
2013-07-06 11:12:16 -07:00
Sara Golemon deb3366c27 No need to pass ext/standard/versioning/php_sapi_name_variation001.phpt
The expected output is specific to how PHP implements run-tests
2013-07-06 11:12:16 -07:00
Eric Caruso 0a6e1587e9 Special case some bytecode ops in getStackValue
Some bytecode ops, such as CGetL3, would munch the
types of the things on the stack above the new cell that was
pushed because getStackValue assumes all stack outputs from
interpOne are on top of the stack. The result is that the top
of the stack would contain the output type, and the two things
below it would not get any type (unknown).

This usually isn't a problem, but if we fail enough in type
prediction we might get around to InterpOneing these ops.
2013-07-06 11:12:15 -07:00
Eric Caruso 11dc9d091d Remove problematic VectorTranslator assert
Tried to relax this assert in D871843, but it turns
out the assert is completely unnecessary anyway.
2013-07-06 11:12:15 -07:00
Edwin Smith eb56802c97 Add missing include to fix stacktrace_profiler.h
Broken build fix.
2013-07-06 11:12:15 -07:00
Mike Magruder cb8d51fd2a Enable Ctrl-C while looping only in translated code
The debugger relies on hooks into the interpreter to gain control of threads. If a thread is looping in translated code, though, it will never enter the interpreter. Take advantage of the existing surprise checks emitted on back-branches to pop out of translated code back to the interpreter when trying to interrupt threads due to a Ctrl-C from the client.

Also modified TestDebuggerJit to ensure that the thread executing the infinite loop has time to settle into looping in TC's. The signal to interrupt the server is historically fast enough to get there before one of the translations is made. Added a reasonable delay which caused the test to fail deterministically on my machine before the fix.
2013-07-06 11:12:14 -07:00
Edwin Smith 1532dd8597 Add BoolProfiler and IntProfiler clases (using StackTraceProfiler)
A BoolProfiler uses two StackTraceProfilers to take profiled samples of
a boolean value.  At shutdown it prints the %false, %true, and a profile
for each case.

An IntProfiler is similar, but profiles buckets of 0, 1, 2, 4, and 5+.
2013-07-06 11:12:14 -07:00
Sara Golemon 93f5ec9d67 Don't import tests from php-src:ext/spl/examples
These don't test anything relevent
2013-07-06 11:12:14 -07:00
mwilliams 52b914a4c9 Fix type assertions for array-like interfaces
Without this we could infer that an array was an object,
skip the guards, and then die horribly.
2013-07-06 11:12:14 -07:00
mwilliams db29a1127c Disable code coverage for systemlib.hhas
It has no line number information.
2013-07-02 11:46:28 -07:00
Todd Nowacki 485b0b88b2 Minor Fixes for Clang
While these fixes are mainly for clang, they should (for the most part) prevent possible bugs.

The implicit conversion function has been deleted. The explicit conversion function should be used
~~~hphp/runtime/ext/ext_apc.h
~~~hphp/runtime/ext/ext_domdocument.h
~~~hphp/runtime/ext/ext_hash.h
~~~hphp/runtime/ext/ext_icu_ucnv.h
~~~hphp/runtime/ext/ext_image.h

Char is not standardized to be unsigned, this should be explicit
~~~hphp/runtime/ext/filter/sanitizing_filters.cpp

The C++ Standard does not allow for default arguments in lambdas
~~~hphp/runtime/vm/jit/hhbctranslator.cpp
2013-07-02 11:46:27 -07:00
Stephen Chen 92279b2fc6 HPHP: add mechanism to add hooks around server start.
Add mechanism to add hook around server start. Similar to the existing
Thread/Process Init/Fini hooks. This allows us to add behaviors around the main
hphp server start/stop event without introducing source code level dependency.
2013-07-02 11:46:27 -07:00
Jordan DeLong 361df7eb45 Convert tvSet family to take TypedValues by reference
Turns out I need to use tvSet with temporaries.  Also removes
unused tvSetObject*, and replaces some tvSetNull* callsites with using
make_tv temporaries.
2013-07-02 11:46:27 -07:00
Keith Adams acb01dde5d Make ServiceRequest more flexible.
As part of the relocatable assembly work, I'm going to need to
be able to hook places we burn in values for a*.code.frontier. One of
the more important sets of these places is in the bind* service request
stubs, but the infrastructure surrounding them is all about
undifferentiated constants.

So, add a type-aware layer of translation between the arguments to
emitServiceReq and actual code emission. This solves one code problem
we'd been papering over: needing to transmit the value of the condition
code from the request site in an argument.
2013-07-02 11:46:27 -07:00
Eric Caruso d0e49bb0f0 Add some easy simplifications for OpMod to simplifier
OpMod wasn't doing any constant folding or optimization,
so this might give it a little boost.
2013-07-02 11:46:26 -07:00
mwilliams 74ca5cd27f fb_enable_code_coverage needs an ActRec
It tries to unwind the top, builtin frame, making
various assumptions that aren't true if it was called by
FCallBuiltin. In dbg builds, it asserts.
2013-07-02 11:46:26 -07:00
Guilherme Ottoni bc667596e1 Fix InterpOne's output for predicted types
We were always pushing the output type onto the simulated stack,
effectively passing it as an asserted type, even when the type came
from type prediction.
2013-07-02 11:46:26 -07:00
mwilliams f72684f07a Fix spilling bug in linearscan
If we reload a value in an exit trace that was spilled
in the main trace, a comment tells us that we reload it at the
start of the exit trace. In fact the reload was inserted at the
start of the main trace.

Fixed the code to match the comment.
2013-07-02 11:46:26 -07:00
Mirek Klimos 5a98277b6c Replace ContSend by CGetL+CUnsetL
The behavior of ContSend is equivalent to CGetL+CUnsetL. Let's kill this
unnecessary opcode. Let's remove this logic from ContRaise opcode as
well.
2013-07-02 11:46:25 -07:00
Stephen Chen 50b48f1dab Add an option to allow hphp's request queue dynamically switch between FIFO and LIFO.
Add an option to allow hphp's request queue dynamically switch between FIFO and
LIFO. By default everything is still FIFO like today. Setting
ServerThreadJobLIFO to true turns everything to LIFO like today. If
ServerThreadJobLIFOThreshold is also set, then we do FIFO up until the queue
length hits the threshold. Once the threshold is crossed, workers will take
quests from the end of the queue. Once the queue size shrink below the
threshold, we resume FIFO order.

This behavior helps us prioritize newer requests when the server is loaded.
2013-07-02 11:46:25 -07:00
Herman Venter 959d6b5d3d Test conditional breakpoints and re-enable "called from" breakpoints
Added some test cases. Also now permit caller=>func() type of breakpoints. To make this work, I added a method, getCallingSite, to class InterruptSite and use this to walk the stack when checking if a site matches a break point that has more than one function name.
2013-07-02 11:46:25 -07:00
Alok Menghrajani 7a9769a95b Fix HPHP's parser when handling generics
We need to allow any type after the AS keyword, including xhp class names.
2013-07-02 11:46:25 -07:00
Mike Magruder 0d14e585fd Change TERM when running tests with input
In general, a test which gets its input piped in is not really interacting with a terminal like it normally would. Thus, letting it think it has the same terminal as the environment is incorrect. More specifically, hphpd uses Readline, which inspects the TERM env var and based on that and a stunning array of other options will attempt to initialize the terminal with extra control characters on first use. It would be tough to try to control for all of the different options and ensure they're all the same, and honestly testing Readline is not the objective of our tests anyway. Thus, I'm forcing TERM to 'dumb' when a test has input to ensure a) a simple terminal which requires no control characters and b) consistency no matter what environment is present when the tests are run.
2013-07-02 11:46:21 -07:00
Sara Golemon 556b4ac04f Add EastAsianWidth.txt to checked in files 2013-07-02 00:12:49 -07:00
Sara Golemon 8d839ee730 Remove --arg from travis config
hphp/test/run doesn't seem to know what to do with this anymore
2013-07-01 22:21:15 -07:00
Sara Golemon 8a891f617a Make sure fr_FR locale is available during test 2013-07-01 14:09:17 -07:00
Eric Caruso 5d27fbcc69 Promote cns argument to int64_t to ensure correctness
Some operations such as cns(-1) would end up emitting
the wrong thing, because the -1 literal would be interpreted as
int32_t and only four bytes would get copied across by memcpy.
The result is that cns(-1) would in fact emit the constant
4294967295 (= 2^32-1) which is bound to lead to wrong code.

A former workaround involved using cns(-1LL). I removed this
use case to show that this is now kosher (and added a test to
show that nothing broke - use TRACE=hhir:2 to check).
2013-07-01 13:41:04 -07:00
Sean Cannella b1c329a7e1 annotate a few printf stragglers
- Found a few more va_list functions when reviewing last diff
2013-07-01 13:41:04 -07:00
Bert Maher 8257b2b805 Clean up argument order for AKExists
We were passing the array and key parameters to ak_exist_* in
the opposite order from exists(), leading to some unnecessary register
shuffling.
2013-07-01 13:41:04 -07:00
Stephen Chen 82dc4550da A simple facility to track runtime statistics in hphp.
This a simpler / cleaner version of fbcode's ServiceData for hphp. Currently we
support only flat counters, MultiLevelTimeSeries and Histograms. We can add more
stats types later on as needed.

ServiceData is a global entry point for all this stuff. The current idea is to
completely decouple data input and export. ServiceData internally has three
separate maps tracking flat counters, timeseries and histograms. These maps are
wrapped by spin locks and protected by folly::Synchronized.

ServiceData provides three functions to create/retrive counter objects. The
counter objects are thread safe (protected again by spin locks and
folly::Synchronized).
2013-07-01 13:41:03 -07:00
Avani Nandini e61c684271 Update ext_hash test isFacebook() check 2013-07-01 13:41:03 -07:00
Sean Cannella c891ec4d62 annotate printf-like functions
- added annotations to a few more functions
- fixed a few bugs exposed by the annotations
2013-07-01 13:41:02 -07:00
Jordan DeLong 58d58a10cb Add forgotten expect file 2013-07-01 13:41:02 -07:00
Jordan DeLong 819f3877aa Fix trunk due to merge messup
I apparently merged badly and then committed diffs in a bad
order and broke trunk.
2013-07-01 13:41:02 -07:00
Jordan DeLong 6b92028afd Remove base parameter from tvCastToInt64InPlace
Nothing uses it, and it means we can't as easily drop
folly::to for int-string conversions into these guys, which I'd like
to try later.  (Non-base-10 conversions are probably much rarer so
it's fine to have different code, I think?)

Also removes tvCastToInt64 and ports its single callsite to cellToInt.
I plan to move the tvCastTo*InPlace to tv_conversions.h (probably
cell-based functions) in upcoming diffs.
2013-07-01 13:41:01 -07:00
Jordan DeLong ddfce3150e Fix a crash when dividing INT64_MIN by -1 2013-07-01 13:41:01 -07:00
Jordan DeLong c51583cfb8 Functions for basic php arithmetic operators in tv_arith.h @override-unit-failures
Deletes operator overloads on variant for the same and points
bytecode.cpp at them.  Also fixes one known accidental deviation from
zend.  These functions take Cells by value because it seemed to make
sense---I'll likely convert the various functions in the new
tv_conversions.h (and tv_comparisons.h) to do the same but in another
diff.
2013-07-01 13:41:01 -07:00
Jordan DeLong 8220a18060 Convert a few tvFoo functions to take parameters by reference
Since TypedValue::operator= is dangerous, something like
tvTeleport is usually what you want to use, but it doesn't work with
temporary TypedValues (e.g. return values of things like make_tv or
cellAdd), because it took the arguments by pointer.  This also means
we can change it to take parameters by value later without updating
callsites.  This diff does the tvDup family and changes tvTeleport to
tvCopy.  I'll gradually get the other ones done, but I just need these
for now to work with temporaries for changing SetOp to not use Variant
arithmetic.
2013-07-01 13:41:00 -07:00
Eric Caruso 97a23e5ea7 Support for yield k => v;
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).
2013-07-01 13:41:00 -07:00
Eric Caruso d6fd9de236 Push modular division down to codegen
InterpOne sucks. Let's see if we can do this right.
2013-07-01 13:40:59 -07:00
Drew Paroski e7b90fa691 Clean up how the DebuggerDummyEnv is set up and torn down
A recent diff called my attention to the logic in enterDebuggerDummyEnv()
and exitDebuggerDummyEnv() and I noticed it didn't look quite right.

The first time enterDebuggerDummyEnv() is called it creates a frame on an
empty call stack, but then exitDebuggerDummyEnv() does not correctly tear
down this frame and null out m_fp and m_pc, and this leads to subtle issues.
For example, invokeFunc() checks if m_fp is null to decide whether to call
enterVM() or reenterVM(). I found a case with the "flow_gen_excep.php" test
where invokeFunc was incorrectly calling reenterVM (because m_fp hadn't
been nulled out) and it was pushing bogus VM state info into m_nestedVMs.
This in turn was causing the logic in CmdNext::onBeginInterrupt() to get
confused when comparing the original stack depth with the current stack
depth.

This diff updates exitDebuggerDummyEnv() to correctly tear down the frame
and null out m_fp and m_pc, and it updates enterDebuggerDummyEnv() to
assume the callstack is always empty (which should be the case). I've also
beefed up the asserts in both of these methods.
2013-07-01 13:40:59 -07:00
Eric Caruso c498e390da Make continuations cloneable
Continuations would throw before if you tried to
clone them. This restriction has been lifted.
2013-07-01 13:40:59 -07:00
mwilliams 6bd65a5cd6 Fix spilling bug
If we spilled a FuncCtx (pretty unlikely), we treated the class/this
portion as a type, and only spilled/restored the low 32 bits:

   0xb23ad54:    mov    %r13,0x10(%rsp)
   0xb23ad59:    mov    %edx,0x1c(%rsp) # rdx contained a $this pointer
   0xb23ad5d:    mov    %r14,-0x10(%rbx)
   0xb23ad61:    mov    %r15d,-0x4(%rbx)
   0xb23ad65:    add    $0xfffffffffffffff0,%rbx
   0xb23ad69:    lea    (%rbx),%rdi
   0xb23ad6c:    callq  0x33f68f1 <HPHP::assertTv(HPHP::TypedValue const*)>
   0xb23ad71:    mov    0x10(%rsp),%rdx
   0xb23ad76:    mov    0x1c(%rsp),%ecx # restored here
   0xb23ad7a:    movq   $0x0,-0x8(%rbx)
   0xb23ad82:    mov    %rdx,-0x20(%rbx)
   0xb23ad86:    mov    %rcx,-0x10(%rbx) # and written to the new actrec here
   0xb23ad8a:    mov    %rbp,-0x30(%rbx)
   0xb23ad8e:    movl   $0x0,-0x14(%rbx)
   0xb23ad95:    add    $0xffffffffffffffd0,%rbx
2013-07-01 13:40:58 -07:00
Drew Paroski 900dbd0225 Make HHVM's command line parsing closer to Zend
This diff makes some tweaks to how HHVM handles command line arguments
to match what Zend PHP does. This change will allow developers to type
"hhvm foo.php -x" at the command line and "-x" will get passed as an
argument to the PHP application as it would for Zend PHP.

The basic idea is that we detect the first occurrence of either "--" or a
non-option argument. If we encounter "--" first, all subsequent arguments
are passed along to the PHP application (though the "--" token itself gets
swallowed). If we encounter a non-option argument first, that argument
and everything after it are passed along to the PHP application.
2013-07-01 13:40:58 -07:00
Eric Caruso f377180fcf Small improvements on conversion helpers
Added some asserts, took out some unnecessary checks.
2013-07-01 13:40:57 -07:00
Eric Caruso 3d21090118 Move type dispatch of ConvCellToDbl to simplifier
As D867556, but with doubles.
2013-07-01 13:40:57 -07:00
Drew Paroski 28968640bd Remove bogus assert in bytecode emitter
I hit an array on the debug build when I tried to run the following
program:

  <?php
  function f() {
    for (;;) {}
  }
  f();

This diff removes the offending assert since it is technically possible to
have m_maxStackDepth be equal to 0.
2013-07-01 13:40:57 -07:00
Herman Venter a8749c1618 Remove useless change to test/run
Experimental attempt to make sure test output does not contain non ASCII characters is actually completely useless because it sanitizes an integer. Remove it.
2013-07-01 13:40:56 -07:00
Herman Venter 6adc95a975 Replicate debugger eval tests in test/quick/debugger. Take 2.
Ongoing migration of tests to the new infrastructure. The old tests stay in place until we have another way to test the client API.
2013-07-01 13:40:56 -07:00
mwilliams 60a17c5e24 Fix names of closures in pseudoMains
The classes were all called Closure$, with the result that attempting
to instantiate one closure could instantiate a different one.
2013-07-01 13:40:56 -07:00
Keith Adams a0ae83d0fd Introduce rdtsc, cycle delay primitives.
I keep reintroducing these by hand. My workflow is usually:

1. Have an idea to optimize X.
2. Realize I don't even know if X is important or not.
3. Instrument X to slow it down, to see if it makes a difference in
   perflab.

After this diff, 3 is a simple matter of inserting a call to
cycleDelay(1000) (or what have you) in the path of interest.
2013-07-01 13:40:55 -07:00
Jordan DeLong 652f0e7b2a Remove Variant::swap (unused) because TypedValue::operator= is scary
TypedValue::operator= is potentially dangerous when you don't
know where the TypedValue is actually living.  The reason is it copies
the m_aux from the rhs over the m_aux on the lhs, so if your
TypedValue happens to live inside an HphpArray you can apparently
break HphpArray invariants.

Since we still often cast TypedValues to Variants when they live in
HphpArrays, using TypedValue::operator= inside of Variant needs to be
forbidden.  It also is dubious (probably wrong) in any tv_helpers
functions that mutate externally-owned TypedValues.  This particular
function turns out to be dead code anyway.
2013-07-01 13:40:55 -07:00
Sean Cannella c22db0b4be more macosx warnings
- more warnings from macosx OSS
2013-07-01 13:40:55 -07:00
Sara Golemon 252dfe987c Update folly 2013-07-01 13:40:50 -07:00
Herman Venter 4506f32342 Debugging functions in systemlib.php
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.
2013-06-28 11:36:10 -07:00
Herman Venter bca91c8ef3 Really turn off tutorial output this time and re-enable tests that failed because of tutorial mode.
It turns out that Tutorial=0 means "auto" and -1 means "off". With auto tutorials, the hphpd.hdf file got updated and test behavior got flaky. Even worse, the non ASCII characters in the tutorial output broke the test runner in a way that made it look like tests passed when you put up a differential, only to fail in contbuild.
2013-06-28 11:36:10 -07:00
mwilliams bc52150751 Fix encoding of default arguments
Default arguments with escape characters in were being
over escaped. The old idl.php would first eval'd the string, then
serialized the result. The new idl.cpp just serializes the original.

We have to unencode it, then serialize.
2013-06-28 11:36:09 -07:00
Todd Nowacki 6d8999b7c1 Simple HPHP Changes for HPHP with Clang
Some simple changes for HPHP to help make it clang friendly

---hphp/compiler/package.cpp
---hphp/compiler/package.h
---hphp/runtime/ext/ext_curl.cpp
---hphp/runtime/ext/pdo_mysql.cpp
---hphp/tools/tc-print/offline-x86-code.h
---hphp/util/async_func.cpp
---hphp/util/async_func.h
---hphp/util/compression.cpp
---hphp/util/compression.h
---hphp/util/db_conn.cpp
---hphp/util/db_conn.h
  Deleted unused private fields

~~~hphp/compiler/analysis/symbol_table.h
  Static assert had to be outside the union

+++hphp/runtime/TARGETS
  Added clang specific flag to supress unneded declaration warning

~~~hphp/runtime/base/datatype.h
  Use of logical '&&' with constant operand. Added !=0 to remove warning,

~~~hphp/runtime/base/string_data.h
  Static fields cannot be declared in an anonymous struct/union

~~~hphp/runtime/ext/bcmath/TARGETS
  Moved gcc specific flag from preprocessor_flags to compiler_specific_flags

~---hphp/runtime/ext/pdo_mysql.cpp
  Removed unnecessary self asignment for row_count

~~~hphp/runtime/vm/bytecode.h
  Added default return statement

~---hphp/runtime/vm/jit/codegen.cpp
  spillSlotsToSize was unused

~~~hphp/runtime/vm/jit/irtranslator.cpp
~~~hphp/runtime/vm/jit/linearscan.cpp
  The c++ standard states default arguments shall not be specified in the
  parameter-declaration-clause of a lambda-declarator.

~~~hphp/runtime/vm/jit/vectortranslator-internal.h
  Clang had some issues determining the correct cast when these macros were used
  A simple '!= 0' check was added to make things explicit for clang.

~~~hphp/tools/tc-print/perf-events.h
  Added parens to make clang happy

+++hphp/util/asm-x64.h
  The constexpr needed to be initialized

+++hphp/util/base.h
  Clang also supports tr1 libraries

~~~hphp/util/bits.h
  Again, clang had issues with implicit casting to bool.
  added != 0 check

~~~hphp/util/malloc_size_class.h
  Ambiguous operator precedence. Added parentheses.

~~~hphp/util/thread_local.h
  Misspelled function
2013-06-28 10:33:52 -07:00
bsimmers b7d178e674 Eliminate Marker instructions
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.
2013-06-28 10:33:51 -07:00
mwilliams 8f421ab193 Mark registers dirty before entering catch-traces
Otherwise we end up with bizarre stack corruption.
2013-06-28 10:33:51 -07:00
Eric Caruso 9a76c1ebe9 Move type dispatch of ConvCellToInt to simplifier
Currently, CastInt does this all in its HHBC -> HHIR
translation, but this could be improved.
2013-06-28 10:33:50 -07:00
Mirek Klimos eddef7ffc0 Replacing PackCont and ContExit opcodes with ContSuspend.
PackCont opcode is always followed by ContExit so let's join them into ContSuspend. ContResume counterpart may come later (replacing ContNext/Send/Raise/Enter).
2013-06-28 10:33:50 -07:00
Mike Magruder 44ae3c3dac Disable tests which are giving us grief with control chars in their output.
We've got some tests that are giving us control chars in their output on contbuild machines. We haven't been able to repo locally yet. Disabling them for now until the test harness can be improved to avoid crashing in these cases.

Note: this diff will likely go thru multiple iterations as more are uncovered.
2013-06-27 17:36:45 -07:00
Vaishaal Shankar 6f3dfaa4a3 zend comparison mismatch
Changed parts of tv_comparisons so certain comparisons to resource type matches zend
2013-06-27 17:36:43 -07:00
Sara Golemon e76acef302 Restore network newlines to mailparse test files
Match PHP's test-case format
2013-06-27 17:06:58 -07:00
Jordan DeLong 67bf707768 Fixes and improvements for type aliases
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.
2013-06-27 15:14:22 -07:00
Sean Cannella 9849079ee4 fix print flag mismatch build warning on other platforms
- fix mismatch between %lu and uint64_t in printf flags
2013-06-27 15:14:17 -07:00
Edwin Smith 685fe164ae Rewrite get using nvGet()
Profile data shows much heavier use of ArrayData::nvGet(),
nvGetCell(), and exists(), than get().  So rewrite get()
using nvGet().
2013-06-27 13:00:47 -07:00
Herman Venter d074fbef0a Disable tests that fail on contbuild
These tests now seem to fail deterministically on contbuild. Disable them until we figure out why.
2013-06-27 13:00:46 -07:00
Sean Cannella 22c5361a24 redis fixes from github comments
- applying github comment fixes (thanks @staabm )
2013-06-27 13:00:37 -07:00
mwilliams 2c1919505f Allow hhas files to set the MayUseVV flag
If the last parameter is '...', set the MayUseVV flag
2013-06-27 12:59:28 -07:00
Sean Cannella 9dfaa87b44 other platform warning in codegen
- fix noisy compiler warning
2013-06-27 12:59:28 -07:00
Sean Cannella 9aaf5ab743 s_counter should still be defined on non-Linux
- s_counter still needs to be defined somewhere in
NO_HARDWARE_COUNTERS builds
2013-06-27 12:59:14 -07:00
Sara Golemon 7aa06852e4 Copy hhas string rather than attach in HHAS parse_long_string()
buffer falls out of scope and becomes invalid on return.
Copy the string so that it's still usable later on.
2013-06-27 12:12:34 -07:00
Mike Magruder db502d7451 Cleanup 'zend' command a bit
The [z]end command in hphpd runs the last manually entered snippet of php in "zend". If you typed 'z' before actually entering any php, it would segfault. Fixed a minor bug in Process::Exec, and present help if none entered. Also clarified that it will simply use your system's default php, and made it so you can override which exe to use with a hphpd config variable. The default is "php", since that is most commonly used.
2013-06-27 10:50:24 -07:00
Sean Cannella b1cc655364 fix very noisy compile warning on other platforms
- fix compile warning generating a ton of spew
2013-06-27 10:50:23 -07:00
bsimmers 4375db0f05 Fix and reenable test/quick/setprofile_throw.php
Fix a cast from a previous diff, and fix surprise checks that throw
exceptions. I turned the two macros into functions to clean things up; the
important part of the fix is taking out the SYNC() before
EventHook::CheckSurprise(). Before this fix, the saved offset in the ActRec
used for reentry would point at the offset immediate of the Jmp instead of the
Jmp itself.
2013-06-27 10:50:23 -07:00
Jordan DeLong aac60ddb1e Don't tell phabricator about skipped tests in test/run 2013-06-27 10:50:22 -07:00
mwilliams 0632fb3a11 Allow .hhas to specify default values
It only matters for reflection, but hhas parameters with
default values need to specify the text of the string.

In addition, change reflection to report parameters with no
default value string as not having a default value, to avoid
crashing when trying to access it.

Update the "func" parameter of array_filter to have a valid
default. The other uses of defaults in array_map and array_filter
are just to get the proper behavior on too few/too many args,
and don't really correspond to default values.
2013-06-27 10:50:22 -07:00
Mike Magruder 6bf4fb404e Fix flow_gen.php to track https://phabricator.fb.com/D864123
A recent diff broke this test. Fixing it up... the issue was that a codegen change altered the number of instructions in Continuation::send().
2013-06-27 10:50:22 -07:00
Jordan DeLong f828a7af6d Never allow typedefs with the same names as classes
Right now, we allowed it as long as the typedef was for the
same class.  (Oversight.)  This involved a few error message changes
in existing tests.
2013-06-27 10:50:13 -07:00
Sara Golemon c4550d2b24 Fix license header in asio 2013-06-27 10:50:12 -07:00
Jordan DeLong 62dd2e2aae Allow type constraints on opaque type aliases
Allows some syntax that is ignored at runtime; only used
ahead of time by the type checker.
2013-06-27 10:50:12 -07:00
Edwin Smith 89ffdb7a01 Remove uses of BOOST_STATIC_ASSERT
Ow, my eyes!  use static_assert instead.
2013-06-27 10:50:11 -07:00
Jordan DeLong 69768a0836 Remove some unused or mostly unused Variant typedefs 2013-06-27 10:50:02 -07:00
Jordan DeLong 90e73bdf6c Add a cellIsPlausible assertion
Cleans up a few assertions in tv_comparisons and I want to
use it elsewhere.
2013-06-27 10:50:01 -07:00
Herman Venter e9fcf01b3d Encode test ouput before returning it to the test framework
When a test fails hphp/test/run runs a regular expression over the test output and returns it to the python scripts that is running the tests on the continuous build machine. These scripts crash if presented with output that is not printable ASCII, which makes it very difficult to figure out why the test is failing. This change modifies hphp/test/run to first encode the test output with quoted_printable_encode before returning it to the python scripts.
2013-06-27 10:50:01 -07:00
Jan Oravec f0dcca8b29 Kill m_received, transfer values thru stack
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.
2013-06-27 10:50:00 -07:00
Jan Oravec 5b9e01ff47 Do not hold unnecessary reference to sent value
Continuaton::send()/raise() are holding reference to the sent value
while the next iteration is being executed. Do not hold this reference
and teleport values instead.
2013-06-27 10:50:00 -07:00
Sean Cannella 04fc9c6993 fix type declaration build warning on other platforms
- fix type declaration mismatch (long vs. int64_t) on other platforms
2013-06-27 10:50:00 -07:00
Sean Cannella 0a80f93ea4 __assert_util is not defined on macosx
- use the HHVM assert_util implementation on OSX
2013-06-27 10:49:59 -07:00
Sean Cannella 779904e538 fix potentially uninitialized warning on other platforms
- fixes compiler warning about variable that might not be initialized on other platforms
2013-06-27 10:49:59 -07:00
Sean Cannella 84672b7782 fix type mismatch in asio declaration
- Fix declaration of type mismatch that shows up on other platforms
- Fix lint warnings re: 80 characters
2013-06-27 10:49:59 -07:00
Jan Oravec 2a1d59c286 Move Continuation state check to ContCheck opcode
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.
2013-06-27 10:49:58 -07:00
Joel Marcey fc4ed71839 Fix PDO MySQL bug in getColumnMeta()
In trying to get the CakePHP Blog Tutorial to run on HHVM, a subtle bug was found where the table name was not being returned, and, instead, an numeric index was being used. The bug was in PDOMySqlStatement::getColumnMeta (pdo_mysql.cpp). Applying this fix, the flock/fwrite fix (D855470) and the Reflection::SetAccessible (D851647) fix makes the CakePHP tutorial run like a champ.
2013-06-27 10:48:32 -07:00
Mirek Klimos 5d09e8a87c CreateCont opcode cleanup - removing FillContLocals instruction
FillContLocals was used only when num of locals > kMaxInlineContLocals; it doesn't hurt performance to copy them always within hhir.
2013-06-27 10:45:56 -07:00
Sara Golemon a3f507d58d Add reference to extension object to class_map
Add IDL component:
{
  "extension": {
    "symbol": "s_foo_extension"
  }
}

extension.symbol is the C++ HPHP::Extension symbol for the
extension (if one exists and is exported).
2013-06-27 10:45:56 -07:00
Bert Maher bb7dff89d9 Make unit.cpp not take forever to compile
The AtomicHashMap constructor seems to be causing
Unit::GetNamedEntity to take forever to compile in the opt build, so I
moved the initialization out of that function and marked it #pragma
GCC optimize ("O0") to prevent whatever crazy optimization is freaking
gcc out.
2013-06-27 10:39:17 -07:00
mwilliams 07dde58004 Remove a not-yet-true assert
In some circumstances we create unreachable blocks,
making the assert invalid. Currently nothing depends on the
assert being true, so remove it for now.
2013-06-27 10:39:16 -07:00
Edwin Smith ada27dfc01 Use KindOfInvalid instead of KindOfTombstone
KindOfInvalid is -1, so IS_REFCOUNTED_TYPE() == false, which
will allow skipping a few tombstone checks in future array work.
But also, it avoids declaring a magic constant outside the
DataType enum, and sometimes gcc can generate better code for
comparisons with 0 (ie type<0) than it can for 0x62, the value
of KindOfTombstone.
2013-06-27 10:38:23 -07:00
Herman Venter 2bf7800c0d Replicate debugger stack tests in test/quick/debugger
Ongoing migration of tests to the new infrastructure. The old tests stay in place until we have another way to test the client API.
2013-06-27 10:38:23 -07:00
Bert Maher 43d2ed7c7c Add PHP function mapping to stacktrace profiler
Adds translation of addresses to PHP function names using the
map created for perf.
2013-06-27 10:38:23 -07:00
Herman Venter 7b75527b3d Replicate debugger info tests in test/quick/debugger
Ongoing migration of tests to the new infrastructure. The old tests stay in place until we have another way to test the client API.
2013-06-27 10:38:22 -07:00
Mike Magruder 96c7a1ce81 I can haz moar usage logging?
Add a bit more usage logging for the debugger, and ensure that there is a common field between clients and servers thats easy to search on, i.e., sandbox id.
2013-06-27 10:38:22 -07:00
bsimmers 26c74bf8e9 Pass known Func*s through in the region translator
Pretty straightforward, since the hard part of figuring out
when the Func* is known is still handled in Translator::analyze.
2013-06-27 10:38:22 -07:00
bsimmers f928f1b320 Support interpOne in translateRegion
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.
2013-06-27 10:38:22 -07:00
bsimmers d99c6b0c58 Handle parameter reffiness in translateRegion
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).
2013-06-27 10:38:21 -07:00
Jan Oravec 514838183c Kill linking of variable environments
Apparently VarEnv's m_previous is not used for anything. Let's kill its
maintenance and avoid 2 native calls per Continuation
next()/send()/raise() calls.
2013-06-27 10:38:21 -07:00
Sara Golemon 2811e9da94 Implement Redis extension
PHP implementation of Redis
2013-06-25 13:19:10 -07:00
Herman Venter a372e0063c Re-enable debugger tests that were suspected of flakiness
These tests failed on the continuous build server, so we disabled them. Since then many other tests have failed and there is no good reason to suspect these tests of being especially flaky, so we may as well re-enable these tests.
2013-06-25 13:19:10 -07:00
Eric Caruso 4a86eb9f1f Implement EmptyIterator, InfiniteIterator, NoRewindIterator
This makes 14 zend tests happy. It also requires some
real stupidity, but PHP iterators are weird.
2013-06-25 13:19:09 -07:00
bsimmers 683bb8af52 Fix hhvm tests
I messed up rebasing my Op enum class diff
2013-06-25 13:19:09 -07:00
Sara Golemon 70dac3df33 Support .skipif in test/run
Calls the first .skipif file to be found of:
$testname.skipif
./config.skipif
../config.skipif
../../config.skipif
etc...

And skips the test if that PHP file outputs anything.

Also expands $test.opts, $test.hdf, and $test.in to
look in config.* and parents
2013-06-25 13:19:08 -07:00
bsimmers 6d91f8195a Turn HPHP::Op into an enum class
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.
2013-06-25 13:19:08 -07:00
Jordan DeLong 6b891c8331 Support checking option type typehints at runtime.
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.
2013-06-25 13:19:08 -07:00
Jordan DeLong afc51da4c6 Move bytecode.cpp use of comparisons to tv_comparisons functions
Instead of calling into the comparisons.h stuff, call into
the cell/tv functions.  This meant moving more_or_equal and
less_or_equal to tv_comparisons and moving cellToBool out of its
unnamed namespace.  Also replaces the global tv() function with some
make_tv() and make_value() thing---it looked like it was incorrect for
doubles, and since the correct compile-time type for the unconstrained
template parameter essentially depended on the runtime value of the
first parameter it seemed more reasonable to move that to
compile-time, too.
2013-06-25 13:19:07 -07:00
Jordan DeLong f3d2185982 Delete Variant's implicit conversion operators 2013-06-25 13:19:07 -07:00
Sean Cannella 3d0c614b9a convert enums to enum classes, part 3
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.
2013-06-25 13:19:06 -07:00
Jordan DeLong 4d5f36126d Remove equalAsStr (perflab can't detect the optimization)
There is only a single call-site for all of this thing.  I
figured perflab could be the judge on whether to reimplement the usage
in a more reasonable way, or just delete it---looks like option 2 is
good.
2013-06-25 13:19:06 -07:00
Owen Yamauchi dfd9746561 Get rid of NameValueTableWrapper, part 1 of 3
It was used to indirect from an array to a Class's propVec during
86pinit methods, but this isn't a significant technical obstacle.
We now just pass in a regular HphpArray and pull values out of it after
invoking the method.

Part 2 will do the same for 86sinit methods (it's a slightly more
involved change, and I want to keep it maximally broken down for
revertibility). Part 3 will delete NVTW itself.
2013-06-25 13:19:05 -07:00
mwilliams 8ea5b023a8 Fix EnableRenameFunction for tests
The slow tests were supposed to run without it, except when they
explicitly requested it, but test/run always set it on the command line.

This moves it into the default config.hdf, and removes a few cases where
it was explicitly turned off in the slow tests.
2013-06-25 13:19:05 -07:00
Sean Cannella 303ea58976 convert enums to enum classes, part 2
C++11 cleanup (clean up easy enums)

Since sandcastle is failing:
2013-06-25 13:19:05 -07:00
Sean Cannella 4872a71b36 convert enums to enum classes, part 1
C++11 cleanup (clean up easy enums)

Since sandcastle is failing:
2013-06-25 13:19:04 -07:00
Paul Tarjan 506f21c4b5 Allow extension functions to match zend calling convention
Introducing `ZendParamMode` to as a idl flag. We are not consistent with zend on how they do their params for builtins. We cast to the expected data type. They do some checks, and if the checks don't pass they issue a warning and return (usually) `null`. This diff starts us down that path.

I'm introducing the param and using it in the places where we were emulating the calling convention in the `f_foo` functions. I'm going to follow up with converting as many as I can and then eventually this becomes the default. I also want this to be applied to php files in systemlib.

Many of the conversions are from https://github.com/php/php-src/blob/master/Zend/zend_API.c#L305
2013-06-25 13:19:04 -07:00
Sara Golemon fd94725e57 Get rid of runtime/base/hphp.h
This is a vestigal limb of HPHPc
which caused global_variables.cpp to way over-include
by way of runtime/ext/ext.h
2013-06-25 13:19:03 -07:00
Todd Nowacki adda9a5022 HPHP Changes for Clang
More changes for HPHP to help make it clang friendly

~~~hphp/compiler/expression/constant_expression.h
~~~hphp/compiler/expression/function_call.h
  rfind returns a size_t/unsigned int

~~~hphp/runtime/base/server/http_protocol.cpp
  Switched to std::to_string. Assuming [] was not intended here

~~~hphp/runtime/base/ref_data.h
  These fields were accessed in a public manner, assuming public was intended
  instead of private

~~~hphp/runtime/base/variable_serializer.cpp
  Switched to using [] and & to make clang happy. Assuming this was to either
  take or drop the first char.

~~~hphp/runtime/ext/asio/asio_external_thread_event_queue.h
~~~hphp/runtime/ext/asio/asio_external_thread_event_queue.cpp
  Cast  which performs the conversions of a reinterpret_cast is not
  allowed in a constant expression. This is been moved to a macro as a temporary
  fix.

+++hphp/runtime/ext/ext_misc.cpp
  Added std::atomic to supress warnings

~~~hphp/runtime/vm/jit/simplifier.cpp
  Chosen constructor is explicit in copy-initialization

~~~hphp/runtime/vm/jit/translator-asm-helpers.S
  Ambiguous instructions require an explicit suffix
  Changed cmp to cmpl

~~~hphp/runtime/vm/jit/translator-x64-helpers.cpp
  Clang does not support global register variables

+++hphp/runtime/vm/unwind.cpp
  describeFault was only used when DEBUG or USE_TRACE was defined

~~~hphp/runtime/vm/verifier/check_unit.cpp
  Made fmt pointer const to avoid string format issues/warnings

~~~hphp/util/stack_trace.cpp
  Clang does not support variable-length arrays.
  Uniqe_ptr is used instead to take advantage runtime-sized arrays, a
  restriced form of variable-length arrays

~~~hphp/util/thread_local.h
  Clang seems to be supporting the __thread attribute, or at the very least
  it is not complaining about it.

~~~hphp/util/tiny_vector.h
  Clang does not like the flexible array here, since T is not always POD.
  I have reimplemented the array here by just sticking one value in the struct
  and calculating the offset from its address manually.
  Alterinatively, we could change the the non-POD types to be pointers, or
  we could edit their implemenations.

+++hphp/util/util.h
  Created a template for the union,
  A function declared with the constexpr specifier cannot contain
  type declarations that do not define classes or enumerations

+++hphp/runtime/vm/jit/x64-util.h
  Added a TODO
  The way hphp/runtime/vm/jit/x64-util.h is currently implemented, it only
  works if USE_GCC_FAST_TLS is defined
2013-06-25 13:19:03 -07:00
Eric Caruso 533ed5d493 Implement LimitIterator
Implements LimitIterator from SPL.

Closes #788
2013-06-25 13:19:03 -07:00
Paul Tarjan f2b3611f48 increase timeout
scrypt is taking too long, and I think the other tests are having some trouble
2013-06-25 13:19:02 -07:00
Jordan DeLong f56d1fed4e Try not to look up scalar class constants in targetcache
Instead, just check the class is defined and is the class we
expected at translation time (side exiting if not), and just use the
scalar value directly.  If the class is Persistent or a parent of the
current context we don't need to check the Class* either.
2013-06-25 13:19:02 -07:00
Jordan DeLong 21dfaaf50e Various small optimizations for JIT compile time perf @override-unit-failures
While debugging a flib test that times out due to bad
compile-time behavior, I fixed several small sources of bad perf
before giving up on trying to just make things fast enough.  Most of
these came from profiling while the flib test repeatedly compiled a
tracelet with close to 100k SSATmps (it keeps side-exiting and
recompiling).

Details:

  - Waiting until codegen for punting on DefCns made some tracelets
    take really long to compile (when they just consist of a bunch of
    DefCnses).

  - In LinearScan::collectInfo, m_jmps.reset() was the top of the
    profiler (since we do it for each exit trace), and from talking
    with @swtaarrs it seems like it can be just omitted.

  - dce.cpp consumeIncRef was trying to memoize in a way that involved
    creating hphp_hash_sets for each SSATmp; removed that.  (Someone
    should double-check I didn't break the algorithm if possible
    because I didn't quite spend the time to 100% understand it.)

  - dce creates a new StateVector<SSATmp,SSATmp*> for each exit trace
    when sinking.  Since the tracelet in question had a side exit for
    about 1/3rd of the HHBC ops, this was kinda bad.  It's also pretty
    sparse, so I just changed it to a smart::flat_map.

  - Convert WorkList from std::list to smart::list.  (Should maybe be
    smart::deque but I didn't want to test fixing the remove() call.)
2013-06-25 13:19:01 -07:00
Jordan DeLong 60036dcdbf Add smart::flat_map and smart::flat_multimap 2013-06-25 13:19:01 -07:00
Paul Tarjan cf37a18981 Use previous version of script
i accidentally committed the wrong version of the diff
2013-06-25 13:19:01 -07:00
Paul Tarjan 5d695acedb Update timelib and datetime functons to match 2013-06-25 13:18:25 -07:00
Paul Tarjan d0f3c0b8ab use timeout in php
Use a script from http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
2013-06-25 12:22:59 -07:00
bill fumerola 2096cd0acc GenMapWaitHandle - a BlockableWaitHandle that wait for a Map of WaitHandles
add GenMapWaitHandle, a compliment to GenVectorWaitHandle and GenArrayWaitHandle.
2013-06-25 12:22:59 -07:00
Mike Magruder 6e6ebfe8d8 Change hphpd –h option to make it a little easier to use, provide warning when no server specified
People sometimes make mistakes and launch hphpd without connecting to a server, but expect to be in the server environment when evaluating expressions. Modified the –h option to not require a host specification, and default to localhost, so "hphpd –h" is a valid way to launch now. Provide a warning on launch when no args are specified at all warning the user that they're not connected, and giving suggestions for how to connect if necessary. There are reasonable use cases for launching hphpd with no args (so, no connection and no local script to debug) and I didn't want to take those away by automatically connecting to a server at localhost if launched with no args. I'm hoping the warning is sufficiently helpful.
2013-06-25 12:22:59 -07:00
mwilliams 090ca545ff Fix shutdown crashes in xbox/pagelet server
Various code tested to see if xbox was enabled by the
config, but what it really cared about was whether there was
an xbox dispatcher. During shutdown we stop the XboxServer before
the main server, so there's a short window where the XboxServer
is enabled by the config, but there is no dispatcher. If a running
thread tries to run xbox code, it would crash.

Switch the tests to test s_dispatcher and hold a lock, rather than
testing the config.

Fix similar issues with PageletServer, (although we don't currently
shut it down until process exit - I'll post a follow up diff to fix that).
2013-06-25 12:22:58 -07:00
Edwin Smith 8317e1e59e Ensure all static strings come from the same table.
GetStaticString() is now the only way to get a static string,
so enforce it and short-circuit out when asking for an already-
static string.

Add a GetStaticString(data,len) overload and up some dead code along the way.
2013-06-25 12:22:58 -07:00
Dario Russi c9daa2175f Foreach phase1: expose collection types to foreach JIT helper
Create a set of templatized functions for iterator over collection and bubbled them up closer to the JIT entry point for foreach.
2013-06-25 12:22:58 -07:00
Jordan DeLong 7a08c6e6fa Don't put non-Unique classes into the instanceof bitmask @override-unit-failures
We want to throw exceptions if someone does "instanceof Foo",
where Foo is a type alias.  The easiest way to make sure the
instanceof bitmask optimization doesn't get in the way of this is to
not allow it on non-unique classes, assuming this is ok perf-wise.
2013-06-25 12:22:57 -07:00
Jordan DeLong 7d99716399 Beef up type alias mixedcase unit test
Add a few more cases that weren't tested.
2013-06-25 12:22:57 -07:00
Jordan DeLong e08d0ca2b1 Delete a couple functions in ArrayData
If you are dealing with const StringData*'s, they convert to
bools and call CVarRef overloads here.  (I'm sure there's others, and
this conversion for CVarRef should go away soon, but we might as well
have this for now to possibly catch bugs ahead of time.)
2013-06-25 12:22:56 -07:00
Jordan DeLong 1c710536b1 Mark classes with the same name as a type alias as redeclaring @override-unit-failures
If you have an alias named "Foo", and a class named "Foo" in
the same program, we should not be treating instanceof (and probably
other things) as if the class name is unique.
2013-06-25 12:22:56 -07:00
mwilliams fdc153980f Fix typecheck crashes
We didn't fill in the m_namedEntity field for hiphop-only type
hints in non-hiphop mode, resulting in crashes when we tried to
use them.

Regardless of mode, we didn't check self or parent before
checking a non-object parameter, resulting in asserts in
dbg builds and seg-faults int opt builds.
2013-06-25 12:22:56 -07:00
Paul Tarjan cdffeebb97 I was using a binary with the new timelib. Undo the datetime tests
Test Plan: ran zend tests
2013-06-25 12:22:55 -07:00
Paul Tarjan 5d998b32c0 zend test upgrades
* change warnings from `%a` to `%s`. This way, we don't eroneously match more than one line for an error message
* import all the 5.5 tests since it is now official

I checked through all the tests that went from good to bad, and each one is correctly failing. Most of them are from us doing the extension calling-convention wrong.

The only thing to review is the change to `tools/import_zend_test.py`
2013-06-25 12:22:54 -07:00
Paul Tarjan 57c3d0250b remove extra tempname
This fixes the test in travis
2013-06-25 12:22:53 -07:00
Paul Tarjan a75ac9b498 remove duplciated content
I think you double imported this. It is all in `lwp.php`
2013-06-25 12:22:53 -07:00
Paul Tarjan 0b02291c12 make test less specific
some machines say `localhost.localdomain`. Think this is good enough?
2013-06-25 12:22:53 -07:00
Paul Tarjan 63fc74a751 reflection for namespaced constants
In repo mode this does the right thing and returns the right constant, but for non-repo it thinks it is an undefined non-namespace constant. I'll have to do something more hardcore if that starts to matter

While I was in there, I made the correct name for `ReflectionParameter` that was added in 5.4 instead of the draft we copied.
2013-06-25 12:22:52 -07:00
Jordan DeLong 1df58ddcbf Don't set $env 2013-06-25 12:22:52 -07:00
Jordan DeLong 1aa7ad7819 Modify lwp tests that try to run php in a subprocess
Open source continuous integration doesn't have php available
to run.
2013-06-25 12:22:52 -07:00
Mirek Klimos 56ddbc6bd3 CreateCont opcode optimization - avoid unnecessary reference counting.
Continuation argument values are copied to the continuation object and the locals are unset - in this way we don't need to change the reference coutners.
2013-06-25 12:22:51 -07:00
Eric Caruso 463290b8ea Adds decl and decw instructions that operate on registers
Cherry-pick of D851076 which was reverted in the OSS
segfault catastrophe.
2013-06-25 12:22:51 -07:00
Herman Venter 524ada08bc Tolerate output spew generated by the readline library on some machines
It seems that on some machine configurations the readline library has the bad idea of spewing some control characters to stdout. This causes failures in any test that is reading from the command line, which currently only happens in debugger tests. Possibly this behavior shows up on the continuous build machines, so we'll make the expected output provide for this variation, just in case.
2013-06-25 12:22:51 -07:00
Paul Tarjan d3e6ade96f fix all the $_SERVER urls - take 2
I needed to `m_origPathInfo.reset()` in `RequestURI::clear`
2013-06-25 11:42:33 -07:00
Paul Tarjan b9058d036e add SessionHandler
In PHP 5.4 they added this class that encased the callback functions. The difficulty came with needing to fallback to the previously registered session handler.

Closes #792
2013-06-25 11:42:33 -07:00
Paul Tarjan 23c8e35811 make sysdoc.php not write WarningThis
Also, while I was in there I made the script not spew anything on the terminal.

@markw65 `array_filter` doesn't match the signature from php.net. Should it?
2013-06-25 11:42:32 -07:00
Mike Magruder b7d2212723 Remove useless interpreting flag from execution context
We were maintaining a flag that said if we were interpreting on the EC. It was only used in the implementation of hphp_break(), for pretty minimal benefit. I yanked it… it seems fine to me to throw the switch exception if someone steps out of the hard break even if we're already interpreting.

Also yank out a vestige of the previous stepping and breakpoint logic from the dispatch loop I noticed today. I'd previously missed it, but I made a change a while ago to put the state of the last location filter into the hands of the flow control commands. This was unnecessary and should have been removed then.
2013-06-21 16:37:12 -07:00
Paul Tarjan 3cbf137805 small fixes to SplFixedArray
`is_numeric` is a superset of `is_int` and 2 of these tests don't pass until we get Zend calling convention over stdlib.
2013-06-21 16:37:12 -07:00
Dario Russi a94e453dd6 Complete work for CGetM, SetM, FPassM and IssetM applied to collections
Added helper for the remaining collection types, emit guards and call specialized helper for the above opcodes
2013-06-21 16:37:11 -07:00
Eric Caruso 035b3eaff7 Adds word-size instructions to x64 assembler
Retry of D848605 which doesn't segfault the open-source build.
Formerly, this change caused the assembler to emit an opsize
prefix before ret instructions taking a 16-bit immediate, which
worked on our machines but caused problems for Travis CI.
2013-06-21 16:37:11 -07:00
Herman Venter 1197521469 disable flaky test
Fails on continuous build server
2013-06-21 16:37:11 -07:00
mwilliams 9cecd8956a Shut down pagelet server before exiting
There was nothing stopping a pagelet thread from continuing
to run after the server was shut down. If it continued to run after
main exited, it could access data structures (such as the global maps
used by Apc and FileRepository) that had been torn down, and crash.
2013-06-21 16:37:10 -07:00
mwilliams 000eadc430 Read the last commands from a light process
poll can set both POLLIN and POLLHUP. We were checking for
POLLHUP first, which meant we often missed the "exit" command. This
meant the LightProcess would incorrectly report that it was exiting
because it lost its parent, rather than because it was told to exit.

Fixing this so its easier to diagnose what was going on.
2013-06-21 16:37:10 -07:00
Sean Cannella 51ce8d138a remove tx64 dependencies from runtime/vm
Refactor platform-independent/interface methods into translator
so runtime doesn't depend on tx64 directly
2013-06-21 16:37:10 -07:00
mwilliams 679fb61d40 Clear g_procs before closing light processes
Otherwise, the SIGCHLD handler will trigger a server shutdown.
The only time this is bad is when LightProcess::Close is called
from the segfault handler, because it triggers a server shutdown
while we're dealing with the initial crash, which almost always
leads to misleading core dumps.
2013-06-21 16:37:10 -07:00
mwilliams 26396ca0e1 Throw an exception, not a pointer to one
It will probably work better.
2013-06-21 16:37:09 -07:00
bsimmers 8f6c65a550 Add an option to test/run to pass through extra runtime options
This is useful when testing out a new feature that's hidden
behind a runtime option.
2013-06-21 16:37:09 -07:00
Herman Venter b66f8587e8 Disable flaky tests
test/quick/debugger/break1.php and test/quick/debugger/break2.php are failing on the the continuous build machines. Disable these tests while we figure out what is going on.
2013-06-21 16:37:09 -07:00
Mike Magruder e3f34ac774 Don't warn when there is no debugger startup doc
It's perfectly valid to have no debugger startup doc configured for a server. The code was a bit silly in that case.
2013-06-21 11:45:54 -07:00
Herman Venter 52804d5874 Generalize breakpoint matching involving relative paths
Currently a breakpoint specified as relativefilepath:lineno will match only if the relative file path is a simple file name or if sandbox root + relative file path is an exact match. This is now generalized so that matching occurs if the relative file path is a suffix (path) of the absolute path of the execution location.
2013-06-21 11:45:54 -07:00
Sean Cannella e1b843862d runtime/base should not depend directly on tx64
remove dependencies on tx64 for runtime/base (by refactoring platform-independent code into translator)
2013-06-21 11:45:53 -07:00
Eric Caruso f3e34edab5 Match Zend behavior for openssl_pkey_get_{public,private}
We weren't treating array(key, passphrase) correctly.

Closes #815
2013-06-21 11:45:53 -07:00
Herman Venter 026be6adbd Add test case for hitting breakpoint of the form DerivedClass::inheritedMethod
It turns out that this feature already works. Adding a test case to make sure it stays that way.
2013-06-21 11:45:53 -07:00
Mike Magruder 94793b70da Add info about debugger config to our runtime options doc
This is what people need to enable debugging for their servers.
2013-06-21 11:45:53 -07:00
Mike Magruder 4b4123f935 Debugger developer documentation.
Adding some developer docs for the debugger. The idea is to give an overview of the major implementation points so we can refer to them from the source when necessary.
2013-06-21 11:45:52 -07:00
Edwin Smith 5ec269bf85 Fix up style of StaticString declarations.
At the top level of a file, "const" is the same as "static const",
and reduce the stuttering.
2013-06-21 11:45:52 -07:00
Paul Tarjan c56c17e1d1 switch to an extension that is actually used
just 'cause it is in the `facebook/extensions/` dir doesn't mean we use it. I checked this one and it is loaded internally and not open source.
sosorry
2013-06-21 11:45:52 -07:00
Jordan DeLong 3bb3b3df13 Fix ostensive bug in sorting debugger constants
This was doing ref(foo), where foo is an Array.  This will
create a temporary Variant, call the ref(CVarRef) overload, which
casts the temporary to a non-const RefResult, then a temporary
VRefParam is implicitly constructed from this, which creates a
KindOfRef and points the temporary variant at that.  The sort will
operate on this temporary (leading to copy on write, and storing the
new ArrayData* there), so the m_constants field won't reflect the
changes.
2013-06-21 11:45:51 -07:00
Jordan DeLong 811b11711b Put a lid on test_ext for now
Hopefully stops the php file from auto-generating test stubs,
and adds a comment discouraging adding more of them.  For now I'll
stop porting the remaining ones to php: the left over tests mostly
start test servers, except TestExtTao and TestExtServiceRouter.
TestExtTao is kinda big, so I'm skipping it for now, and ServiceRouter
actually tests C++ functions (although it has a lot of use of the
smart pointer API), not extension functions.
2013-06-21 11:45:51 -07:00
Jordan DeLong c65b3bda41 Port TestExtProcess to php 2013-06-21 11:44:42 -07:00
Jordan DeLong efb4b89252 Port TestExtPdo to php
Leaves out the mysql test, which was disabled.
2013-06-21 11:44:41 -07:00
Jordan DeLong edf410ad86 Port TestExtPosix to php
Dropped tests that just called functions and did no testing
of the the result (the probability they'll catch a bug is around
zero).
2013-06-21 11:44:41 -07:00
Paul Tarjan e929e800b5 fix new php tests for open source
This was a pretty bad import into open source :(

https://travis-ci.org/facebook/hiphop-php/builds/8251282

* date tests assumed PDT. I tried putting `date_default_timezone_set("America/Los_Angeles");`. Lets see if that helps.
* options test checked for `phpmcc` which is only a facebook thing
* I'm not sure what is wrong with hash or network, but their output totally masks the real value. Made the tests output their value so I can at least test in prod.
2013-06-21 11:44:41 -07:00
Andrei Alexandrescu a33a4b0b19 PolicyArray: implement NOT_IMPLEMENTED methods
This implements the "last" unimplemented methods in ArrayShell. The sorting-related methods need no implementation because PolicyArray scales to HphpArray before sorting.
2013-06-21 11:44:41 -07:00
Sean Cannella d1b3172352 remove hphp_process_abort
- Remove questionable hphp_process_abort debugging method
2013-06-21 11:44:40 -07:00
Herman Venter 8d25c0f6f2 Give feedback if breakpoints won't hit because a file is not loaded, a class is not loaded, or a function is not loaded
The debugger client now accepts feedback from the the debugger server about whether a breakpoint can be hit, absent further loads of files, classes or functions.
2013-06-21 11:44:40 -07:00
Joel Marcey 530efd6760 Add default values to parameters of SplFileObject::flock(),fwrite()
Trying to get CakePHP running on HHVM revealed warnings around SplFileObject flock() and fwrite(). E.g., HipHop Warning: flock() expects exactly 2 parameters, 1 given. Added default values for those particular parameters
2013-06-21 11:44:40 -07:00
Andrey Sukhachev e1f159ba78 Fix the Content-MD5 handling.
The current implementation is broken, as the Content-MD5 is
computed over the uncompressed response instead of the compressed one.
RFC-1864 states that only Transfer-Encoding can be applied after the MD5
is computed, not the Content-Encoding.

We don't use Content-MD5, so this bug remained latent up until now.

Also verifying that the PHP side computed the MD5 correctly.

not sure what's happening
2013-06-21 11:44:39 -07:00
Jordan DeLong 7eb65ff688 TestExtMcrypt -> php 2013-06-21 11:44:21 -07:00
Sara Golemon 3cb57c36f0 Remove errantly added includes 2013-06-21 11:39:03 -07:00
Jordan DeLong f0afa537d6 Port TestExtOpenssl to php 2013-06-21 11:38:45 -07:00
Jordan DeLong f435bf5ba7 Move TestExtSession to php 2013-06-21 11:33:24 -07:00
Jordan DeLong 3d3865c34e Port TestExtZlib to php
Also fixed the memory leak.
2013-06-21 11:33:24 -07:00
Jordan DeLong f42ce41179 TestExtOutput -> php 2013-06-21 11:28:47 -07:00
Sean Cannella 4ed3495700 remove one more dead method
remove another dead method
2013-06-21 11:26:05 -07:00
Sean Cannella 7659942d52 remove unused platform-specific references
remove unused references to platform-specific code
2013-06-21 11:26:04 -07:00
Paul Tarjan 9fbfca6510 fix typo in SplFixedArray 2013-06-21 11:26:04 -07:00
Jordan DeLong b053111f16 Retry port binds a few times in ext_stream test @override-unit-failures
The ext_socket test actually already does this.
2013-06-21 11:26:04 -07:00
Jordan DeLong 104f003257 TestExtMailparse -> php 2013-06-21 11:25:34 -07:00
mwilliams 6342bdbf1b Don't pass environment variables with "\n" to LightProcesses
A recent diff started (correctly) passing the environment
through to child processes. It turns out our LightProcess implementation
can't handle environment variables with new lines in them, so (for now)
strip out any such variables.
2013-06-21 11:21:43 -07:00
parent5446 61ec6703fc Added missing PHP SPL classes
Added PHP implementations for PHP SPL classes that are currently missing from HHVM. These include:

- SplDoublyLinkedList
- SplQueue and SplStack
- SplFixedArray
- SplHeap, SplMinHeap, and SplMaxHeap
- SplPriorityQueue
- SplTempFileObject

Closes #807
2013-06-21 11:21:43 -07:00
Jordan DeLong 6fe6e59c0e TestExtSoap -> php
Except one part that didn't work.  (Tasked.)  Also discovered
a SEGV (tasked).
2013-06-21 11:21:42 -07:00
Jordan DeLong 2147b11334 TestExtSqlite3 -> php
Except part of it that SEGVs in the JIT.  (See task.)
2013-06-21 11:21:42 -07:00
Jordan DeLong e1b03d674a TestExtVariable -> php 2013-06-21 11:21:42 -07:00
Jordan DeLong 877f06c1e1 TestExtString -> php 2013-06-21 11:21:41 -07:00
Jordan DeLong 72c4d16df2 TestExtStream -> php 2013-06-21 11:21:41 -07:00
Owen Yamauchi 35fafe5545 Run shutdown handlers before running request-exit cleanup
Shutdown handlers can run user code (e.g. the session stuff serializes
the session and can pass the serialized blob to user code to do
something with), so it's generally not safe to run them after
requestExit(). In particular, requestExit destroys global variables, and
the session serializer reads $_SESSION.

My recent diff to get rid of the hardcoded globals exposed this, though
I argue this situation was incorrect all along.
2013-06-21 11:19:34 -07:00
Paul Tarjan 07fe7cd4a0 make test runner match php style
fixed lint finally (since we didn't have lint when i authored this)
2013-06-21 11:19:34 -07:00
Paul Tarjan 3064830921 disable ext-filter/049.php
We don't serialize doubles correctly in the repo, so this test passes on first try, and fails on second try.
2013-06-21 11:19:33 -07:00
Jan Oravec 621a7d9c55 Pass generator body Func* to c_Continuation::alloc()
Pass generator body Func* to c_Continuation::alloc(), which is then
passed to the new helper that computes ActRec offset.
2013-06-21 11:19:33 -07:00
mwilliams dde3c9e8d8 Fix tvSame for null-by-reference values
The dereference was too late.
2013-06-19 09:57:02 -07:00
Edwin Smith d7ee6388dd Split lvalPtr() into createLvalPtr/getLvalPtr()
Callers are always passing a constant to choose one or the other,
so make them distinct methods.
2013-06-19 09:57:02 -07:00
Paul Tarjan fe323e4821 add filter extension 2013-06-19 09:56:50 -07:00
mwilliams 49aa101879 Fix crashes with empty string as SetElem base
It needs to convert the key to a real TypedValue, and needs
to side exit (via throw).
2013-06-19 09:56:49 -07:00
Paul Tarjan 28bbefa14d actually implement SplObjectStorage 2013-06-19 09:56:39 -07:00
Paul Tarjan 09c916e585 make o_toBoolean non-virtual
I know this is bad form, but we need this for performance. Right now, o_toBoolean() isn't even being called. When D825610 lands it will be and will be a small perf regression.

If this situation gets bad, then we should revisit it, but since only one class is overriding it for now, this should be ok.

(I don't understand C++, did I do the virtual thing right? I had to declare them to make the linker work)
2013-06-19 09:54:37 -07:00
Eric Caruso 320babafb9 Match Zend behavior on openssl_pkey_get_details
Zend PHP populates an extra field in the details array
with some more information about the resource it is passed,
while HHVM leaves this information out.

Closes #815
2013-06-19 09:54:37 -07:00
Jordan DeLong 5a17a10cb6 TestExtOptions, TestExtNetwork, TestExtSocket -> php 2013-06-19 09:54:36 -07:00
Jordan DeLong fa3e93fdca Move TestExtMath to php 2013-06-19 09:54:36 -07:00
Jordan DeLong 4cebdbe47d Remove the ImageSprite extension
Believed to be unused now.
2013-06-19 09:54:36 -07:00
Sean Cannella 5a8d66a614 remove unused tx64 methods
remove dead tx64 code

due to sandcastle flakiness per bsimmers:
2013-06-19 09:54:36 -07:00
Sara Golemon 96caaa2e07 Bundle libmbfl filter files by default
Unicode.org's license allows us to redistribute these files
so long as they contain their original notice, so let's do so
and remove the need to download the files on every new checkout.

To force-update any file, just delete it and the build script
will download the most current version from unicode.org
2013-06-18 17:01:23 -07:00
Sean Cannella 6b2f9631b3 enable inlining for (most) static functions
- Enables inlining for existing function shapes for static calls except:
  1) static calls with a 'this' (as the refcounts become wrong)
2013-06-18 16:23:28 -07:00
Edwin Smith 6f8c436f66 Change HphpArray::m_lastE (an iterator) to m_used (a limit)
I made this change in my arrays working branch and liked it
enough to split it out and test/submit it early.  treating
the range of valid Elm slots as a vanilla open-ended range
[0..m_used) simplifies a bunch of code.
2013-06-18 16:23:28 -07:00
Sean Cannella 1b559a5364 remove unused files
remove unused files
2013-06-18 16:23:27 -07:00
Paul Tarjan 77cf51fb32 add session_register_shutdown
added in 5.4. The comments on http://php.net/manual/en/function.session-register-shutdown.php said this was equivilent.
2013-06-18 16:23:27 -07:00
Owen Yamauchi 49269952c8 Move everything out of GlobalNameValueTableWrapper
This is to clear the runway for getting rid of
GlobalNameValueTableWrapper. It moves aside these three items that were
in there for no particular reason other than convenience. I moved them
aside into another struct that I arena-allocate and initialize at the
same time as the global VarEnv (which initializes the GlobalNVTW).

I called the struct where these live "EnvConstants" since they look like
constants to PHP but their values are determined at startup time (by the
environment, like whether we're in server mode). lvalProxy doesn't fit
that mold, but oh well.
2013-06-18 16:23:27 -07:00
bsimmers 351d40d3d2 Transl::Tracelet -> JIT::RegionDesc converter
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.
2013-06-18 16:23:27 -07:00
Sean Cannella 019b649246 remove unused test code
removing unused code (supplanted by better assembler tests)
2013-06-18 16:23:26 -07:00
Sean Cannella c39053b32b cleanup annotation interface
Remove dead code, un-expose unused methods
2013-06-18 16:23:26 -07:00
Jordan DeLong 3add328e02 Fix slow/ext_url
Not sure why this passed in contbuild.  (It failed only on
the diff immediately after it ...)
2013-06-18 16:23:25 -07:00
Benjamin Strahs e35bded5b3 Add hash algos to openssl_verify
A bunch of hash algos are missing from openssl_verify(), this was fixed in PHP ( https://bugs.php.net/patch-display.php?patch=openssl-add-sig-algs.txt&bug_id=61421&revision=1340052451 ) and should be fixed in hhvm
2013-06-18 16:23:25 -07:00
Jordan DeLong 23ddfd8769 Port TestExtMb to php 2013-06-18 16:23:24 -07:00
Jordan DeLong 12b68dcd4b Port TestExtIpc to php
I don't like these ones very much.
2013-06-18 16:23:24 -07:00
Jordan DeLong 58f3a89039 Port TestExtJson 2013-06-18 16:23:24 -07:00
Jordan DeLong 32d985bb4d Port TestExtIntl 2013-06-18 16:23:24 -07:00
Jordan DeLong 75be029d31 Get the rest of the ExtIcu-ish things to php 2013-06-18 16:23:23 -07:00
Jordan DeLong 4795dcdc09 Migrate TestExtFile to php
I dropped a couple tests that did nothing
(e.g. clearstatcache) or almost nothing, or that 'tested' things that
almost all the tests do (e.g. unlink or fclose).  Dropped a few unixy
apis that really didn't test that they do anything.  Combined a few
tests also.
2013-06-18 16:23:23 -07:00
Jordan DeLong 877603b393 Convert most of TestExtMisc to php; delete rest
Removed all the tests that tested functions that just throw
NotImplemented, or actually did sleeps (without any testing that the
sleep actually did anything).  Otherwise about the same, but I had to
add some assumptions in unpack because you can't do sizeof() from php.
2013-06-18 16:23:23 -07:00
Jordan DeLong 79ce492c0d Port TestExtUrl to php 2013-06-18 16:23:23 -07:00
Jordan DeLong 99ce60eda7 Port TestExtIcu to php 2013-06-18 16:23:22 -07:00
Jordan DeLong 740998c959 Port TestExtIconv to php 2013-06-18 16:23:22 -07:00
Jordan DeLong c26c540024 Port TestExtPreg to php 2013-06-18 16:23:22 -07:00
Jordan DeLong 6d9262d63f Move TestExtHash to php 2013-06-18 16:23:22 -07:00
Jordan DeLong 74f217adcb Move TestExtBzip2 to a php implementation 2013-06-18 16:23:21 -07:00
Jordan DeLong e6052a08c1 Move TestExtXml{,Reader,Writer} to php 2013-06-18 16:23:21 -07:00
Jordan DeLong b95200c2d9 Remove several TestExt tests that did nothing or added no coverage
All did nothing except ExtFunction and ExtSimpleXml.
ExtFunction does things that are sufficiently tested in other suites.
SimpleXml has a test suite, and this only had a few calls to some last
error functions that seemed weak enough to delete.
2013-06-18 16:23:21 -07:00
Jordan DeLong e54398e418 Translate TestExtBcmath to php 2013-06-18 16:23:20 -07:00
Jordan DeLong 9d2faa74cc Move tests from test_ext_datetime to php 2013-06-18 16:23:20 -07:00
Jordan DeLong ee3d0c2d2d Move TestExtCType to php 2013-06-18 16:23:20 -07:00
Jordan DeLong 343f0b01f6 Port TestExtClass to php; delete TestExtClosure through Continuation 2013-06-18 16:23:20 -07:00
Jordan DeLong bda16ef85c Delete TestExtAsio
Empty stubs.
2013-06-18 16:23:19 -07:00
Jordan DeLong 2bbb036c66 Delete TestExtApd
It only tests that it is not implemented.
2013-06-18 16:23:19 -07:00
Jordan DeLong 606db54adb Remove TestExtThread
It doesn't really test anything.
2013-06-18 16:23:19 -07:00
Jordan DeLong 6c7cb9f55e Move test_ext_fb to php 2013-06-18 16:23:19 -07:00
Jordan DeLong 06a3a6b27d Delete TestExtSpl (it was empty) 2013-06-18 16:23:18 -07:00
Jordan DeLong 9e127b9831 Rewrite TestExtArray in php
Most of this is ported over, except some omissions:
  - array_filter, array_key_exists (suspected we had coverage already;
    one is a bytecode, and one was rewritten in hhas recently)
  - some random cases distinguishing init_null_variant vs. null_variant
2013-06-18 16:23:18 -07:00
Jordan DeLong e7d5f5d30f Move test_ext_{apc,apache} to php
Should include everything except I dropped:
  - anything that just tested we're throwing NotImplementedException
  - something about start_time() in ext_apc
2013-06-18 16:23:18 -07:00
Jordan DeLong a6854002c9 Fix hphp build
Not sure when this started happening, but it was getting an
unused but set variable warning.
2013-06-18 16:23:17 -07:00
Mike Magruder b24d2f2016 Unify multiple debugger client event loops, proper event handling in eval/print
There was a similar-but-different event loop used when receiving command results from the server which was close, but not quite right. Unified it with the main event loop to ensure that all error cases are handled properly when we put up a prompt at a nested interrupt, like when hitting a breakpoint during an eval. The event loop is now shared, with a few different "kinds" to control some of the special needs of the loop when executed from a command. Most  commands don't cause the server to run more PHP, so they don't change the machine state or cause more interrupts. But some do (Eval and Print) and certainly the top-level loop does, too. Made sure to throw a protocol error if any command causes this to happen when we don't expect it.
2013-06-18 16:23:17 -07:00
Herman Venter 902c13ed3e Disable test/quick/debugger/list.php
After a rebuild, the first run of the run/tests tests/quick/debugger/list.php invariably fails on developer machines. It passes if run again, or if another debugger test has passed before it has run.
2013-06-18 16:23:17 -07:00
Mike Magruder 22f8788e2f Cleanup client and server communication, events loops, and error handling.
Cleanup a lot of hangs with either the debugger client or server in a variety of error conditions, mostly related to communication errors or the client or server exiting unexpectedly. One of the biggest fixes is that all cases where the client was left in a state where Ctrl-C wouldn't work have been fixed.

Remove lots of little snippets of dead code. If you see a function (or small set of functions/fields) deleted then it was actually dead.

I debated whether to keep throwing DebuggerClientExitException on the server, and I decided to keep it. I think it's reasonable that if you've got the server stopped and you quit the debugger that the request gets terminated rather than continuing to run.

I also considered a big change to the way Ctrl-C works, but ended up staying with what was there with just a bit of cleanup. We need to guard against people banging on Ctrl-C, which is a reasonable behavior, and I think it feels pretty reasonable with the updated message.

Finally, added many comments about how this stuff works.
2013-06-18 16:23:17 -07:00
bill fumerola 8b80373f17 expose Vector->reserve(size) to php space
example usage: genv() takes a Vector of Awaitable and creates a
Vector of WaitHandles. resize() requires a default value, reserve allows us to hint proper allocation.
2013-06-17 17:31:33 -07:00
bill fumerola 4049e79f18 GenVector: it's likely the callers passed a proper Vector of WaitHandles 2013-06-17 17:31:33 -07:00
Eric Caruso 7ee2057a7d Revert "Adds word-size store instructions to x64 assembler" 2013-06-17 14:47:03 -07:00
Paul Tarjan 129b122972 revert timeout change
It looks like "timeout" doens't work on some machines...

  +sh: /usr/bin/timeout: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
2013-06-17 14:46:27 -07:00
Paul Tarjan 66b2ef1e3b add timeout to test
One bad test shouldn't kill the whole run
2013-06-17 13:02:12 -07:00
mwilliams 3a6c6c286e Remove m_importMethToTraitMap from Class.
Its a temporary structure thats just used to help build the class.
Use it a local instead.
2013-06-17 13:02:12 -07:00
Jan Oravec c6f4e6b3c7 Recover from C++ exceptions in AsioExternalThreadEvent::unserialize(), part 2
AsioExternalThreadEvent::unserialize() may legally throw PHP exceptions.
When that happens, construction of PHP exceptions reenters VM, surprised
flag is checked and pending C++ exceptions may be thrown.

Let's make sure the queue of received events in runUntil() is not lost.
Move this responsibility to the AsioExternalThreadEventQueue.
2013-06-17 13:02:11 -07:00
Jan Oravec 797a6822d0 Move external thread event queue logic from AsioSession to AsioExternalThreadEventQueue
External thread event queueing logic is big enough that it deserves its
own class. Move the code and rename members to better reflect the
underlying operations. Implementation is otherwise unchanged.
2013-06-17 13:02:11 -07:00
Jan Oravec d6e869dfa9 Recover from C++ exceptions in AsioExternalThreadEvent::unserialize(), part1
AsioExternalThreadEvent::unserialize() may legally throw PHP exceptions.
When that happens, construction of PHP exceptions reenters VM, surprised
flag is checked and pending C++ exceptions may be thrown.

Let's make sure the event is properly destroyed. If it is not, the web
request will get stuck forever waiting for the finished event to finish.
2013-06-17 13:02:11 -07:00
Sara Golemon 27ef4c02cc Rename hphp/tools/gen-ext-hhvm to hphp/tools/bootstrap
gen-ext-hhvm actually contains three different
bootstrapping utilities:
* gen-ext-hhvm
* gen-infotabs
* gen-class-map

This move is just to give it a more contextually appropriate name.
2013-06-17 11:08:04 -07:00
Paul Tarjan 872c1d1bcf disambiguate symbols for Transl killing
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.
2013-06-17 11:01:27 -07:00
ptarjan e48c95208d codify the instructions
People are using this to setup their machines. It should be more robust.
2013-06-07 22:14:00 -07:00
Sara Golemon 3a4defc30b Throw an exception when an unknown flag is specified
Because if we don't know, we can't fix it!
2013-06-15 23:32:09 -07:00
Sean Cannella e89645d960 Remove rematerialization code
- Remove rematerialization since it doesn't buy us much and we've had issues with it
2013-06-15 23:32:09 -07:00
Paul Tarjan 9f7b4a73c6 update mysql to a saner default
Most normal PHP programs will use mysql as an actual database, instead of the key/value store we use ours for.

It is hard to get a definitive answer on what the PHP default is, but I think it is 1 minute since it follows `default_socket_timeout` which is 60 seconds.
2013-06-15 23:32:09 -07:00
mwilliams 1626223e97 Avoid allocations for empty maps
Empty FixedStringMaps would do a malloc of at least 9 bytes,
and IndexedStringMap would do a 1 byte malloc, and a malloc of at least 9
bytes.

We have a lot of typically empty maps in our data structures.
2013-06-15 23:32:08 -07:00
Eric Caruso 5c787f5889 Adds decl and decw instructions that operate on registers
There was a confusing comment left in the assembler
that said that we can't encode a decl r32 instruction, because
the opcode is the same as a REX byte. This is untrue in our
assembler, because we use the FF /1 encoding, rather than the
48 one (which is a REX byte and would be a problem).

Some tests were added to show that this is fine.
2013-06-15 23:32:08 -07:00
Sean Cannella e7fc33d93f Inline simple printers (easier inline testing)
- Inlines simple constant print functions (makes it easier to test
inlining side effects in a simple manner)
- This also confirms that FPushObjMethodD inlining is working as expected
2013-06-15 23:32:08 -07:00
Paul Tarjan 613295121f make debug_backtrace 5.4 compatible
This was spewing on mediawiki and we need to update. It is backwards compat.

I tried to put the constants in PHP but failed. I spent 30 mins on it. I'll come back to it next time I get the itch.

Closes #812
2013-06-15 23:32:07 -07:00
Paul Tarjan 1ca7c026d1 Revert double thing
Some tests are failing now that didn't fail in contbuild. Revert until I can look at it.
2013-06-15 23:32:07 -07:00
Paul Tarjan 140c537a90 add JSON_UNESCAPED_UNICODE
This is giving warnings on wikimedia and was implemented in 5.4
2013-06-15 23:32:07 -07:00
Paul Tarjan 74b6e69086 fix what I broke with the double diff
I committed the wrong version.
2013-06-15 23:32:06 -07:00
Paul Tarjan 794f87542a try strtod instead of zend version
why is there a zend version and a c version? we mix and match in `is_numeric_string`. I'm worried this is giving me a problem in the filtering of floats.
2013-06-15 23:32:06 -07:00
bsimmers a4c8ea2957 Revert "Added AssertThis opcode and modified translator to emit it" 2013-06-15 23:32:01 -07:00
Paul Tarjan 0714b4e389 use a flag instead of isdigit
Instead of doing name-based checks, using a flag in the runtime seems better. I tried to have a flag on the FuncEmitter that was set when you made these weird functions, but there was a few situations that needed to do name-based checks

* .hhas files have no control over anything but the name
* the parser would have to pass the info through the AST to the emitter

Instead I opted for the simpler approach for now until we want to solve those.
2013-06-15 23:30:25 -07:00
Eric Caruso 1920e85155 Adds word-size store instructions to x64 assembler
Formerly, trying to emit a 16-bit instruction, such as
with test_imm16_disp_reg64(...) would actually emit a testl
instead of a testw. This would emit an 8-byte instruction
(ex. 41 f7 45 0e 01 01 00 00) and possibly be testing the wrong
thing. Now, when you emit a word-size instruction, it will prefix
with 66 and use the correct operand size, saving us a byte
(ex. 66 41 f7 45 0e 01 01).

I also converted the instruction emission in ContPreNext to
use the new style assembly emission.
2013-06-15 23:30:24 -07:00
Drew Paroski e6b6aa0b09 Clean up the hphp/system folder
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".
2013-06-15 23:29:49 -07:00
Herman Venter 97f3015bb0 Add comments and type information to break_point
Non functional changes to make the code more readable.
2013-06-15 19:33:46 -07:00
Jordan DeLong f49b7f2e1c Delete various dead "currentRef"-related functions
endRef() is also almost dead, but not quite yet...
2013-06-15 19:33:46 -07:00
Jordan DeLong e11fd75d7a Remove Variant's o_foo member functions @override-unit-failures 2013-06-15 19:33:46 -07:00
Jordan DeLong f7d3d6511d Remove SmartAllocator support from Variant @override-unit-failures
It looks like this is all it takes now.  I couldn't find any
of the old .inc file stuff; I guess it went away at some point.
2013-06-15 19:33:46 -07:00
Jordan DeLong bb4ce81442 Remove NEW(Variant) uses in ext_mysql 2013-06-15 19:33:46 -07:00
Paul Tarjan bd8a697f13 fix text
oops
2013-06-15 19:33:46 -07:00
bsimmers f26cd669cc WIterNext and WIterNextK should break BBs
They're control flow instructions.
2013-06-15 19:33:45 -07:00
Jan Oravec 3ac5f621cd Recover from C++ exceptions
Recover from C++ exceptions so that PSP does not think ASIO is running. Fixes a segfault when ASIO fails on internal invariant violation in runUntil() with m_current == nullptr.
2013-06-15 19:33:45 -07:00
Edwin Smith d3601af2ac Remove StringOffset and String.lval() overloaded functions.
These are dead code, except for a few tests.
2013-06-15 19:33:45 -07:00
Herman Venter 4ed56d8a1d Parse nested namespaces in break point specifications.
Changed the parser for break point specifications to allow nested namespace qualifiers. Also extended this to the exception command.
2013-06-15 19:33:45 -07:00
Paul Bissonnette 5ee5fd8925 Added AssertThis opcode and modified translator to emit it
AssertThis is now emitted when IR is generated rather than simply
setting the isThisAvailable flag.
2013-06-15 19:33:45 -07:00
Paul Bissonnette c6ca429a5e Changed lookupIR in targetcache.cpp to not require a VMRegAnchor
Updated lookupIR functions in StaticMethodCache and StaticMethodFCache
to accept the FP as an argument.
2013-06-15 19:33:45 -07:00
Paul Tarjan d8386c9bc8 kill dead attributes
I was in here and noticed a few of them aren't used.
2013-06-15 19:33:45 -07:00
Paul Tarjan 419b03c787 clone config.hdf from slow to large_memory
It failed again with my other config.hdf commit already in the tree. Lets try the whole config I guess...
2013-06-15 19:33:45 -07:00
Herman Venter af0f28532a Cache the contents of systemlib.php for use by the debugger, if debugging.
Instead of calling get_systemlib every time the debugger client needs to list source from systemlib.php, use a cached copy of the source string. Only do this if debugging is enabled.
2013-06-15 19:33:45 -07:00
Owen Yamauchi e3ddc77159 Kill InclOpLocal
This one's an artifact of ReqMod and ReqSrc, which don't exist anymore.
2013-06-15 19:33:44 -07:00
Ben Maurer 69143a273c Possible Leak in UnitEmitter
I was looking at a jemalloc profile of HPHP ram and noticed
250 MB of RAM allocated from UnitEmitter::UnitEmitter. This
doesn't make sense since the memory is released on destruction.
I think that we're calling setBc which leaks the memory
2013-06-15 19:33:44 -07:00
Ben Maurer 27b22a4c6d Make libevent takeover support have better behavior when takeover not done
Currently, when we have takeover configured we don't close() the listen
socket until the hhvm process dies. This is bad because the loadbalancer
will continue to try to connect to the server and we will throw those
requests away.

This diff ensures that we always close the listen socket during server
shutdown.
2013-06-15 19:33:44 -07:00
mwilliams 866290d835 Fix crashes/assertions related to fb_intercept and reentry
If a function was called via (re)enterVM, and it didn't yet
have a prolog, and it was unable to get the write lease, and it was
intercepted, and the intercept handler asked for the original function
to be skipped, fcallHelper didn't return correctly, typically resulting
in the original function being re-executed, and then re-intercepted -
except that it was one level deeper in the vm-nesting hierarchy.

Eventually, it crashed.
2013-06-15 19:33:44 -07:00
Sean Cannella db9197d7a9 enable more failed inline shape printing
- profile inline shapes that fail due to IR compat reasons
2013-06-15 19:33:44 -07:00
Paul Tarjan 388ef5b984 back to 8 compile processes
I think they were running out of RAM
2013-06-14 15:56:02 -06:00
Paul Tarjan 5f5218836e use number of processors for compilation 2013-06-14 15:42:21 -06:00
Paul Tarjan a645427bce use number of CPUs on machine for tests 2013-06-13 16:34:43 -06:00
Sara Golemon c01bbf22de Translate gen_systemlib.php to bash
Remove another piece of PHP-dependant bootstrapping
2013-06-13 12:13:09 -07:00
Drew Paroski 7252c636ac Fix: Vector, Map, and StableMap should implement the Indexish interface 2013-06-13 10:25:47 -07:00
Jordan DeLong 7d9d87aee1 Revert "PolicyArray: implement NOT_IMPLEMENTED methods"
This reverts commit 1b65776a391188369a73dafca4851ba233e4e410.
2013-06-13 10:25:44 -07:00
Andrei Alexandrescu 1bfe90084a PolicyArray: implement NOT_IMPLEMENTED methods
This implements the "last" unimplemented methods in ArrayShell. The sorting-related methods need no implementation because PolicyArray scales to HphpArray before sorting.
2013-06-13 10:25:43 -07:00
Paul Tarjan fd8f503b18 more robust test
horribly broken things don't emit json
2013-06-13 10:25:43 -07:00
Paul Tarjan 5d47440dd1 add config.hdf to large_memory test
This probably needs a repo to check repo contention
2013-06-13 10:25:43 -07:00
Jordan DeLong f336f30911 Verifier: Fix a typo in switch bounds checking 2013-06-13 10:25:43 -07:00
Paul Tarjan 6e62230978 RecursiveFilterIterator
simple
2013-06-13 10:25:42 -07:00
Jordan DeLong 960f36f836 Restructure the unwinder a bit; use visitStackElems and simplify some things
Hopefully a little bit simpler, and duplicating less logic
with Stack::toString.  Contains some fixes to visitStackElems to make
it work for this (it is printing some stacks slightly incorrectly
right now, too ... :)
2013-06-13 10:25:38 -07:00
Jordan DeLong b01043bf3c Move the unwinder out of bytecode.cpp
Move all the stack unwinding code to its own module, delete
some redundant enumerations, document a few things.  Gets rid of most
of the remnants of the old setjmp/longjmp-based implementation at the
enterVM level but doesn't do much to the unwinder itself (coming in
separate diff to hopefully be easier to review).
2013-06-13 10:25:38 -07:00
Jordan DeLong 9e56c78038 Remove Variant::GetTypedAccessor
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.
2013-06-13 10:25:37 -07:00
Jordan DeLong d145ce88e3 Remove less, more, and equal functions from Variant
Re-implement them in terms of TypedValue and Cell helpers.
2013-06-13 10:25:37 -07:00
Paul Tarjan b2fb023ca8 use cpus+1 for tests
@swtaarrs says repo contention is a thing of the past and this is the right load to put on the cpu.
2013-06-13 10:25:37 -07:00
Owen Yamauchi fb930b9916 Delete reqLitHelper
It seems to have died with tx64.
2013-06-13 10:25:36 -07:00
Herman Venter 1cd7eb316e Check precondition before calling set_execution_mode
set_execution_mode has an assertion that amounts to a precondition requiring that its input parameters have been validated. This causes hhvm to assert and crash if the user specifies an invalid mode on the command line.
2013-06-13 10:25:36 -07:00
Herman Venter 2c37e4477e Port debugger unit tests for break command to new framework
Port debugger unit tests for break command to new framework to prepare for added many more tests dealing with nested namespaces.
2013-06-13 10:25:36 -07:00
Jordan DeLong cca68a7f91 Remove two unused builtin_functions.h things, collapse print() into echo() 2013-06-13 10:25:36 -07:00
Owen Yamauchi d7c2eac643 Get rid of variable break/continue
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.
2013-06-12 17:10:34 -07:00
Jordan DeLong bf72004e0e Remove some confusing assignments to NamedEntity::m_cachedClassOffset
Assigning this field is actually protected by the target
cache lock, and allocKnownClass does the assignment.
2013-06-12 17:10:26 -07:00
Paul Tarjan bd77ea909b try without recursion
see if we don't need it
2013-06-12 17:10:26 -07:00
Jordan DeLong 48346cb13d Remove lval(), id() and wrap_variant() from builtin_functions.h 2013-06-12 17:10:25 -07:00
Jordan DeLong a8a57b4b1a Remove concat5 and concat6 2013-06-12 17:10:21 -07:00
Sara Golemon 971f17421d Remove generator for system/constants.h which is now auto-built at compile time 2013-06-12 15:40:29 -07:00
Sara Golemon 13a055efa4 Add gen-class-map.cpp for bootstrapping constants.h and class_map.cpp
Conversion of PHP versions so we don't need PHP to build HHVM

For the most part, the generated files haven't changed from the
PHP sourced versions (apart from minor indentation and whitespace
changes).

Except for one major exception:
An IDL's function/method argument list includes a "value" field
for default parameters which takes psuedo-serialized values in
several forms. Most are simple scalarish values like:
  "true", "null", "null_array", "null_variant",
  "123", "0x456", "0123", "1.23", "\"foo\""
However referencing other constants is also supported:
  "k_FOO", "q_Bar$$BAZ"
Or even bitmask compositions like:
  "k_FOO|k_BAR|k_BAZ"

Runtime uses of these values are encoded directly into *.ext_hhvm.cpp
files, so they reach userspace code just fine.

The value placed in g_class_map are used exclusively by ext_reflection
to allow introspection at runtime.  Under the old class_map.php parameter
default constant references would be resolved in a (somewhat buggy) eval(),
since we don't have eval within gen-class-map, we reuse the
kUnserializable deferral.

This diff provides a mechanism to resolve this in ReflectionMethod
uses (an improvement from previous behavior), and leaves the current
eval-on-demand behavior for ReflectionFunction.  These two code paths
are different due to the partial state of migration away from using
ClassInfo.
2013-06-12 15:38:53 -07:00
Jan Oravec 8491515257 Kill InlineCreateCont
Remove unnecessary optimization that can be achieved in a more general
way and simplify continuation creation code.

VMExecutionContext::createContinuationHelper was renamed to
VMExecutionContext::createCont{Func,Meth}. The createContFunc no longer
takes this/class arguments, the createContMeth transfers them in one
Type::Ctx pointer that is used natively by ActRec's m_this. Since the
whole logic of this function is to set this single field, the logic is
now simpler.

Interpreter: iopCreateCont() just passes the m_this field of the parent
ActRec.

Translator: CreateCont opcode loads m_this field using LdCtx opcode.
This opcode optimizes into LdThis, which optimizes into
DefInlineFP->SpillFrame->object and allows frame to be eliminated, a
case previously covered by InlineCreateCont.

This diff uncovered a bug in trace builder, where LdCtx in static
methods could be optimized into LdThis, if the method was called thru
object. Fixed.
2013-06-12 14:04:05 -07:00
Paul Tarjan fca204fd63 add slow tests
with the repo contention test moved, these now all pass
2013-06-12 13:51:10 -06:00
Owen Yamauchi 79224cdd38 Remove the hardcoded globals from GlobalNameValueTableWrapper
The ultimate goal is to de-virtualize ArrayData. To do this, we need a
single ArrayData subclass that has all the capabilities we need. This
2013-06-12 11:35:00 -07:00
bsimmers cf87b7eec3 Basic region translator
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.
2013-06-12 11:34:41 -07:00
Edwin Smith 274ef6c45b Split ArrayData::append(ArrayOp) into plus() and merge()
We had two distinct functions dispatched by an enum that was
always known somewhere higher up on the callstack.
2013-06-12 11:34:41 -07:00
Paul Tarjan b0de59da49 move repo contention test
I'd like to run the slow tests in our open source testing framework. This is the only test that fails hard. It actually fatals the test framework even with the 10 Meg limit we are using now.

What do you think about breaking it out to not run in open source?
2013-06-12 11:34:40 -07:00
Paul Tarjan 6d109c37c2 only accept ports in range
http://example.com:-1 isn't a valid url
2013-06-12 11:34:40 -07:00
Paul Tarjan e8aa945337 fix pathinfo
This is needed for CodeIgniter. They do `pathinfo()` and triple equal compare to "".
2013-06-12 11:34:40 -07:00
Jan Oravec e8acd400ac Remove unused UnitEmitter::m_feMap
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.
2013-06-12 11:34:39 -07:00
Paul Tarjan e3d31d70de fix StaticString copy constructor 2013-06-12 11:34:39 -07:00
Paul Tarjan 269ec416d5 Rename closures and generators - take 3
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.
2013-06-12 11:34:39 -07:00
mwilliams 8069424449 Fix order dependencies in BuiltinSymbols::Load
We need to import the c++ classes and constants before parsing
systemlib.php so that static analysis is aware of them.
2013-06-12 11:34:39 -07:00
Herman Venter d160ad4ddb Source information for systemlib.php for use in debugging.
The debugger can only hit breakpoints and list source lines for code lines that have an entry in the byte code repository. In order to make systemlib.php debuggable, it needs an entry. A customized routine has been created for doing this since there is no actual source file available. Also, special case logic is needed to list the source file during debugging.
2013-06-12 11:34:38 -07:00
Herman Venter 6a0d728a8a Add tracing to cmd_run and the debugger API
Add some tracing to help with debugging the debugger API.
2013-06-12 11:34:38 -07:00
Mike Magruder 5d25a36a61 Remove the rest of the dead instrumentation code
This is the follow on to https://phabricator.fb.com/D805320. Removing the rest of the instrumentation code.
2013-06-12 11:34:38 -07:00
Edwin Smith d44d103886 Keys can't be doubles: remove a bunch of Array/Variant methods.
Array and Variant don't need to accept double for array keys,
since they can only be int or string anyways.  The only place
we called those methods was in test_cpp_base.cpp anyway.
2013-06-12 11:34:38 -07:00
Jordan DeLong 08ea36967e Delete all non-CVarRef overloads of empty/isset @override-unit-failures
We only really use those now.
2013-06-12 11:34:37 -07:00
Sean Cannella 333f0a76f4 Fix a zend compat issue in array_slice
- Fix the behavior of array_slice when using PHP_INT_MAX
2013-06-12 11:34:37 -07:00
Jordan DeLong fd657cfeb8 Remove mostly unused instanceOf() function
We don't need to overload this on types anymore.
2013-06-12 11:34:37 -07:00
Jordan DeLong 27faa44c30 Delete same() overloads that don't involve VM types
Don't really need these anymore now that we're not generating
C++.
2013-06-12 11:34:37 -07:00
Jordan DeLong 3e188a56dd Prune some unused/barely used functions from type_conversion.h @override-unit-failures 2013-06-12 11:34:36 -07:00
Jordan DeLong d8bddea335 delete Variant::same, implement same(CVarRef, CVarRef) in terms of tvSame
Step two.  Leaving the Variant::same methods as deleted for
now because I'm worried about the implicit conversion operators to
other types that support same.
2013-06-12 11:34:36 -07:00
Jordan DeLong 2618ad0ef2 Delete all the non-variant Variant::same overloads
Step one.
2013-06-12 11:34:36 -07:00
mwilliams 412dce677f Better reffiness checks
While debugging a sandbox crash, I spent some time looking at a huge
sequnce of conditional masks, compares and branches that didnt seem
to belong in the code I was debugging. Finally realized that it was
a reffiness check. It looked way too complicated, so I investigated.

Part of the problem was that we were avoiding a malloc in the case
of a zero param function at the expense of an extra check.

Instead, this diff always sets up at least 64 bits worth of m_refBitVec.
But by using the space set aside for the pointer in Func::m_shared it
avoids a malloc for any function with fewer than 65 arguments, and
avoids the numParams check for the first 64 parameters.

In addition, the existing code was spitting out a generic test for
the guard condition - (mask & bits) == value - where mask and value
are known constants. Since the most common case is that value == 0
(all the parameters are expected to be by value), we can usually omit
the compare. In addition, since most functions only have a small
number of parameters, we can usually get away with 8 bit, or 32
bit operations.

The result is that for a typical function (fewer than 64 args, args
expected to be by value) the reffiness guard is now

  test <mask>, Func::m_refBitVec[0]
  jne exit

Rather than:

  move <mask>, reg1
  xor reg2, reg2
  cmp 1, Func::m_numParams
  jnl ok
  test AttrVarArgs, Func::m_attrs
  jne exit
  jmp done
ok:
  load reg3, Func::m_refBitVec[0]
  and mask, reg3
  cmp reg3, reg2
  jne exit
done:
2013-06-11 11:48:25 -07:00
mwilliams 94ad2fd0ee Fix TestExtSocket flakiness
It picked a random starting port, then incremented
for each test. If it happened to collide with an existing
port, it failed. Make it try 20 different ports before giving
up and failing.
2013-06-11 11:48:25 -07:00
mwilliams b967e102a0 Get rid of BuiltinSymbols at runtime
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.
2013-06-11 11:48:24 -07:00
Jan Oravec 9662396bf0 Store variable arguments in optional local
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.
2013-06-11 11:48:06 -07:00
Dario Russi f6de025eab Optimize FPassM for Vector and Map
Added FPassM to the instruction optimized for Vector and Map. It reuses the code for CGetM.
2013-06-11 11:47:48 -07:00
Paul Bissonnette d8df647b38 Fixed cleanup/exception handling for vector operations.
Vector statements ending with a SetProp now properly free
         memory when run with JIT enabled.  Additionally, in both
         JIT and interpreted mode memory will still be freed if
         exceptions are thrown during evaluation of vector operations.
2013-06-11 11:47:47 -07:00
Drew Paroski 9b95c48416 Fix issue with XHP and keywords 2013-06-11 11:47:47 -07:00
Mike Magruder c158e4a24b Cleanup small stepping
Small stepping, which is stepping over sub-expressions (kinda), worked but was a little goofy. The mode was set on the client, passed over with control flow commands, placed on the execution context, then retrieved from there and used by those same flow commands. Removed the execution context part of it, since it was useless, and factored grabbing the offsets into the flow cmds where they belong instead of doing it all the time.

The run cmd also had some notion of small stepping, but you'll note it was never sent over the wire. Nuked that, since it never mattered anyway.
2013-06-11 11:47:28 -07:00
Drew Paroski eaabed2416 Fix deep copying for Sets
This logic got messed up somehow during rebasing and we were missing a
case for Set inside collectionDeepCopyTV(). This diff fixes the issue.
2013-06-11 11:47:28 -07:00
Herman Venter da8e8adc46 Add back a necessary null check
Diff 817612 added a null check, but inadvertently removed a null check.
2013-06-11 11:47:28 -07:00
Paul Tarjan d5ee17487a allow constants in systemlib
The problem was a few:

* All constant declarations were wrapped in a statement list. The merge-only check was allowing top-level `define()`s but not top level statement lists. I unwrapped them. I have no idea why it was done. Probalby just cargo cult programming.
* When converting a UnitEmitter to a Unit we only allowed constants in RepoAuthoritative mode and not systemlib mode.
* Systemlib constants weren't being set as UnitMergeKindPersistentDefine
* UnitMergeKindPersistentDefine constants weren't being marked mergeOnly when pulling out of a repro
2013-06-11 11:47:28 -07:00
Paul Tarjan 18067c4020 don't call auotloader with blank name
I debated putting in an assert in the autoloader but I'm worried that will break many things. Lets just plug this for now.

Closes #803
2013-06-11 11:47:08 -07:00
Dario Russi fe8b84f542 vector and map get/set/isset specialization in IR
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.
2013-06-11 11:47:07 -07:00
Edwin Smith 51967b2c12 Remove ArrayData::getIndex virtual methods.
They aren't used anymore, except to implement isVectorData(),
which we can make pure-virtual and implement more efficiently
in each subclass of ArrayData.
2013-06-11 11:47:07 -07:00
Mike Magruder eec54a0f6c Cleanup a bit of exception/error handling between the VM and the debugger
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.
2013-06-11 11:47:07 -07:00
mwilliams 7398db6097 Keep the uploaded data when a partial upload error occurs
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.
2013-06-10 10:14:13 -07:00
Paul Tarjan 8cf6ccb00a use TRACE_SET_MOD
I found this macro while refactoring and since I like consistency, I used it everywhere.
2013-06-10 10:14:13 -07:00
Paul Tarjan 1b47c9fdd2 fix header order
fixed the lint rule and includes the extra header we needed
2013-06-10 10:14:13 -07:00
Herman Venter a2d949f9d2 Do not recreate the debugger options file.
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.
2013-06-10 10:14:13 -07:00
Herman Venter fcf0c7533c Remove assertion that is no longer true and that does not do anything useful.
This assertion should have been removed with an earlier diff that made it no longer true.
2013-06-10 10:14:12 -07:00
Edwin Smith f69a002911 Remove the SharedVariant pointer from StringData.
We only use it to lazily grab the hashcode.  So just grab the hashcode
eagerly when we create the string.
2013-06-10 10:14:12 -07:00
Herman Venter 3d0330fd9d Provide a command line switch to specify the path to the debugger config file
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
2013-06-10 10:14:12 -07:00
Paul Tarjan a729338538 Trace -> IRTrace
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`.
2013-06-10 10:14:12 -07:00
Paul Tarjan 1c50cae763 s/Call/CPPCall/
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 :)
2013-06-10 10:14:11 -07:00
Mike Magruder 96d6bab291 Cleanup flow control around exceptions
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.
2013-06-10 10:14:11 -07:00
Sean Cannella 4c26494f85 Make Nemo aware of functions defined in systemlib
Now that we define functions in systemlib they also need to be available during static (Nemo) analysis.
2013-06-10 10:14:11 -07:00
Paul Tarjan 7b6d06074c just thorw a regular exception
I'm not expecting a user to do anything actionable (other than open an issue) on this error so a regular Exception should be ok.
2013-06-10 10:14:11 -07:00
Paul Tarjan 0d3eaf9fd3 add irc notifications 2013-06-07 17:53:59 -06:00
Paul Tarjan 83b310a20f try more threads now that there is less used ram 2013-06-07 15:27:35 -07:00
Paul Tarjan bcefd15d4e change amount of memory tests can use 2013-06-07 14:24:34 -07:00
Sean Cannella 543927cc35 make PHP_SAPI dynamic based on execution mode
It isn't really a constant anyways.

Closes #757
2013-06-07 12:41:50 -07:00
Herman Venter 894b0addf2 Provide a config option to turn off debugger prompt.
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.
2013-06-07 12:41:30 -07:00
Jan Oravec 1d90b368dc Kill m_localsOffset and free another 16 bytes of memory
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.
2013-06-07 12:41:30 -07:00
bsimmers aa509ef3b9 Clean up TranslatorX64
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.
2013-06-07 12:41:30 -07:00
Edwin Smith 4fac83a847 Remove dumpDebugInfo (dead code)
it's dead
2013-06-07 12:41:30 -07:00
Edwin Smith c5fed85723 Delete unused litstr conversion functions
These aren't called, so this takes them off the table.
2013-06-07 12:41:29 -07:00
Paul Tarjan f5569e4755 clean up tests dir
I think this dir shouldn't have anything non-necessary in the root.
2013-06-06 16:31:09 -07:00
Jordan DeLong dc6dc022e7 Initial API for region selectors
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.
2013-06-06 15:58:14 -07:00
Jordan DeLong e05dd4e9ff Make stack walking logic from Stack::toString reusable
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.
2013-06-06 15:58:14 -07:00
Jordan DeLong 51574fb2ec Fix an assembler bug with FPI region offsets
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.
2013-06-06 15:58:14 -07:00
mwilliams adee83bab7 Run repo-authoritative tests in repo-authoritative mode
Because its the right thing to do. Even if some tests fail.
2013-06-06 15:58:13 -07:00
Jan Oravec c839f3c3d0 Fix static variables in closure generators
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).
2013-06-06 15:57:06 -07:00
Jan Oravec 1e48e96bbe Remove m_obj from c_Continuation
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.
2013-06-06 15:57:06 -07:00
Edwin Smith 3515793e74 Remove ArrayData::nvSet() wrappers and several dead Array helpers.
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.
2013-06-06 15:57:05 -07:00
Paul Tarjan 20ad8ba931 fix SplFileInfo->openFile
without a default class, opening a file doens't work so well

Closes #802
2013-06-06 12:00:08 -07:00
Eric Caruso 958df942ce replicating readline control characters in test output
Readline is awful and dumps characters in the output.
This was causing tests to act weird on another build.
2013-06-06 12:00:07 -07:00
Eric Caruso 9b750620a7 Clean up some header includes 2013-06-06 12:00:07 -07:00
mwilliams 70751f99a8 Fix a bug for continuations-from-closures that need a local $this
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.
2013-06-06 12:00:07 -07:00
Andrei Alexandrescu 4debf268f7 ArrayData: consolidate m_nonsmart and m_allocMode into one field
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.
2013-06-06 12:00:06 -07:00
Edwin Smith fe32089a67 Reduce use of AttachLiteral StringData construction
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.
2013-06-06 12:00:06 -07:00
Jan Oravec 611e80011a Remove unneeded EmitterVisitor::m_methLabels
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.
2013-06-06 12:00:06 -07:00
Eric Caruso 006d2da96d Added warning for bad return values from user comparators
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).
2013-06-06 12:00:05 -07:00
Jordan DeLong fa6f3f7e12 Implement most of class_alias
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.
2013-06-06 12:00:05 -07:00
Edwin Smith 34a52f49f5 Array::add(), set(), and setRef() don't need to return anything.
Removes a bit of code, and avoids a few uses of lvalBlackHole().
2013-06-06 12:00:04 -07:00
bsimmers 6fca89f259 Disable flaky zend test
I've seen it failing on master intermittently
2013-06-06 12:00:04 -07:00
Bert Maher bf52b61852 Allow early initialization of classes if they don't have any [sp]init methods
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.
2013-06-06 12:00:04 -07:00
Jordan DeLong bcc0192c13 Improve verifier error message marginally (include unit, func) 2013-06-06 11:59:56 -07:00
Paul Tarjan ec6f051b0b fix bug36258
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.
2013-06-06 11:39:15 -07:00
Edwin Smith de080dbc75 StackTraceProfiler utility class
StackTraceProfiler is a utility class for collecting call-stack profiles
at specific places in the code.  Typical use is to create a static
instance, then call prof.count() under the desired conditions.  You
can of course compose these to make value profilers.
2013-06-06 11:39:14 -07:00
Paul Tarjan 43da51882c fix argv in server mode
Match zend.
2013-06-06 11:39:14 -07:00
mwilliams 7f77095315 Fix asm_test
SimpleLableTest used rbx, r10, r11, r15 without saving them,
causing lots of potential issues.

RandomJunk relied on white space at the end of a line - but our
master.emacs is setup to strip trailing space on save. I rewrote
the test to avoid having to remember to override every time.
2013-06-06 11:39:14 -07:00
Mike Magruder 87ff333281 Add support for debuggers and continuations to out2expectf.py
Added something specific for the debugger to sanitize the relative paths of the debugger tests. Also added sanitization for continuation functions names.
2013-06-06 11:39:13 -07:00
Andrei Alexandrescu a2e76eb7b2 Eliminate static noise from .h files
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
2013-06-06 11:39:13 -07:00
mwilliams 310884d8f1 Don't crash trying to print bytecode for unreachable switch targets
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.
2013-06-06 11:39:13 -07:00
mwilliams 2a36ee1405 Free Func's properly
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.
2013-06-06 11:39:12 -07:00
Paul Tarjan e433cd193c move compiled tests files into another dir
I've been linking people to the README in this directory, but it is hard to see with all these files in here. What do people think about it moving a subdirectory? I don't love the name.
2013-06-06 11:39:06 -07:00
Sean Cannella 64e24977ca STD* streams should not be defined in server mode
- Zend doesn't define STDIN/STDERR/STDOUT in server mode, neither should
  we
2013-06-06 11:08:39 -07:00
Jordan DeLong 4e547faa8f Verifier: disable iterator checks, turn verifier on for systemlib @override-unit-failures
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.
2013-06-06 11:07:59 -07:00
Herman Venter 917fffb462 Reduce redundant spew when breaking on an unhandled exception. Quit cleanly.
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.
2013-06-06 11:07:59 -07:00
Owen Yamauchi 3e26291f90 Fix missing header
Some systems (my ARM SDK) seem to need this.
2013-06-06 11:07:58 -07:00
Mike Magruder da03bc9353 A few step out fixes
Fix counted step outs, and add a test for all counted stepping commands.
2013-06-06 11:07:58 -07:00
Paul Tarjan 4d642e9cd7 test runner fixes
* Put `details` in the ending results output. Hopefully that appears on diffs.
* Exit early if we can't invoke the command (and abuse the `.diff` file).
* Error out if any output is on stderr.
* Fix the diff for regex tests (not that we have many).
* Capture stderr when running `hphp`
* Parse out FAILED: line during jenkins
2013-06-06 11:07:58 -07:00
Paul Tarjan d1baeadc65 update link to CLA
we will use the individual one most commonly
2013-06-04 18:01:44 -07:00
mwilliams d62fddec07 Fix crash in array_filter/array_map with a bad function
interp only
2013-06-04 17:53:38 -07:00
Jordan DeLong 82095e9227 Unconditionally run the verifier on hhas files; fix various errors @override-unit-failures 2013-06-04 17:53:38 -07:00
Jordan DeLong 0a18064197 Add some unique_ptr-related support to smart:: containers
- 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.
2013-06-04 17:53:38 -07:00
bill fumerola d139011517 GenVectorWaitHandle
add GenVectorWaitHandle, a WaitHandle suitable for use with the Vector collection.
2013-06-04 17:53:38 -07:00
Guilherme Ottoni 5a76c92c73 LdClsCns's dest is Uncounted
So annotate that when generating the IR instruction and clean-up isRefCounted.
2013-06-04 17:53:38 -07:00
mwilliams 99f3924872 Fix an issue with fb_intercept
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.
2013-06-04 17:53:38 -07:00
Paul Tarjan 55acd87832 fix namespace assert
this need to check the short form not the original.
sosorry
2013-06-04 17:53:38 -07:00
Mike Magruder 5299e5ba0d Basic stepping in generators
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.
2013-06-04 17:53:37 -07:00
Jordan DeLong 3866a8b966 Verifier: treat Throw and Unwind as terminating a block
isCF() was returning false for instructions without jump
targets.
2013-06-04 17:53:37 -07:00
Herman Venter a73eaaabd9 Do not persist the EnableDebuggerColor config option into the hphpd.hdf file
The ~/hphpd.hdf file provides the ability to customize (or turn off) colorization in hphpd as a user preference. The EnableDebuggerColor option turns of colorization for a single run only and should not persist into hphpd.hdf.
2013-06-04 17:53:37 -07:00
Paul Tarjan d95fd236d2 flakey tests
Stop using the same filename!
2013-06-04 17:53:37 -07:00
Paul Tarjan b369aa91bc compile with -Wunused-but-set-variable
Our open-source build compiles with these warnings, so they cause spew when building from github. And I think they are good to catch programmer error.
2013-06-04 17:53:37 -07:00
Paul Tarjan 9d085274c1 add individual CLA
The other one was for corporations. We should be using this one most often.
2013-06-04 17:53:37 -07:00
mwilliams 0007231452 Fix spew from hphp when it tries to constant-fold php-builtins
trigger_error bypasses the usual error handling, so
explicitly test for throwAllErrors.
2013-06-04 17:53:37 -07:00
Sara Golemon fb60327fb0 Update Folly 2013-06-04 17:53:37 -07:00
Adam Simpkins f40b14aa63 Always require the register_libevent_server() function
Update CMakeLists.txt to force the linker to always pull in the
register_libevent_server(), even if none of the source files reference
it.  This is needed to register the "libevent" server type on startup.
2013-06-04 17:30:03 -07:00
Paul Tarjan ff25486f9f Revert cache size changes
This will need some love first
2013-06-04 17:11:55 -07:00
Paul Tarjan 4ee7a582d6 make caches exact multiples of 2 megs
This is the page size and will cause weird segfaults if they aren't multiples.
2013-06-04 17:54:46 -06:00
Paul Tarjan ab4b5ce72a Update .travis.yml
Now with the smaller cache sizes, can we support 4 threads?
2013-06-04 17:21:45 -06:00
Paul Tarjan 37edc8b56e Update .travis.yml
test/slow/locale/176.php depends on this locale being present
2013-06-04 17:19:34 -06:00
Paul Tarjan 628487943f a bit more? 2013-06-04 15:27:50 -07:00
Paul Tarjan 1646097b50 try less RAM 2013-06-04 14:19:34 -07:00
Paul Tarjan fcfc758672 try slow 2013-06-04 13:38:37 -07:00
Jan Oravec 8834f9211b Embed ContReceive into UnpackCont
Hoist ContReceive to the beginning of continuation body and make it part
of UnpackCont. This is a preparation for passing m_received thru the
stack.
2013-06-03 23:54:41 -07:00
Alexandru Suhan 93edca4397 Smaller c_Continuation
Save 16 bytes in c_Continuation by moving running and done flags to o_subclassData and making labels 2-byte.
2013-06-03 23:54:41 -07:00
Adam Simpkins be42cb5fdc add a ServerFactory class
This refactors the Server creation code, to make it easier to create new
Server implementations in the future, and to separate the LibEventServer
code from the main hphp_runtime library.

This defines a new ServerFactory interface, and a ServerFactoryRegistry
which maintains a mapping of server type strings to ServerFactory
objects.  The HttpServer code now uses a ServerFactory to create the
m_pageServer, rather than directly creating a LibEventServer object.
2013-06-03 23:54:40 -07:00
Adam Simpkins 31d042061c move warmup thread functionality out of LibEventServer
This moves the warmup thread logic from LibEventServer to a new
WarmupRequestHandler class.  This will allow the logic to work with any
server implementation, since it isn't really specific to LibEventServer.
(Eventually it would perhaps be nice to decouple the worker thread
behavior from the server I/O implementation entirely.)
2013-06-03 23:54:40 -07:00
Adam Simpkins b69fe9baf1 move addTakeoverListener() to the Server API
Make addTakeoverListener() part of the top-level server API, instead of
being specific to LibEventServerWithTakeover.  Servers that don't
support socket takeover simply ignore this call.

This will allow future server implementations to support socket
takeover.  This also allows us to start making the server creation logic
in HttpServer a bit more generic, since the code can always call
addTakeoverListener() without having to know if it really has a
LibEventServerWithTakeover or some other type of server.
2013-06-03 23:54:40 -07:00
Adam Simpkins e7a5f77b35 replace Server::shouldHandle() with a std::function
Change the Server API so that users don't have to subclass it in order
to override shouldHandle().  Now users can specify a custom
std::function for checking allowed URLs.

This will make it easier to provide alternative Server implementations.
Previously InternalPageServerImpl had to subclass LibEventServer in
order to override shouldHandle().  This tied the code to LibEventServer,
so that it could not be easily changed to an alternative implementation.

It seems like this URL checking functionality should perhaps be moved
into the RequestHandler.  However, for now this is a simpler change.
2013-06-03 23:54:39 -07:00
Adam Simpkins ee27bfa147 refactor RequestHandler behavior
This refactors the RequestHandler code, to decouple RequestHandler
behavior from the Server implementation.  The goal is to make it easier
to define additional Server implementations, in addition to just
LibEventServer.

This adds a RequestHandlerFactory function, rather than using a pure
virtual method of the Server class.  With the old model, you had to
subclass each server implementation separately for each RequestHandler
type you wanted to use, resulting in NxM classes if you have N server
types and M request handler types.

This also changes the behavior of the RequestHandler class somewhat:
the code now only creates a single RequestHandler per thread, and uses
that object for all request in that thread.  Previously the
LibEventServer code would attempt to create a new RequestHandler object
for each request if supportReset() returned true.  This was used by
RPCRequestHandler.  Now the RPCRequestHandler instead just resets itself
automatically when necessary, without requiring external help from
LibEventServer.

contbuild test runs failed due to git server issues.
2013-06-03 23:54:39 -07:00
Jan Oravec e6bd76e3fd Kill m_should_throw
Do not check for m_should_throw from ContReceive. Add a label used by
ContRaise pointing to Throw emitted by the Yield instead.
2013-06-03 23:54:39 -07:00
Drew Paroski a41fb387a7 Fix parsing for generic constraints with the "as" keyword
For generic constraints, the grammar (incorrectly) did not allow for
generic types on the right hand side of the "as" keyword. This diff fixes
the grammar appropriately.
2013-06-03 23:54:38 -07:00
Paul Tarjan 9519cefd00 fix parser tests
I was quite stupid in my rewrite and totally broke this. Wow, it runs fast!

I had to switch to `HHVM_BIN` as the env var, since it seems we force `HHVM` to 1 all the time...
2013-06-03 23:54:38 -07:00
bsimmers 8987de3e84 Remove immstack.cpp
It's dead but I missed it in my previous diff
2013-06-03 23:54:37 -07:00
Paul Tarjan ca5b712ddd resolve potentially global namespaced functions
When we see `define('Foo', 'Bar')` in a namespace, we don't know if it is talking about the global define function or the a local namespace one. What should we do? Does marking constants Dynamic that aren't actually dynamic break anything? Without this, HPHP creates a creates a CodeError.js

Closes #771
2013-06-03 23:54:37 -07:00
mwilliams 013c18b1f8 Fixup lots of include paths
This fixes most remaining paths to be relative to the git root.
2013-06-03 23:54:37 -07:00
Sean Cannella 722c0bd2d0 overrides need to come after defaults in test/run
- reverse order of default and test args so test args override
2013-06-03 23:54:36 -07:00
mwilliams f5387771e6 Fix overloading issues with Variant::nullInit
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.
2013-06-03 23:54:36 -07:00
Mike Magruder cdc4a8eee5 Remove generated generator function name from test
Get the generated function names out of the test output.
2013-06-03 23:54:36 -07:00
Owen Yamauchi 739450013f Move runtime/eval/debugger to runtime/debugger
runtime/eval is now gone. Woooo

This is just a git mv + `codemod runtime/eval/debugger runtime/debugger`
2013-06-03 23:54:35 -07:00
Mike Magruder 609abd866f Fix step out bugs (also effects Next)
We had a lot of odd behavior with both Next and Out. Previously the debugger would interpret the world until it saw that it was no longer on a specific line, or at a specific stack depth. I changed it recently to let the program run normally, and use an internal breakpoint to control step outs. Next's become like a step out temporarily when you descend into a function and need to get back out to the original line, so some bugs with out showed as bugs with Next, too.

Specifically, any time more PHP code was executed as a "side-effect" of a non-fcall instruction, step out would get lost. In these cases the stack trace gives us the offset of the instruction causing the PHP to run, not the instruction that control will return to as is the case with a Fcall. A breakpoint set there would get missed. This changes the step out logic to recognize such cases (via the fact that a nested VM state was pushed to execute the code) and step out more intelligently. We look at the instruction in question, and determine where execution may go, which might be multiple places. I also made a small change to ensure that we don't stop in generated functions when stepping out, which cleans up the iterator experience quite a bit, and sets us up for proper generator stepping, which will come next.
2013-06-03 23:54:35 -07:00
Owen Yamauchi 9494a366b5 Move runtime/eval/runtime/file_repository.* to runtime/base
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.
2013-06-03 23:54:34 -07:00
Paul Tarjan 8eaa77f319 rejigger systemlib
I've always been a bit sad about having all classes in the same file to govern inclusion order. And the filenames didn't match the class names.

Instead, lets not rely on whatever order `find` returns, and instead hard-code the ordering of the system lib. I grouped the files by what extension they came from.
2013-06-03 23:54:26 -07:00
mwilliams 6b50ac0477 Fix PACKED_TV test failures
In the PACKED_TV build, two tests were failing due to treating
the type as a 32 bit field.
2013-06-03 12:44:07 -07:00
Tim Starling 998951619f update copyright date
We did not intend to imply our copyrights last forever

Closes #759
2013-06-03 12:43:56 -07:00
Paul Tarjan f3abe784d4 make all tests the default
I think this is easier to explain
2013-06-03 12:21:16 -07:00
mwilliams 98de876586 Fix uses of FBMAKE_BIN_ROOT
Its supposed to be a relative path from the fbcode dir,
but various tools assumed it was an absolute path.

In particular, test/run failed if it was set, but was
not an absolute path, and tools/run_test_binary.sh failed
if it was set and was an absolute path.
2013-06-03 10:55:24 -07:00
Paul Tarjan 7f4e3c39d6 implement SplFileObject
This diff started off with trying to actually build `SplFileObject` since it was just stubbed out. But then I had to implement everything that extended from it since C++ classes can't extend PHP classes. And then it ballooend into what you see here. I actually think this is better in the long run, so that's why I kept going down this road.

The only thing that doesn't work in pure PHP is `sscanf`. @mwilliams has a fix for that. We need variable args by reference.

I implemented `RecursiveIteratorIterator` in a similar way to our C++ code instead of copying Zend. It translated to PHP a bit nicer. We still don't support the `RecursiveTreeIterator`, but I havn't come accross a need for that yet. I changed the implementation to actually use the `getChildren()` methods instead of peaking inside the `RecursiveDirectoryIterator`.
2013-06-03 10:55:24 -07:00
Paul Tarjan ae636a0a85 stop warnings
##hphp_471## isn't building. Lets try this. (It is also correct I think)
2013-06-03 10:55:05 -07:00
Jan Oravec 58c030adc8 Fix race condition in ExternalThreadEvents
A race condition can occur when the processing thread tries to notify
condition that is not yet waited upon. This can happen during the short
window in the web request thread between transitioning to the WAITING
state and calling condition.wait().

Fix this by locking mutex right before notifying the condition. If the
web request thread is in WAITING state, it is guaranteed to hold the
mutex or wait for condition variable. If the processing thread was able
to transition away from the WAITING state and grabbed the lock, the web
request thread must be waiting on condition variable, so it is safe to
notify it.

Thanks @andrii for tracking the bug down to ExternalThreadEvents and
providing a workaround (grabbing the mutex few lines up than this diff).
2013-06-03 10:55:04 -07:00
Jordan DeLong afa6d733c1 Some optimizations for LdClsCns
Change LdClsCns to side exit when the type is uninitialized.
On the exit path, do a LookupClsCns and ReqBindJmp for the next srckey
so forward progress is still made.  Add a predictionopts case for the
common case of a LdClsCns; CheckInit being followed again by a
CheckType---in this case, hoist all the checks into LdClsCns.
2013-06-03 10:55:04 -07:00
Jordan DeLong f008eafffe Move SrcKey out of translator.h and Transl:: @override-unit-failures
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.
2013-06-03 10:55:04 -07:00
Jordan DeLong d3f443efdf Remove unused member function 2013-06-03 10:55:04 -07:00
Jordan DeLong 05c607e0a7 Print objects of specific classes better in JIT::Type::toString @override-unit-failures
Right now it returns "{}".
2013-06-03 10:55:03 -07:00
Jordan DeLong 2e08484a68 Don't use CSEHash::filter in TraceBuilder::reoptimize @override-unit-failures
Since hitting in the CSE hash is probably more rare, just
wait to check that the cse-candidate dominates the instruction in the
target block until it is looked up.  For now doesn't remove the
1000-block limit on reoptimize (we'll do this soon when we have time
to test it).
2013-06-03 10:55:03 -07:00
Edwin Smith 94a9ad531b A few more accessors losing their get prefixes
More verbose accessors becoming less verbosely named.
2013-06-03 10:55:03 -07:00
mwilliams 3f33747091 Implement array_filter and array_map in php
There's a lot less overhead calling the callbacks from php,
and now we have bytecode support for "withref" operations,
they're much faster.
2013-06-03 10:55:03 -07:00
mwilliams b1eedaa49f Change semantics of DecodeCufIter
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.
2013-06-03 10:54:44 -07:00
Owen Yamauchi dfae726e62 Fix unsatisfied order dependency in systemlib
SplPriorityQueue depends on SplHeap. Make sure SplHeap appears first.
2013-06-03 10:54:44 -07:00
bsimmers cf197fee81 Collapse runtime/vm/translator's contents into runtime/vm/jit
Facebook: ~bsimmers/bin/move-vm-files.sh
2013-06-03 10:54:43 -07:00
aravind a686bd4ca1 Remove BPass* instructions 2013-06-03 10:54:40 -07:00
bsimmers 991c1e3bdb Rip out preconsts
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.
2013-06-03 10:54:40 -07:00
Paul Tarjan bec594ceda disabled tests that only test underlying library
I'd rather not do this, but can't think of another good way. These 4 tests are failing on our opensource build since the image librarys are different there. The files they made end up looking the same but the bytes are different.

I just recently re-enabled these tests as they were a big comment (which I assumed was by accident) in the PHP-in-C++ version. (I'm using that to justify that we weren't covered before).
2013-06-03 10:54:40 -07:00
Herman Venter fd977f7091 Expose a config file option for turning of colorization in hphpd output.
Expected test output for hphpd command line tests is difficult to read when colorization is present. Although there was an internal switch to turn off colorization (for the benefit of API clients), there was no command line option and no config file option to turn off colorization. This diff adds such an option and also fixes a few places where colorization was added regardless of the value of the internal switch.
2013-06-03 10:54:40 -07:00
Drew Paroski 9e1e4e0573 Revert "Rename closures and generators"
This reverts commit f9e1a492285d27021ba50c49049823e7516edb6a.
2013-06-03 10:54:39 -07:00
bsimmers 687164d21b Kill more of tx64
I started by just killing a few unused flags from
NormalizedInstruction and then deleted things that were even slightly
related (and things that depended on them, etc...).
2013-06-03 10:54:39 -07:00
Jordan DeLong 9adc532349 Fix a type bug in BindS and BindG
They should load as a V not a C.
2013-06-03 10:54:39 -07:00
bsimmers 9272f42a88 Fix a lint error 2013-06-03 10:54:38 -07:00
mwilliams 12b768a06a Make exif parser more robust
Currently, as soon as it finds a bad field, it gives up.
Some android devices consistently create a bad field (that
we dont care about) right before fields that we do care about
(the orientation, in particular).

Most exif parsers just move on to the next field in this case;
this changes ours to do the same.
2013-06-03 10:54:38 -07:00
Bert Maher 8e34cbdf15 Allow CSE of ArrayGet by converting to IncRef
ArrayGet has fairly minimal side-effects: IncRef of its
result, and raising a warning if the element is undefined.  To CSE
ArrayGet, replace it with an IncRef of its destination.  Raising
multiple warnings for repeated accesses doesn't seem to have much
value, so just ignore them.
2013-06-03 10:54:38 -07:00
mwilliams 785b07cc42 Fix some hhbc verifier bugs
With these changes, we can run

  HHVM_ALWAYS_VERIFY=1 HHVM_VERIFY_VERBOSE=1 hhvm

without crashing.
2013-06-03 10:54:38 -07:00
Edwin Smith 8e78ddd0b1 More get-ectomy in IR code.
This is about all I plan on doing for now.  Simple accessors
lost their 'get' prefix.  Complicated functions are either still
called getWhatever, or got renamed (genWhatever, makeWhatever).
2013-06-03 10:54:37 -07:00
Guilherme Ottoni 97e2eac6a7 Relax more guards
This diff significantly generalizes guard relaxation and adds support
for more bytecode instructions.  Before, only CGetL, SetL, RetC, and
RetV were able to relax their inputs, and only in limited ways,
e.g. if their outputs were not used or only used in specific ways.
The new approach follows how the input types flow into the output
types, thus allowing dependencies to be relaxed even if they feed a
chain of values through the tracelet.

This diff also add support for relaxing inputs for the following
bytecode instructions:
  - Pop*
  - FCall
  - FCallArray
  - AddElemC
  - ArrayIdx
  - SetS
  - SetG
  - ContPack
  - ContRetC
  - ContHandle

The spill area was also increased (from 16 to 32 cells) since relaxed
dependencies increase register pressure -- relaxed types are not
immediates that can be burned in and need to reside in registers
instead.
2013-06-03 10:54:37 -07:00
Herman Venter 5a9d8751af Move the debugger command line test out of the C++ debugger test harness and use the standard harness.
Added a tweak to test/run to make it look for $test.in and, if there is one, to add <$test.in to the command line for running the test. Together with $file.opts and a config.hdf, this makes it possible to fire up a command line debugger for php, feed it with commands, obtain its output and check it against expected output.
2013-06-03 10:54:37 -07:00
Jan Oravec 817d94ebe1 Change iter_value() to return TypedValue*
Make internal iterator API return a TypedValue* instead of Variant. This
makes it possible to use the same API to update the value in-place
(except for Set, which returns const TypedValue*) and provide optimized
iterator that avoids unnecessary ref counts.
2013-06-03 10:54:36 -07:00
Sara Golemon 25e430f996 Update md5_file() and sha1_file() to use hash's streaming digest
For large files, the old approach would potentially
allocate ridiculous amounts of extra memory.  Let's not do that.
2013-06-03 10:54:36 -07:00
Paul Tarjan baceec1cb7 make test runner better
Some suggestions after talking to @bsimmers

* Print failing tests and diffs as it runs
* Remove the list of failed tests at the end (since they print as you go) and instead give a one-liner to re-run failed tests.
* Use moar colorz!
2013-06-03 10:54:36 -07:00
Paul Tarjan ae4d1a0def fix callble typehint in interp mode
Somehow the JIT doesn't hit this codepath, but with interp mode the param is a string, but we think `callable` means an object of type callable.

I hate to hadd another top-level if statement to every call. Would a switch statement on the type be better?
2013-06-03 10:54:36 -07:00
Paul Tarjan 0204047cce use 2 threads
1 took way too long...
2013-05-31 13:19:52 -07:00
Paul Tarjan df5730104c single-thread the tests
I'm worried there is memory pressures. Better safe than sorry for now.
2013-05-31 13:31:24 -06:00
Paul Tarjan 68e6cf3ba8 use --arg
Drew hasn't fixed argument parsing yet
2013-05-31 13:11:53 -06:00
Paul Tarjan 56964b4ea7 only use 8 threads
Travis was running out of memory. I also use 8 for compiling.
2013-05-31 12:52:39 -06:00
Paul Tarjan 8a29e9e6c8 Run all tests together
That way you don't depend on the previous suite passing
2013-05-31 12:37:14 -06:00
Paul Tarjan 40093d5bda Add zend tests to travis
With the updated systemlib they should pass
2013-05-31 12:25:49 -06:00
Sara Golemon b759586f06 Merge branch 'master' of https://github.com/facebook/hiphop-php 2013-05-31 11:20:33 -07:00
Sara Golemon 6bd13308da Update systemlib from source files.
Failed to generated this during the last push.
2013-05-31 11:19:51 -07:00
Paul Tarjan 0eef7b5935 Run quick tests in travis
The slow ones seems to abort halfway through, and a few zend ones aren't passing right now. :(
2013-05-31 12:12:52 -06:00
mwilliams 716a01c85e Kill lots of tx64
Its dead
2013-05-30 17:39:25 -07:00
bsimmers 8733cdc4f3 Run hhir exit traces during unwinding; don't spillstack before most helpers
Most of the SpillStacks we do are just to keep the in-memory VM stack
clean in case a helper call throws an exception. Many of these exceptions are
vanishingly rare, so let's stop making the fast path slower for them. This diff
adds support for catch traces, which are just like normal exit traces with one
major exception: they're never jumped to from translated code. If we're
unwinding a TC frame and discover that the current rip has a catch trace
registered, the unwinder will execute it before resuming unwinding.

The unwinder parts were fairly straightfoward, then I ran into a bunch of
issues with SetM. The SetElem instruction sometimes consumes a reference to one
of its inputs, which is bad news for our optimizations. To make everything work
again, I changed SetElem to throw an exception in cases where it would've
previously decreffed the value input. This is a special exception that the new
unwinding code recognizes. When one of these is caught, the catch trace
executed for that TC frame will finish up the vector instruction and push the
value provided by the exception on the stack. This allows us to optimize most
traces under the assumption that SetM's output is the same as its input,
letting the catch trace clean things up if the helper decides that's not the
case and throws.

There is one common case where SetM's output isn't the same as its input:
setting an offset in a string base returns a new String. Luckily, we can detect
most of these at compile time so SetElem returns a new StringData* when the
base is known to be a string. If the base might be a string, SetElem will
return nullptr if the base wasn't a string, and a StringData* if it was. We
test the output in these cases and side exit if the return value of SetElem is
non-null (I have yet to see this side exit happen outside of artificially
created test cases).

Once I got things working in the vector translator, I went through every other
call to spillStack and exceptionBarrier, replacing them with catch traces as
appropriate.
2013-05-30 17:39:25 -07:00
Paul Tarjan 677900f05d Use a pretty ascii art boat for all tests passed.
From http://www.chris.com/ASCII/index.php?art=transportation/nautical
2013-05-30 17:39:24 -07:00
Paul Tarjan ebf437281c Don't escape exception error messages in command line mode
The main impetuous was "\" is the namespace character, so I want namespace errors to not have double backslashes everywhere.

After finding that, it turned out we were escaping all exceptions in the command line, which is wrong. We only want the escaping when we are in server mode (emulating apache)

I basically pushed what we were doing in ##error_log## down to ##Logger::Log##.
2013-05-30 17:39:24 -07:00
Paul Tarjan 4022b5240a add SplPriorityQueue
Tons of copypasta from `SplHeap`. I'd love a better way...
2013-05-30 17:39:24 -07:00
Owen Yamauchi 494adcb2f4 Clean up HPHP flags a little bit
Some of this is trivial stuff -- flags that aren't even referenced except to read
them from the command line. I removed a few more that weren't used in
any meaningful way.

I figure we could also stand to remove --nofork, since "freeing up
memory for g++" isn't a concern anymore, but I figured it might still be
useful somehow.
2013-05-30 17:39:23 -07:00
Edwin Smith 0b599e48fa Remove old memlim code.
This has been turned off for about a month and is hopelessly
bitrotted.
2013-05-30 17:39:23 -07:00
Jan Oravec 57f1460cc7 Use virtual method return type covariance in clone()
Let clone() return pointer to the actual type instead of returning
pointer to generic ObjectData. Avoids unnecessary static casts.
2013-05-30 17:39:23 -07:00
Herman Venter 0cdf54a970 Insert new lines between object properties when serializing with DebuggerDump
DebuggerDump did not separate object properties with new lines. Now that it is used for cases with PrintR was previously used, the new behavior should be to insert the new lines.
2013-05-30 17:39:22 -07:00
Owen Yamauchi fee428f6fb Some compatibility changes for more recent versions of boost
- boost::shared_ptr now has "explicit operator bool", which means we
  can't "return <a shared ptr>" from a function with return type bool.

- Our use of shared_ptr<T[]> in debugger_client.h was screwed.
  Unfortunately it's not straightforward to make it a unique_ptr as per
  our discussion; there are other objects that call setLiveLists, and
  it's not clear to me that this is a total transfer of ownership. I'm
  just fixing the immediate problem using shared_array. (Also made the
  typedef less confusing, hopefully.)

- Our specialization of graph_traits<G> for ControlFlowGraph didn't
  define the null_vertex member function. This didn't matter in older
  versions of boost because they didn't use it internally, but now they
  do (the call to depth_first_search in control_flow.cpp was failing to
  compile).
2013-05-30 17:39:22 -07:00
Edwin Smith 92a4705514 Move the large-ish collections functions out of line.
These seem on the big side to make them inline, and the conversion
from string literals to StaticString is cleaner if the ones that
use string literals are not in headers.
2013-05-30 17:39:22 -07:00
Paul Tarjan d8d1e7f840 add simplexml_import_dom
This is needed for Symphony.

I copied the zend implementation and then cargocult programmed the rest from the other 2 functions in the file.

Closes #789
2013-05-30 17:39:21 -07:00
Paul Tarjan b4d4e630c3 rewrite test running in php and cleanup test output
I started cleaning up the perl script and then realized that it wasn't buying us much at all. So I changed the ##test/run## script to just do the executing of the ##hhvm## directly and printing the output.

While I was in there, I also made the ##verify_to_json.php## redundant by allowing different output formats, one of which fbmake can consume.

A good run looks like:

    $ test/run test/slow/array
    Running 68 tests in 20 threads
    ....................................................................
    All tests passed. Ship it!

and a bad run looks like:

  $ test/run test/zend/good/ext-bz2
  Running 5 tests in 5 threads
  ....F

  1 tests failed:
  test/zend/good/ext-bz2/002.php

  To run these by hand:
  hphp/hhvm/hhvm --config test/zend/config.hdf  -v Repo.Local.Mode=-- -v Repo.Central.Path=/data/users/ptarjan/other-git/fbcode/hphp/test/../../_bin/verify.hhbc -v Eval.Jit=true -v Eval.JitEnableRenameFunction=true -v Eval.EnableArgsInBacktraces=true --file test/zend/good/ext-bz2/002.php

I chose to not support the ##1..1## syntax since only 5 tests were using it.
2013-05-30 17:38:57 -07:00
mwilliams 78ca8ecbaa Add bytecodes to decode a function, and push an actrec for a decoded function
array_filter and friends only need to evaluate the callback once,
so add bytecodes to support that.

Depends on D817883
2013-05-30 17:33:05 -07:00
Edwin Smith 177f1add3e Make DefLabel optional at the front of a Block.
A DefLabel instruction with 0 destinations is a NOP, so make it
optional; only generate DefLabels when we need phi-parameters to
the block.
2013-05-30 17:33:04 -07:00
mwilliams c12714e2bb Add bytecodes for some "withRef" operations
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.
2013-05-30 17:33:04 -07:00
Guilherme Ottoni ec6ab13b15 Fix typos: MMX => XMM
I just noticed some stuff using MMX in their names where they should be XMM.
2013-05-30 17:33:03 -07:00
Herman Venter a9fa4568fe Always use DebuggerDump for printing values in hphpd client console.
The proximal purpose of this differential is to fix the debugger client so that it does not write raw strings to the console (with control characters doing their thing to the console and unprintable characters pretending not to exist). This change in behavior means that the serializer used to convert values to strings can no longer be instantiated with the PrintR option, as it has been in a subset of cases. (The reason being that print_r() must not change its behavior.)

Rather than introduce yet another serializer option, I decided to always make the debugger client serialize user visible values using the existing DebuggerDump option, which is already used in a number of such  cases and which has no other use. To make the overall change less painful for users, I preferred to change behavior of DebuggerDump to be more like PrintR in a number of cases, primarily the formatting of objects (where the current behavior is to make a JSON like string).

This does not impact the behavior of the debugger client API or the behavior of FBIDE, since these do their own thing directly with the DebuggerSerialization format and never see the result of the DebuggerDump format.
2013-05-30 17:33:03 -07:00
Sara Golemon 6927cf84e4 Objectify and clean up bootstrap programs.
Refactor a lot of idl.h/idl.cpp to be more generic and
make them easier for other bootstrap apps to build on.

This is a precursor for building infotabs/class_map generators
in cpp to remove the need for PHP during bootstrapping.

I'll also be git mving this to hphp/tools/bootstrap
in a follow-up move-only commit.
2013-05-30 17:33:03 -07:00
Sara Golemon c3193512d6 Pull DataType and related asserts/macros/inlines into separate header
Allows DataType to be referenced without having
to pull in the entire kitchen sink of hphp/runtime.

This will be used by the bootstrap process for creating
ext_hhvm, infotabs, constants, systemlib, and class_map.
2013-05-30 17:33:03 -07:00
Edwin Smith 8a8b27071f remove "get" from label, trace, block, hint, next, taken, extra
Makes the code less repetitive and easier to read
2013-05-30 17:33:02 -07:00
Jordan DeLong 0e7c8a33f2 Use an enum for SimpleFunctionCall::m_type instead of an int
It already had an enum, but wasn't using it.
2013-05-30 17:33:02 -07:00
mwilliams 71859e5566 Add support for .hhas files in systemlib
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.
2013-05-30 17:33:02 -07:00
Edwin Smith 0fabe930f8 Rename s/get// for id, src, dst, srcs, dsts, numSrcs, numDsts
Dropping the "get" prefix makes the code more readable.
Also srcReg(), dstReg().
2013-05-30 17:33:01 -07:00
Wez Furlong 5301896d35 fixup environment inheritance
obsoletes D825704?  populate our env array from environ,
then overlay local changes that were made to m_envs.

I didn't make this conditional on CLI but could if that is desirable.

I didn't tackle the allocate-after-fork issue that @jdelong raised in D825704
2013-05-30 17:33:01 -07:00
Jordan DeLong 1c0a6c9082 Remove some linear searches; use a vector instead of a list for BlockList
Less malloc and less linear search.  Also renames sortCfg,
since @smith told me he didn't like that name very much.  This still
makes use of the postId() field on each Block, which maybe still has
us leaving some trash in the Block structure that should be on the
side.  (These functions can be changed to take indexes later instead
if we want to kill that.)
2013-05-30 17:33:01 -07:00
Jordan DeLong e405aa7bce Remove hoistGuardToLoad
This doesn't happen, and if it did it would be incorrect,
since it assumes a getTaken() implies a side exit which is no longer
true.  We may bring back something similar to this for LdClsCns but
it'll be easy to do it at that point (and a bunch of the instructions
in here aren't used as guards/checks anymore).
2013-05-30 17:33:00 -07:00
Jordan DeLong 03c652cb3c Minor tweak for better StateVector error messages
If you use StateVector<Block*,...> or similar on accident,
you get a bunch of junk.  Add a static_assert so there's at least a
reasonable error in there somewhere.
2013-05-30 17:33:00 -07:00
Misha Shneerson 2e72a2aba5 Do not suppress exceptions thrown by PHP transport
Currerntly, if TServiceRouterTransport::flush throws an exception,
this exception is swallowed non-chalantly by Thrift's extension layer.
This should not happen.
2013-05-30 17:33:00 -07:00
Jan Oravec 935011733c Make AsioExternalThreadEvent::abandon() not hit assertion error
Destructor of AsioExternalThreadEvent uses assert() to check whether the
state is legal. Introduction of abandon() mechanism makes it possible to
destroy the AsioExternalThreadEvent in the Waiting state and hit the
assertion error.

This diff solves the problem by introducing Abandoned state.
2013-05-30 17:33:00 -07:00
Paul Tarjan 992cd4efb6 add FilesystemIterator
This was inserted as a class inbetween RecursiveArrayIterator and DirectoryIterator. Sadly our RecursiveArrayIterator implementaiton is crazy and calls into C++ which can't call back up to `parent::method()`. I'll fix RecursiveArrayIterator in another diff.
2013-05-30 17:32:59 -07:00
Jordan DeLong 9638191f2a Remove emitInterpOneOrPunt
It just calls emitInterpOne now.
2013-05-30 17:32:59 -07:00
Jordan DeLong f93b15f67d Remove weird IncRef thing in emitBindL
The comment is correct that doing the IncRef first is
necessary in pseudo mains.  However, I can't see any disadvantage to
not doing it first outside of them---IncRef/DecRefNZ elision still
seems to kick in in all cases I can think of.
2013-05-30 17:32:59 -07:00
Jordan DeLong 85aa9442ac Fix AddNewElemC bugs in HHIR
emitAddNewElemC didn't properly implement the specified
behavior for this opcode.  It assumed topC(1) was always an non-static
array with refcount 1 or 0.  This changes to interp the case when it's
not an array, and make the helper support static arrays.  (If it
matters for perf, we should engineer the bytecode spec to require this
as well, since the point of this opcode is initializing array literals
that can't be done as static arrays.)  In practice I think this is
only working because it always comes after a NewArray with a capacity
hint != 1, which means it's a newly allocated non-static array.
Ignoring the capacity hint would've broken it.
2013-05-30 17:32:59 -07:00
Edwin Smith cd734dec99 Eliminate ArrayInit.set(litstr)
In runtime code, use StaticString for literals or String for computed
char strings.  In test code, I justed used String("literal") to keep
the conversion simpler.  I think tests are ultimately easier to maintain
without the StaticString treatment.
2013-05-30 17:32:58 -07:00
Drew Paroski 13c4c29555 Revert "[hhvm] proc_open should inherit g_context->m_envs"
This reverts commit 0a03e2fdd8cfa1c7dd0a1f9b836443a6464d69b2.
2013-05-30 17:32:58 -07:00
Jordan DeLong aef3e1ea9b Finish ir.specification entries for remaining instructions
I was looking over the instruction table to try to understand
what may need to happen to make it easier for a memelim mark 2 to
track memory effects (on object properties and other memory
locations), and I made the mistake of documenting StProp and StPropNT
(currently unused).  This led to finishing the remaining missing
entries...
2013-05-30 17:32:58 -07:00
Paul Tarjan c2ec1c97c9 sortof format slow tests
A poor man's formatter since I didn't like any of the other ones I found. The original C++ source sometimes put newlines and sometimes not.

Codemods:

    codemod '([;{}])([^\n])' '\1\n\2'
    codemod -m '\s*<\?php\s+' '<?php\n\n'
    codemod '\t' '  '

I hand-fixed all the failing tests
2013-05-30 17:32:57 -07:00
Paul Tarjan 8ea73f74b2 Update README.md
-m server runs from the current directory
2013-05-29 19:16:07 -06:00
Edwin Smith 89237f753a Keep track of predecessors all the time.
Use a struct wrapping from and to Block* pointers to represent
control flow edges, keeping a predecessor list up to date whenever
edges are updated.  This subsumes EdgeData, which was only used
to track jumps that pass values.
2013-05-28 10:30:28 -07:00
Dario Russi e93120812a Extend the type system of the JIT (Type class) to allow for specialized Class instead of just Type::Obj
Allow RuntimeType to specify a more specific Type (by adding a Class*) and transfer that Class* to Type. Extended API to allow discovering when a Type is a subclass of Type::Obj
2013-05-28 10:30:28 -07:00
mwilliams 23919b915f Fix crash/hang in Parser::newClosureName
The parser was updating a static std::map without a lock.
It looks like this is supposed to be local to a file anyway,
so add the map as a member of ParserBase.
2013-05-28 10:30:27 -07:00
Jordan DeLong 4f3c0c15b4 Fix a bug in codegen block order; add a step to choose the order
Codegen had a bug where if you emit a block in astubs that
has a getNext() which is also in astubs, it would omit the jump.
However, it might visit another block in a first, which is allowed to
put code in astubs.  Generally the block order was just defined by the
order that happened to be in the block list by the time we get there.

Change it to emit blocks in the RPO defined by sortCfg for now, after
partitioning them into groups for a and astubs.  This fixes the bug,
and at least makes codegen use a defined order.  We later will
probably want to see about whether we may be able to avoid more jumps
with smarter layout.
2013-05-28 10:30:27 -07:00
Jordan DeLong 42a6039125 Fix a bug with debug_backtrace during an unwind
The change to stop zeroing locals during RetC was too
aggressive---we stopped doing it during unwinding also.  When
unwinding, we need to zero locals and $this because another
destructing object may still run debug_backtrace, and we won't have
the *pc == OpRet{C,V} trick to tell us to ignore the junk.
2013-05-28 10:30:27 -07:00
Edwin Smith 76546fceb5 Don't use RAND_bytes() under valgrind.
The results are marked uninitialized and trigger spew.
2013-05-28 10:30:26 -07:00
Edwin Smith 1664473ecb Use uppercase for RuntimeOption static methods.
Main style for static functions is UpperCase.
2013-05-28 10:30:26 -07:00
Paul Tarjan 7930598d18 indent function docblocks 2013-05-28 10:30:26 -07:00
Jordan DeLong 2751922302 Fix a fallthrough bug in TranslatorX64::smash
If smash is told to generate a forward jump to a target less
than 7 bytes away, it nops out the intermediate region.  It's
currently impossible for this to cause any issues (as far as I know),
but technically there can be other instructions in there.  I hit this
by randomizing the layout of blocks in codegen---if you place a block
consisting of only a short backward jump immediately after the block
containing the main trace exit, and then a fallthrough-ish translation
occurs, smash will nop out the short-jump block.
2013-05-28 10:30:25 -07:00
Paul Tarjan bd9f92da9a add SplHeap, SplMaxHeap, and SplMinHeap
closes #505
2013-05-28 10:30:25 -07:00
Jordan DeLong 362f69b6fe Fix an issue in the register allocator
An optimization I'm working on sent the register allocator a
CFG that looked like this:

  M0
  | \
  |  M1
  M3 | \
  |  |  E4
  |  M8
  | /
  M2
  |
  M5

The RPO was 0 1 8 4 3 2 5.

It assert-fails here because it visited E4 before M3, and it appears
this would incorrectly mark everything as free.

This diff changes the register allocator to skip all non-main-trace
blocks during the first pass over the CFG.  Then each exit block is
visited.
2013-05-28 10:30:25 -07:00
Jordan DeLong d51ab6e272 Make LdClsCns not CSE-able
If you load the same class constant multiple times in a
tracelet, this will extend the lifetime of the LdClsCns, and reuse it
at sites past the CheckInit guard.  It can generate incorrect code if
the LdClsCns has a type more specialized than Cell (because if the
unlikely branch happens, later code will reuse the uninit value that
was loaded), and if the type is less specialized it keeps two GPRs
live longer than probably makes sense.
2013-05-28 10:30:24 -07:00
Jordan DeLong e3bdb5123f Remove edges when dce eliminates a whole block
If DCE eliminates a block that ends with a Jmp_, two things
can currently go wrong.  One is that linearscan will still inspect the
incoming edge to try to precolor jump destinations and fail an assert;
the other is that the type of the DefLabel destination may be too
relaxed.

This diff adds a new checkCfg invariant that all incoming edges to a
DefLabel are in the block list for the trace, and weakens the assert
in linearscan so things still work if DCE is turned off but a block
becomes unreachable.  Also changes dce's removeUnreachable to
reflowTypes if it removes an incoming edge.
2013-05-28 10:30:16 -07:00
Keith Adams 26e23732d3 Inline CreateCont's with arguments.
Well, this was a lot easier than expected. Don't give up inlining Cont creation just because it takes args.
2013-05-28 10:30:16 -07:00
Guilherme Ottoni 975afed427 Use r15 instead of r13 in generic return dec-refs
This avoids a bad interaction with LinearScan, which saves the return
value in r13 and r14 around GenericRetDecRefs.  Effectively, this diff
ends up saving a push, a pop, and some stack adjustment in
GenericRetDecRefs.
2013-05-28 10:30:15 -07:00
aravind 841670cd26 clean up SharedMap
This diff cleans up some of the mess in SharedMap. The existing way of accessing values in ShareMap is SharedMap -> SharedVariant -> ImmutableMap -> SharedVariant. This diff changes it so that the path is reduced to SharedMap -> ImmutableMap (with inlined SharedVariants).
(Likewise for VectorData)

The hashing scheme in ImmutableMap is left unchanged (chaining with ->next pointers, though we could change it to something similar to HphpArray).
2013-05-28 10:30:15 -07:00
Paul Tarjan 98589f6e87 support IteratorAggregateClass
someone added this class but didn't really hook it up. This was breaking Symfony.
2013-05-28 10:30:15 -07:00
Paul Tarjan e30d6e377b fix thrift for namespaces
Thrift doesn't autoload the class, it just does a ##lookupClass##. We need to normalize it so the lookup doesn't fail.

Closes #775
2013-05-28 10:30:14 -07:00
Paul Tarjan abb171eb41 allow (clone)->bar() and (<xhp>)->bar()
People have asked for ##(new Foo)->bar()##, ##(clone Foo)->bar## and ##(<xhp>)->toString()##.
2013-05-28 10:30:07 -07:00
Paul Tarjan 56172bc9fc Merge pull request #791 from ptarjan/unused_var
fix unused variables in third-party
2013-05-25 12:25:57 -07:00
Paul Tarjan 70fd03a5e7 fix unused variables in third-party 2013-05-25 12:09:41 -07:00
Paul Tarjan 39ccf09e05 change to webchat
github does't link irc:// links. Great.
2013-05-24 16:38:32 -06:00
Paul Tarjan 6c0ddfefca Added IRC and CLA pdf 2013-05-24 16:22:15 -06:00
Paul Tarjan ed171866b7 update docs 2013-05-24 10:10:58 -07:00
Andrei Alexandrescu 6d365df98f HphpArray compact layout
ArrayData gets on a diet, down to 32 bytes
devirtualized destructor call in HphpArray::release()
aggressively inlined constructors for ArrayData (do away with defaulted arguments)
eliminate a dead memset() for the hashtable in HphpArray(uint size, const TypedValue* values)
2013-05-24 10:10:17 -07:00
Herman Venter 5f75fbcf69 Restore syntax for specifying a breakpoint using only a line number.
The special case got over looked in the recent breakpoint parser rewrite. This change is a small point fix that restores this functionality while perturbing as little else as possible.
2013-05-24 09:48:43 -07:00
Jordan DeLong f50482c213 Increase level of getRegType traces
These are at too low of a level.  (Most per-pass logs in
hhir: are starting at "5" right now, mostly because it used to be the
same TRACE as printir.  I've been putting detailed per-pass info at 6
or 7.)
2013-05-24 09:48:43 -07:00
Paul Tarjan 39d6a7f26a add $name to ReflectionParameter
This is in the docs http://www.php.net/manual/en/class.reflectionparameter.php and is used by Symfony
2013-05-24 09:48:43 -07:00
Paul Tarjan 2d105535f3 fix idl/sysdoc.php
They changed their html to have an extra attribute in the `div`.
2013-05-24 09:48:42 -07:00
Paul Tarjan cef8fcc6e3 add ArrayObject
This is a pure PHP implementation of ArrayObject. It does't match the reference semantics of zend's implementation, but it is much easier to build this in pure PHP, so its a good first step. It is better to have it like this, than to not have it at all.
2013-05-24 09:48:22 -07:00
Paul Tarjan 0666f0df1e add CLA
If people don't want to use the CLA tool (if they don't have a FB account for example), then they can print this, sign it, and return it to us.
2013-05-24 09:48:21 -07:00
bill fumerola d9de1a83e3 re-order includes to satisfy lint header order rule
"The associated header file of .cpp files should be included before any other includes. (This helps catch missing header file dependencies in the .h)"
2013-05-24 09:48:21 -07:00
Herman Venter 58760b99ae Serialize partial class instances using correct class name
When hphpd does a print instruction for a value that is an object, the object is serialized in the proxy (server) and then deserialized in the client. If the client VM does not have the class loaded, then the deserializer creates an instance of __PHP_Incomplete_Class and adds the class name to it as the value of a property called __PHP_Incomplete_Class_Name. This then shows up in the textual output of the print command, which is a bit confusing to say the least. Ironically the printed output is obtained by serializing the object instance.

The basic design seems OK to me: The proxy should send the client the raw data and then leave it up to the client to figure out how to format it and what elide. And in this case, if the client is accessed via the API, the caller gets the raw data. So, it does not seem like a great idea to get the proxy to format objects so that the client just has to print the string as received from the client.

Instead, this diff changes the object serializer so that when the PrintR option (debug output format) is specified, incomplete class instances are serialized with the class name obtained from the value of the __PHP_Incomplete_Class_Name (if present) and the property itself is elided from the output.
2013-05-23 21:03:07 -07:00
mwilliams bec724926c Fix crash in hphp
The AnalysisResult for systemlib.php was allowed to go out of
scope, taking the FileScope with it, causing us to crash when
trying to flatten systemlib traits.
2013-05-23 21:03:06 -07:00
Paul Tarjan d4f57cbe3e add dom_import_simplexml
Needed for Symphony. We are labelling the dom extension as unsupported, is that still correct @sgolemon?

The iffiest part of the diff is new-ing up the ##c_DOMDocument##. Is that right?
2013-05-23 21:03:06 -07:00
Paul Tarjan c02df18f78 don't show Closure in get_declared_classes()
This was the fastest thing I could think of. Would string searching the name be better?

No user class can extend from Closure, so we're ok on that front.
2013-05-23 21:03:05 -07:00
Guilherme Ottoni 1cd5784ef6 Allocate XMM registers for some SSATmps requiring 2 64-bit regs
This diff allocates some SSATmps requiring 2 64-bit registers (value
and type) to a full XMM register, instead of allocating them to 2
64-bit GP registers.  If all def/uses of such SSATmp are simple
loads/stores from/to memory, then they're considered for allocation to
a full XMM register.

Since all XMM registers are caller-saved, an exception is made for
SSATmps crossing native calls.  In this case, if there are
callee-saved GP registers available, the SSATmp will be allocated to
them.

Also, I cleaned up code-gen for RetVal to use cgStore, and renamed the
IR instruction to StRetVal.
2013-05-23 21:03:05 -07:00
Guilherme Ottoni 7f19d85acc Kill translator-x64-vector.cpp, again
It ressurected somehow.
2013-05-23 21:03:05 -07:00
Alexandru Suhan eb5d2d1f00 CGetS output type prediction 2013-05-23 21:03:04 -07:00
Sean Cannella 685af88ccf fix file/class in backtraces involving traits
- non-repo mode: use fullName() instead of flawed logic in type constraint failures
- repo mode: save the original filename when flattening traits
2013-05-23 21:03:04 -07:00
Guilherme Ottoni a12865c040 Reserve r11 for code-gen's scratch fallback
This diff reserves r11 for the GP scratch register used by the
CodeGenerator (in case no better register is available). rScratch
(r10) is now reserved for the assembler, and was renamed to rAsm.
This avoids a class of subtle bugs where code-gen mixed uses of
rScratch with calls to the assembler that could also make use of this
register.  (Tx64 code still uses rScratch/rAsm for now.)

While here, also moved the reserved XMM scratch registers from the
assembler to CodeGenerator, since the assembler doesn't really use
them.  (The uses of these registers in Tx64 were renamed back to
xmm0/xmm1 as they were until recently.)
2013-05-23 21:03:04 -07:00
bill fumerola 771c423868 expose Vector->count() for use inside hphp 2013-05-23 21:03:03 -07:00
aravind 3ebcd53563 Revert "HphpArray" 2013-05-23 21:02:52 -07:00
Jordan DeLong ecc6a44af6 Hoist CheckType instructions above generic IncRef/LdMem @override-unit-failures
Because we normally find out about a type prediction at hhbc
bounderies, sometimes we generate type checks after we've already done
some generic operations on Cells.  This optimizes a specific pattern
of this that occurs in vector translations.  The code is set up as if
there is more than one since I have another case partially
implemented, but it currently hits issues in both linearscan and
codegen that need to be addressed first, so I split the diff for now.
2013-05-23 20:02:42 -07:00
Jordan DeLong 0b763991b6 New Block invariant
It's a little hard to reason about how lastMarker works in
codegen wrt blocks that don't have Marker.  In a optimization pass for
hoisting CheckType instructions I'm running into cases where I'd have
to track arbitrarily far backward in the main trace to find a Marker
that needs to go into the exit trace; it seemed simpler to just always
have a Marker in the front of each block.
2013-05-23 20:02:42 -07:00
mwilliams 4215e2b9d4 Fix defaults for preg ini settings
Use the RuntimeOptions, rather than hard-coding them
2013-05-23 20:02:41 -07:00
Guilherme Ottoni f3f3e0b48e Optimize ContSend, ContRaise, and ContNext for m_received being null
Make sure m_received is always null at ContSend, ContRaise,
and ContNext, and this information to generate better code for these
bytecode instructions.
2013-05-23 20:02:41 -07:00
Guilherme Ottoni d04d06c735 Increase spill area
Bump it from 8 to 16 Cells.
2013-05-23 20:02:41 -07:00
Andrei Alexandrescu fe73940a51 Refactor copyImpl() and nonSmartCopy()
I've done this refactoring without efficiency in mind - it's one of the steps toward more aggressive in-situ allocation. Yet to my surprise perflab rewarded this simple refactoring with a whopping decrease in I-TLB misses. I myself am wondering what has caused this. Anyhow let's run perflab once more and get this baby on the road.
2013-05-23 20:02:41 -07:00
Paul Tarjan 7059bc285f move test
StringBuffer is aparantly a facebook only thing
2013-05-23 20:02:40 -07:00
Paul Tarjan ceab90edaf is_dir should be false for false
This is breaking Symphony
2013-05-23 20:02:40 -07:00
aravind fec5acd7ec Treadmill for shared variants
Avoids atomic incRefs and decRefs. StringData no longer needs to
be sweepable for SharedVariants.
2013-05-23 20:02:40 -07:00
Chip Turner 65c4109224 Fix idl generation
Make idl generation work; properly use hphp/ paths, tweak some
out-dated names, etc.
2013-05-23 20:02:39 -07:00
Sean Cannella bdc1644753 gen_systemlib.sh should use passed-in files
gen_systemlib.sh currently takes a list of input files and then ignores them
2013-05-23 20:00:58 -07:00
aravind c51bb67028 Use AtomicHashArray for PCRE 2013-05-23 18:57:03 -07:00
Paul Tarjan c1705cb7c8 !bool != bool
I should have tested it :( While I was in there debugging I found some dead code

Closes #771
2013-05-23 18:56:55 -07:00
Owen Yamauchi dd43894685 Fix printing of ActRecInfo
If it's an AR for a constructor, the high-order bit is set, and it gets printed
as -2 billion. This is confusing; at first I thought it was a bug. Print it out
in a readable way.
2013-05-23 18:56:45 -07:00
Paul Tarjan 17c75f16d1 stop spew
The open source build complains about these: https://travis-ci.org/facebook/hiphop-php
2013-05-23 18:17:27 -07:00
Paul Tarjan 4f48bb7052 don't create an empty String
@mwilliams reminded me variables declarations actually make them.
2013-05-23 18:16:56 -07:00
bsimmers c4161ae787 Turn SrcRec
There's no compelling reason for this to be a fixed
constant. I also renamed EvalMaxTrans in an attempt to differentiate
it from the new option.
2013-05-23 17:08:18 -07:00
Sara Golemon fd2cc271b6 Update folly 2013-05-23 14:36:08 -07:00
bsimmers a9f529a91a Add TranslArgs and delete a bunch of tx64 code
I want to add a new argument to translateTracelet. Rather
than plumbing it through the many functions in the translation stack,
let's use an options struct. Dealing with the many bools we had flying
around controlling hhir was complicating things, so I removed
m_useHHIR and collapsed them all into an "interp" bool in
TranslArgs. I removed any code that was clearly unreachable from these
changes.
2013-05-21 11:17:37 -07:00
bsimmers 21b545f297 Nuke translator-x64-vector.cpp
Most of it was dead code. The few helpers that are still used
were moved to translator.cpp.
2013-05-21 11:17:36 -07:00
Andrei Alexandrescu 872d24b761 HphpArray
I've run a bunch of experiments on HphpArray speed and am still yet to have a major breakthrough. However, there are a few clear small winners that I'm submitting with this diff. CPU instructions, CPU loads, and CPU stores are all as green as the Eternal Hunting Grounds. Speed is drowned in noise but I sususpect will be measurable on these changes combined.
2013-05-21 11:17:36 -07:00
Drew Paroski 110f05277c Fix hphpd to not raise a notice when no file is given at the command line
"hhvm -m debug" without specifying a file should work without raising
notices. hphp_invoke_simple() and friends used to (incorrectly) tolerate
using an empty string for the file name, and hphpd was relying on this.

This diff fixes hphpd to not call hphp_invoke_simple() when no file was
given at the command line.
2013-05-21 11:17:36 -07:00
Paul Tarjan 9006ed7c1b idx is NOT a builtin
@seanc This is the second time... Third time we should figure out a solution
2013-05-21 11:17:35 -07:00
Sean Cannella 05a8a8d7ca Rewrite idx in PHP using IR instruction for hot path
- Do the actual work of implementing idx() in PHP
- Remove the old C++ builtin (which needs to be done at the same time)
- Remove OSS test dependencies on idx()
2013-05-21 11:17:35 -07:00
Erling Ellingsen dcf471996e Fix shapes
The keys were dropped.
2013-05-21 11:17:35 -07:00
Guilherme Ottoni d5657a46cf Fix propagation of predicted function-return types
Tx64 had an optimization in planPop() to avoid dec-refing a function
return value that's predicted by the front-end to be of a
non-ref-counted type.  This optimization was clearing the
outputPredicted flag in the NormalizedInstruction, thus preventing
HHIR from getting those predictions. So, I got rid of the optimization
in Tx64 to allow HHIR to get those predictions.
2013-05-21 11:17:34 -07:00
Mike Magruder 35e171458f Add client- and server-side logging to the debugger
Log details about debugger usage from both client and server side. Added a new runtime option to control whether the logging is used or not. There's a base class for a usage logger defined and used under runtime/eval/debugger.
2013-05-21 11:17:34 -07:00
Paul Tarjan c798a717b8 change version string
Now that we have all the 5.4 features, should we bump the version up? I wanted to pick the most recent version number, but we aren't really comparable since we aren't tracking the bugfixes. We might have them, we might not. I think we should just be the highest version of 5.4 so that all software tries to run us. Then we should expose our own version number incase software really needs some fixes from our tree.
2013-05-21 11:17:33 -07:00
Jordan DeLong f9c18fafd6 Rename jumpsopts to jumpopts 2013-05-21 11:17:33 -07:00
Paul Tarjan a9f7fee483 kill tryLockWait
There is no calls to `tryLockWait` in the codebase, and OSX doesn't have the underlying function, so why do we have it? It was added in D299757 with no callers.
2013-05-21 11:17:33 -07:00
Paul Tarjan 4d2e8af379 kill SpinLock
It is unused (and not implemented on OSX) so killing it seems good. It was introduced in rFBCODEe991769c74e876f345e2cd92edf1d970801e884b with no users.
2013-05-21 11:17:32 -07:00
Jordan DeLong c14f38d855 Mark all stack values available in an inlined callee
For DecRef -> DecRefNZ transitions.  Any value on the stack
at the callsite must outlive the callee.
2013-05-21 11:17:32 -07:00
Daniel Sloof 33817be827 change segment name for osx
OSX requires a comma after segment name. The segment name must also not be longer than 16 characters.

Pull Request: https://github.com/facebook/hiphop-php/pull/781
2013-05-21 11:16:51 -07:00
Paul Tarjan 6ef9d37225 fix builtin extension tests
In D804289 I scrwed up and needed a ##/g## in my script...
2013-05-21 11:12:06 -07:00
Paul Tarjan b2de6fb9da fix segfault for wikimedia
If you call a static method on a instance, we decRef the object before running the method. If that is the last reference to the object, then its destructor will be called right in the middle of setting up the ActRec for the static method. Currently, the top of the stack will be off by 2 Cells because we have already popped off one Cell (the object) and an ActRec takes up 3 Cells.

Instead, we have to have the top of the stack to be after the ActRec that we are building for the next method call.
2013-05-21 11:12:05 -07:00
Paul Tarjan e208a339d1 cleanup temporary test things
I hope our muscle memory has forgotten all these :)
2013-05-21 11:12:05 -07:00
mwilliams 227b3b7cc2 Fix bug with boxed type hints
We assumed the inner type remained the same from invocation
to invocation without guarding on it.
2013-05-21 11:12:05 -07:00
Sean Cannella 22a1609d50 remove hhir references from test runner
- remove dangling references to hhir now that it is gone
2013-05-21 11:12:05 -07:00
Jordan DeLong 943acd54c6 Fix a bug in hphp/test/run 2013-05-21 11:12:04 -07:00
Sara Golemon be9f36d3bc Always look for crypt lib, don't look for iconv twice 2013-05-20 17:07:08 -07:00
bsimmers 733abb2799 Move JIT 2013-05-20 14:41:00 -07:00
bsimmers f323a90b12 Kill runtime options related to turning off the IR 2013-05-20 14:41:00 -07:00
Paul Tarjan e1fb60cfcf Update README.md
links in code look weird
2013-05-20 14:54:46 -06:00
Sara Golemon 5e655de3d0 Remove FB specific makefile fragment from OSS repo
To rebuild generated files, see: hphp/tools/generated_files.sh help
2013-05-20 13:52:33 -07:00
Paul Tarjan 61734c80c9 clean out test_ext_magick.cpp
It looks like contbuild fails on warnings now. This file does nothing but issues a warning. If someone actually wants to test image magick, then please feel free to rever this and find a better solution, like breaking the method up.
2013-05-20 13:52:33 -07:00
Mark Williams 117823acf1 Pass name of called class to intercept handler for static methods
Otherwise there is no way to tell which class was actually called.
More context here: https://www.facebook.com/groups/243324789049477/permalink/470958322952788/
2013-05-20 13:52:33 -07:00
Sean Cannella c0cc5ef954 update idl_list.php for namespaces + lint errors
- fixes lint errors regarding generated files and generates same headers
2013-05-20 13:52:33 -07:00
Owen Yamauchi f537fa7cc1 JSON parser: fix empty dictionaries inside of dictionaries
I broke this with my change to stop boxing everything. It was dropping
empty dictionaries inside dictionaries, because the "}" of empty
dictionaries is a different parser action from the "}" of nonempty
dictionaries, and I'd neglected to update it. (The fact that no tests
caught this before is a little unsettling.)
2013-05-20 13:52:33 -07:00
Drew Paroski 9b8b31b62a Fix bug with $_SERVER['PHP_SELF']
Currently we have bug where $_SERVER['PHP_SELF'] is "" a script is invoked
at the command line without using "-f" or "--file".

This diff fixes the problem by making more places use the adjusted version
of argc/argv built using prepare_args(). This also allows us to get rid of
a old hack we've had for a long time for supporting running scripts without
using "-f" or "--file" at the command line.

Github issue 730: https://github.com/facebook/hiphop-php/issues/730
2013-05-20 13:52:33 -07:00
Drew Paroski 4d923bf679 Fix foreach with superglobals
HHVM was segfaulting on "foreach ($x as $_FILES) {}" during bytecode
emission. This diff fixes the issue.

Github issue 734: https://github.com/facebook/hiphop-php/issues/734
2013-05-20 13:52:33 -07:00
bsimmers 7f335950f9 Move more IR classes into their own headers 2013-05-20 13:52:32 -07:00
Jeff Welch 781cea6aa1 Fix extra element bug with $_SERVER['argc'] and $_SERVER['argv']
When a file is executed on the command line without the --file argument,
$_SERVER['argv'] contains an extraneous empty string at the beginning of
the array. (Note this bug does not occur when the --file argument is used.)

Github pull request 767: https://github.com/facebook/hiphop-php/pull/767
2013-05-20 13:52:32 -07:00
Drew Paroski 89765cd4f2 Make arrays implement Traversable and KeyedTraversable
This diff changes HHVM so that arrays are considered to implement the
Traversable and KeyedTraversable interfaces (which have no methods).

The idea is that these interfaces will be useful for parameter type
constraints for PHP code that wants to be compatible with both arrays and
collections (and possibly other objects that implement these interfaces).
2013-05-20 13:52:32 -07:00
Paul Tarjan 393d445193 disable tests not passing on ubuntu
I got the list from https://travis-ci.org/ptarjan/hiphop-php/builds/7268132
2013-05-20 13:52:32 -07:00
Paul Tarjan c487678d3d stop testing for locale installation
Ubuntu doesn't come with german@euro. I don't think looking for that locale was the goal of this test.
2013-05-20 13:52:32 -07:00
Paul Tarjan 26267b4a0a fix nemo for namespaces
This code was using the old assumption that namespaced functions always started with a ##\##. Instead, lets do the same thing we do in the emitter.

Closes #771
2013-05-20 13:52:32 -07:00
Jordan DeLong f4942ec853 Simplify jumpopts and the tracelet-crossing instructions
- Add ReqBindJmp, and ReqBindJmpCond instructions which emit service
    requests.

  - GuardLoc/GuardStk always imply cross-trace control flow

  - New CheckLoc/CheckStk instructions imply inside-of-trace
    control flow.
     - Renamed GuardType to CheckType to match this convention (we were
       loosly following it in the api to irtranslator, so I spread it
       through everything)

  - Check{Loc,Stk} can be optimized into SideExitGuard{Stk,Loc}

  - Reimplement jumpopts using this:
     - Check{Loc,Stk} branching to a "normal exit" can turn into
       a SyncABIRegs; SideExitGuard{Loc,Stk}.
     - A conditional jump to a normal exit followed by another normal
       exit turns into SyncABIRegs; ReqBindJmpFoo.

  - Remove the ExitTraceFoo instructions.

  - Remove IRInstruction::{get,set}TCA.

  - Remove order dependence in the ir.h enum.  (bsimmers has some
    ideas about generic branch fusion that would reduce the
    duplication there wrt this new set of similar op names; we
    discussed it and for now it seemed ok to have a whole ReqBindJmp*
    family, though.)

  - Fix the creation of unused REQ_BIND_JMPs in astubs.  I think there
    was also unused dead jumps-to-fallbacks in astubs due to the (now
    unneeded) guard-hoisting optimizations, but I haven't verified.

  - Some random cleanup along the way (adding consts to members,
    comments, removed some weird functions in codegen, etc).
2013-05-20 13:52:32 -07:00
Jordan DeLong 509a0e11dd Add assertions that no SSATmps span calls, except constants and FramePtrs 2013-05-20 13:52:32 -07:00
Paul Tarjan d088d7aa20 use chinese as the test locale
ubunut 12.04 only ships with english and chinese, so I think we should work with those.
2013-05-20 13:52:32 -07:00
Paul Tarjan a37423e4f3 stop testing the underlying library
On ubuntu mathines, this still returns PM even in the netherland's locale for both zend and us. I think we shouldn't test it.
2013-05-20 13:52:31 -07:00
Paul Tarjan 97e81277da fix ordering for test
In the open source build, this test has an inconsistent ordering. I think the underlying library doesn't maintain order of entities. Zend also has an inconsistent ordering. Lets stop testing the order.
2013-05-20 13:52:31 -07:00
Paul Tarjan 0b062c3f3b disable flakey time test 2013-05-20 13:52:31 -07:00
Jordan DeLong a9da324254 Fix a bug in simplifyDecRefStack
My bad.  If you're going to gen something with no dest in
simplifier, you need to nop out the old one.  This was leading to
over-decrefs in some cases.
2013-05-20 13:52:31 -07:00
Drew Paroski 4013bcede8 Need short array syntax here too
This corresponds to github pull request 777:
https://github.com/facebook/hiphop-php/pull/777
2013-05-20 13:52:31 -07:00
Paul Tarjan d4f8c52e9f fix uninitialized spew 2013-05-20 13:52:31 -07:00
Paul Tarjan 3f65895955 only compute variable if it will be used 2013-05-20 13:52:31 -07:00
Paul Tarjan 2a9761d838 Fix "unused variable" warnings 2013-05-20 13:52:31 -07:00
Paul Tarjan c4d32bde0f fix uninitialized warning
The open source make spewed a warning about this. How does 0 sound?
2013-05-20 13:52:31 -07:00
Paul Tarjan 8f31d3356e Add support for REQUEST_TIME_FLOAT which returns secs.usec since epoch
Zend compat http://php.net/manual/en/reserved.variables.server.php

closes 778
2013-05-20 13:52:30 -07:00
Herman Venter 23d9095d4b Add comments and split function for better readability.
As part of reading through the code of the list command, I've added some more comments and did a small refactoring to improve readability.
2013-05-20 13:52:30 -07:00
Paul Tarjan 4da410ab58 Rename closures and generators
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.
2013-05-20 13:52:30 -07:00
Paul Tarjan f9f0d8a4f1 fix unused variable 2013-05-20 13:52:30 -07:00
Paul Tarjan 0ef4ed7b1f fix spew in open source build
These constants are defined in ##folly/Malloc.h## which is being pulled in before the jemalloc and spewing in open source builds.

Closes #673
2013-05-20 13:52:30 -07:00
Jordan DeLong 30667b7fe5 Basic support for inlining functions with parameters, inline some setters
Adds support for some functions with parameters.  Parameters
work by doing StLocs to the inlined frame, which can be eliminated if
the frame can be eliminated.  (Non-parameter locals will eventually
work similarly.)  This diff also moves all the state tracking to
updateTrackedState instead of beginInlining/endInlining functions on
TraceBuilder---the second TraceBuilder pass currently tracks state
incorrectly if the inlined frame wasn't eliminated.

This diff doesn't inline setters that have parameter type hints
because they could hold on to the frame.  Seems to be in the noise in
perflab, although contrived setter microbenchmarks definitely reflect
the change.
2013-05-20 13:52:30 -07:00
Mike Magruder fb093f8850 Add basic debugging information to crash reports
I'm adding the count of connected debuggers, and whether or not the process is hphpd, to the crash reports. In another diff I'll wire these up to hphpcrash_categorizer.py and get these as columns in the Hphpcrash Scuba data set so we can filter crash reports based on whether or not it's from hphpd, and whether or not a server was being debugged when it crashed.
2013-05-20 13:52:30 -07:00
Herman Venter f9197ff35c Use & rather than * for pointers that should never be null
This is a rather mechanical refactor that uses references (&) rather than pointers (*) for parameters that are not permitted to ever be given null arguments. In effect, the onus for checking null pointers is shifted from the callee to the caller. The & type annotation makes it clear that the callee is not prepared to deal with a null pointer.
2013-05-20 13:52:30 -07:00
Guilherme Ottoni c5e36d31af Predict that constructors return KindOfNull
If we can't infer it, then predict it.
2013-05-20 13:52:30 -07:00
Chip Turner a5f568f9d7 Add a nice error message when json failes to parse and fix Makefile rule
I had a json that wouldn't parse (trailing comma) but it was an
odd php error about iterating over a null.  So this should give a
slightly better error.

Also, .inc files are no longer used.  Remove the Makefile references.
2013-05-20 13:52:29 -07:00
Jordan DeLong dc69f1030e Flag ext-json test as bad 2013-05-20 13:52:29 -07:00
Sean Cannella c6dc5f366f ArrayIdx bytecode and IR instruction
- Implemented ArrayIdx bytecode and IR instruction for common pattern
2013-05-20 13:52:29 -07:00
Mark Williams 59f2c1749f Fewer varEnvs in generators
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
2013-05-20 13:52:29 -07:00
mwilliams ca4d38d5ff Fix fb_intercept for functions with extra arguments
If you pass extra arguments to a function, and it doesn't
use any of the func_get_args type functions, by default we drop
them.

Now that fb_intercept runs after the prolog, rather than before
this means it doesnt see them. Disable the extra args optimization
when JitEnableRenameFunction is in effect.
2013-05-20 13:52:29 -07:00
Guilherme Ottoni b5d291c373 Use scratch registers that don't need REX prefix when available
Instead of using register r10 (which needs a REX prefix) as scratch
everywhere, select a cheaper scratch register for each instruction
that doesn't require a REX prefix if available.
2013-05-20 13:52:29 -07:00
Guilherme Ottoni d7708fde5b Allocate XMM registers for doubles
This diff adds support for allocating SSATmp's of type Dbl directly to
XMM registers. The register allocator now keeps per-reg-type lists of
caller/callee saved registers.  xmm0 and xmm1 are reserved for scratch
as rXMMScratch[01].

Added a runtime option HHIRAllocXMMRegs to enable/disable XMM
allocation -- if disabled, it forces all SSATmps to be allocated to GP
regs, as before.

While here, changed the conversion of int/bool consts to double from
runtime conversions to JIT-time.
2013-05-20 13:52:29 -07:00
Mark Williams 5c491af2de Don't reinitialize native funcs
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).
2013-05-20 13:52:29 -07:00
Paul Tarjan 2ece03bbac make get_cfg_var return false
The spec says this returns false on error.
2013-05-20 13:52:28 -07:00
Guilherme Ottoni cef8173383 Document .hphp_opts test files
That's all.
2013-05-20 13:52:28 -07:00
Mark Williams 53433c3359 Fix classof for traits
Class::classof(Class* t) would always return false, if t
was a trait, but should return true if t == this.

This was causing the call_user_func in the new test to fail,
reporting that T was not a subclass of T.
2013-05-20 13:52:28 -07:00
Mike Magruder a605a5c699 Add ring logging for interesting debugging events
This adds a new trace macro to allow tracing to the ring buffer in release builds. It also performs normal tracing, too, like TRACE(n, ...). Converted a number of trace/log messages in the debugger to the new macro so we have this data when we get a core file. I've converted things that we've found useful lately, but this will be adjusted over time quite a lot as we discover new things that help us find problems more quickly, or find messages that turn our to be useless or spammy.
2013-05-20 13:52:28 -07:00
Jordan DeLong cd1888f738 Mark a couple zend tests as bad 2013-05-20 13:52:28 -07:00
Sean Cannella 0a65744bf5 rename IgnoreRedefinition to AllowOverride
IgnoreRedefinition does not do what it says it does (as the userland definition is selected) so renaming it
2013-05-20 13:52:28 -07:00
Paul Tarjan 6e391b3c51 add Facebook test suite
We've been sprinkling FB-specific stuff into other tests. I think having a dedicated suite will make it obvious where to put things. I looked at all the failing tests when running the open source build and moved them here. I also had to rejigger the flib include, since that didn't work in repo mode.
2013-05-20 13:52:28 -07:00
Paul Tarjan a7c6ad1817 add namespace reflection methods
added in 5.3

I couldn't actually get the ##sysdoc.php## to work (it just deleted all the docblocks), so I just copied the format.
2013-05-20 13:52:28 -07:00
Paul Tarjan 6f1ffc569d add php_ini_loaded_file
Since we don't support ini files, returning FALSE seems within the bounds of this function.
2013-05-20 13:52:27 -07:00
Paul Tarjan b86cce6282 document VMStackElms
This whole doc needs some love but at least it is documented.

closes #729
2013-05-20 13:52:27 -07:00
Matt Glazar d6d9955136 Allow shebang/hashbang (#!) as first line in Hack files
A shebang allow a script to be run as an executable on UNIX
systems. PHP allows shebangs, but Hack does not. This
changeset allows Hack to have shebangs like in PHP.
2013-05-20 13:52:27 -07:00
Owen Yamauchi daae3730e1 Split Xor into BitXor and LogicXor; clean up binary arithmetic
This started out as splitting Xor into two separate opcodes with more
precise type descriptions, and turned into a more sweeping change that
removes the conditional "use bool ops" logic in binary arithmetic, by
simply emitting ConvBoolToInt for bool inputs.

This will actually emit more code than before in the case of binary
operators with two bool operands. As I write this I'm crossing my
fingers and hoping that this will turn out not to matter in practice.

Also deleted some redundant if cases in codegen.
2013-05-20 13:52:26 -07:00
Paul Tarjan d8b36de433 allow namespaced classes in type args
This is a bug that running Symphony found. This part of the AST is weird as it doesn't introduce any more nodes, but I think I got it right...
2013-05-20 13:52:26 -07:00
Paul Tarjan eed19d46ac I found some more namespace tests
These all now pass with my namespace diffs
2013-05-20 13:52:26 -07:00
Mike Magruder 075926978e Segfault when calling hphpd_break() with no debugger attached
A call to hphpd_break() with no debugger attached, from a command-line run (no request), with debugging enabled (not normally true, but can be true if you use something besides cli.hdf), will segfault every time. Simple fix for a high hit-count crash.
2013-05-20 13:52:26 -07:00
Paul Tarjan 99fcd4295e canonicalize \print_r to print_r at runtime
builds on D795509.

This copies all the callsites where we autoload.
2013-05-20 13:52:26 -07:00
bsimmers 76a872c882 Fix static_assert in packed_tv build
I didn't check m_type's offset in a packed_tv build when I
first wrote this.
2013-05-20 13:52:25 -07:00
Paul Tarjan 09c139c4f7 disable flakey test
I saw this test fail on an unrelated diff
2013-05-20 13:52:25 -07:00
Jordan DeLong 5cf59f2fc1 Move another flaky zend test 2013-05-20 13:52:25 -07:00
Jordan DeLong 2f14ad8d54 Remove AllocSpill/FreeSpill
Doesn't work, so we shouldn't maintain it.  We can add a
feature like this later if we need it (although it might be easier and
just as good to just increase the preallocated spill number if
needed).
2013-05-20 13:52:25 -07:00
Andrei Alexandrescu 2baabea1ae new considered harmful
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.
2013-05-20 13:52:25 -07:00
aravind 7fbef94637 Optimize SharedVariant refcounting
Elide refcounting for non-refcounted TVs in SharedVariant.
Additionally for apc_store, if TV is a static string, use
the static version insted of the given one.
2013-05-20 13:52:25 -07:00
aravind 64889059a2 Use eager vmreganchor
This diff introduces a new "eager" vmreganchor, which we call
from some of the heaviest users of vmreganchor. For an eager
reganchor, we save the rbp, pcOff and spOff at the call site
in the MInstrState, and the reganchor itself reads it off
from the MInstrState (instead of following the rbp chain
and looking up the hash table). Currently, the set of functions
which use eager vmreganchor is based on profiling.
2013-05-20 13:52:25 -07:00
Herman Venter 5b8209aa87 DebuggerCommand::onClient and DebuggerCommand::help do not return anything meaningful.
These commands invariably return true. This is more than a tad confusing to a new reader of the code. Refactor them to return void. Remove a few pieces of dead code that would log something if they ever returned false.
2013-05-20 13:52:25 -07:00
Bert Maher 66f135b6df Add verbose option to test/run
If -v is specified print how to run the test manually even if
it doesn't fail.  Helpful for remembering how to do a
RepoAuthoritative build.
2013-05-20 13:52:24 -07:00
Paul Tarjan c0694a2ae9 name in unset error
zend does this, we should too
2013-05-20 13:52:24 -07:00
Paul Tarjan 2494ce49b5 Don't allow use Foo where Foo is already a class
Classes need to take up space in the alias map (according to zend).

Suprisingly, functions and constants don't. When importing a duplicate, zend doesn't do anything and just continues, and we currently overwrite the symbol. Should I match zend on this, or is the fact that we both continue working good enough?
2013-05-20 13:52:24 -07:00
Guilherme Ottoni 42734902fa Clean-up GenericRetDecRefs
This diff cleans some register shuffling that GenericRetDecRefs was
doing because it calls helpers that use a special ABI, in which r13 (a
callee-saved register) is not saved.

The new approach simply checks if r13 is live, and if so, pushes and
pops it around the call. This removes the need for GenericRetDecRefs
to take the function return value as a source.
2013-05-20 13:52:24 -07:00
Herman Venter 84f8764931 Clarify contract for DebuggerClient::process and remove confusing returns from helpers.
Functions that always return true may as well return nothing. That is way less confusing.
2013-05-20 13:52:24 -07:00
Drew Paroski 16a372962c Tolerate "isset($c->prop)" for collections
Currently collections define magic __get, __set, __isset, and __unset
methods which will throw exceptions if any property access is attempted
on collections (such as "isset($vec->prop)" and "$x = $vec->prop").

However, there is existing code that uses isset() to check if various
objects have a property with a certain name, and it feels like throwing
an exception here is a little harsh. This diff updates collections to
be tolerant of reading properties.
2013-05-20 13:52:24 -07:00
Jordan DeLong 5685d18e05 Fix another flakey zend test 2013-05-20 13:52:24 -07:00
Mark Williams 88ec1476e2 Fix user defined sorting
copy paste error crept in a few weeks ago, breaking the
case of a user-defined function that returns boolean.
2013-05-20 13:52:24 -07:00
Keith Adams 77d26f2bf4 Limit huge pages to the hot portion of the TC.
Huge pages are a limited system resource. When we ask for
huge chunks of system ram as huge pages, the kernel may actually do
physical memcpy's to satisfy our desires, burning CPU.

Only use huge pages on the portion of the TC that Bert's data shows to
be hot.
2013-05-20 13:52:24 -07:00
Andrei Alexandrescu 6f3b584bee Famous last bug in PolicyArray
PolicyArray pased all tests but failed in production. After browsing on my own box I figured that what happened was the method addLval() with a string key is called in production on many pages, but never in the tests. @ptarjan maybe you could look into adding such a test?

This diff still does not instantiate the policy-based array (I did instantiate it during testing).
2013-05-20 13:52:23 -07:00
Mike Magruder 64da297ced Adjust some debugger logging around the communications channel, and ensure we check all error conditions before attempting to read data from the socket
The error handling around the communication channel between client and server is a bit sketchy right now. We have some cases that are reasonable when the client is quitting and the socket is closing, and some cases where it would be surprising for this to happen. This leads to spurious messages printed out when quitting the client normally. For now, switch some of these to trace messages instead of log messages. Task 2398988 tracks cleaning this up properly.
2013-05-20 13:52:23 -07:00
Paul Tarjan b23fab2d9b Update README.md
Link to our pretty travis image
2013-05-20 14:53:50 -06:00
Paul Tarjan c30fe678f0 Merge pull request #763 from ptarjan/travis
add travis CI
2013-05-20 13:12:28 -07:00
Mark Williams 1489c698dc Use AtomicHashMap for NamedEntities and StaticStrings
Its faster as long as you have a good starting point.
Add RuntimeOptions to specify initial sizes.
2013-05-20 12:04:09 -07:00
Sara Golemon 1efb5915a0 Update folly 2013-05-20 12:04:08 -07:00
Paul Tarjan d2efdd49c0 add travis CI
To do this, I had to encode the wiki instructions in a file, which
seemed like a good thing anyways.
2013-05-18 20:23:28 -07:00
Paul Tarjan e7d8f2e54d Merge pull request #783 from rlerdorf/patch-3
Fix Bison paths
2013-05-17 22:45:17 -07:00
Rasmus Lerdorf be93cbfa08 Fix Bison paths
Some internal FB bison version thing?
2013-05-17 23:37:36 -03:00
Paul Tarjan fce1d9d636 Merge pull request #764 from ptarjan/test_whitespace
fix test whitespace
2013-05-17 13:00:03 -07:00
Paul Tarjan 3b1ca9f22d Merge pull request #770 from ptarjan/fix_cmake_patch
Fix cmake patch
2013-05-17 12:58:50 -07:00
Paul Tarjan 5c337c07aa Merge pull request #772 from ptarjan/spew
fix spew
2013-05-17 12:55:00 -07:00
Drew Paroski 92dc2dfbe1 Merge pull request #777 from rlerdorf/patch-3
Need short array syntax here too
2013-05-17 12:08:38 -07:00
Rasmus Lerdorf 4530d5d25e Need short array syntax here too 2013-05-16 15:04:16 -03:00
Paul Tarjan 92a0f8692c fix spew in folly (this is already upstream in folly) 2013-05-15 22:41:47 -07:00
Paul Tarjan 7ef447d119 change AM_CONFIG_HEADER to AC_CONFIG_HEADERS
This is needed for OSX and I think fixes a spew on others
2013-05-15 19:51:01 -07:00
Paul Tarjan 055cda0dd5 Update README.md
No printing involved, just electronic bits
2013-05-15 17:28:36 -06:00
Paul Tarjan 3019644e91 Update README.md
Relative links
2013-05-15 15:11:53 -06:00
Paul Tarjan 7e16ec7d1c Update README.md
Deeper link
2013-05-15 15:07:53 -06:00
Paul Tarjan faf9ab909f Update README.md
Examples for how to run hhvm
2013-05-15 14:33:11 -06:00
Herman Venter f7da2cfa18 Refactor DebuggerCommand.
Rename onClient to onClientImpl and move to protected space. Rename onClientD to onClient. Add comments.
2013-05-15 13:05:10 -07:00
Paul Tarjan cbd2e367c5 Move slow namespace tests back
I totally forgot about these. Lets see if they pass.
2013-05-15 13:05:10 -07:00
Mike Magruder 3522d9440f Remove races from the WebRequest debugger unit test
Got rid of our reliance on sleeps to ensure correct timing in the WebRequest debugger unit test. A change with a recent diff removed some of the races by waiting for the client to enter the busy state before sending an interrupt to mimic ctrl-c. Generalized that a bit, and extended it to ensure the initial handshake between the harness, debugger request, and the request to be debugged is correct. I've removed the 10s sleep on startup, and the 3s sleep after each notification from the various requests back to the harness. Also added a bunch of comments to hopefully explain the test better, and renamed some files/functions to better reflect what they're doing. This seems to work well on my box… I've run it a bunch in both dbg and opt builds to try to get it to fail but haven't yet. Fingers crossed ;)
2013-05-15 13:05:10 -07:00
Mike Magruder 1d68aeb876 Segfault when evaling for the debugger
Fix a sigfault when we eval a snippet of PHP for the debugger. If there is no activation record (between the end of a request and PSP, before first function execution of the request, etc.) we'd segfault setting up the invocation. Fixed to tolerate that case.
2013-05-15 13:05:10 -07:00
Paul Tarjan 9309f4c9c7 don't use aliases for functions or constants
@andrewparoski had the excellent observation that functions and constants don't get imported with use statements.
2013-05-15 13:05:10 -07:00
Edwin Smith ada1c7b2f9 Eliminate most Variant litstr methods
Doesn't eliminate the Variant(litstr) constructor, or the
same/equals/more/less/etc helpers called from comparisons.h;
those will come in a followon diff.
2013-05-15 13:05:10 -07:00
Mark Williams 86d9acaf6e Undo some #include renames
sys/*.h should use angle brackets.
Also, fix most of the lint errors for the affected files
2013-05-15 13:05:10 -07:00
Drew Paroski 2ad3ec4a14 Fix the build 2013-05-15 13:05:10 -07:00
Paul Tarjan 61c545c838 fix constant()
we don't store constants with the preceeding ##\## so slice it off. I originally edited ##name## but couldn't find a clean c++-ish way to do that. I'm open to teachings.
2013-05-15 13:05:09 -07:00
mwilliams 27601d53fd Revert "Allow shebang/hashbang (#!) as first line of Hack files"
This reverts commit d1f3c9e03d4eed7a3262bcdb461b77bbd661e5d6.

Its breaking tests
2013-05-15 13:05:09 -07:00
Bert Maher ed5d3150e3 Revert "Try inlining the LdGblAddr(Def) helpers" (commit bc1e471).
This used to look perf-neutral with a slight instruction
win... after I actually landed it, it looks like a big, consistent
negative for perf.
2013-05-15 13:05:08 -07:00
Matt Glazar eb6eb3f495 Allow shebang/hashbang (#!) as first line of Hack files
A shebang allow a script to be run as an executable on UNIX
systems.  PHP allows shebangs, but Hack does not.  This
changeset allows Hack to have shebangs like in PHP.
2013-05-15 13:05:08 -07:00
Dario Russi 0a50439fd6 InstanceOf optimization and Class::classof clean up
Changed the Set of all interfaces imlemented by a Class with an IndexedMap. Also changed the classof (and thus instanceof) to lookup in that map by name to see if an interface is imlemented by a class. That replaces the
previous mechanism that would walk the class hierarchy dereferencing PreClass in order to see if the interface was in the class inheritance. The new model seems to lead to better performance in terms of CPU instructions, lodas
and stores. The latest perflab also showed improved CPU time though that may be just lucky noise.
We have also removed the Class::classof (PreClass*) method which leads to a slightly cleaner code.
2013-05-15 13:05:07 -07:00
Mike Magruder 18f7172965 Fix breaking on request start/end/psp
Breaking at the start of the request, end of the request, or end of PSP has been broken for a while. Giving these events a site with the proper URL in them ensures that the rest of the original logic to match and stop on these breakpoints works again. Also updated the help for the breakpoint cmd using the old text from the reference, which seemed reasonable.
2013-05-15 13:05:07 -07:00
bsimmers 69dc698997 Move parts of ir.h to trace.h and cfg.h
trace.h contains the definition of the Trace class, and cfg.h
contains functions for iterating over Blocks and Traces or inspecting
their CFGs.
2013-05-15 13:05:07 -07:00
Mike Magruder 8d1ade6b3b Remove dead subclass of ThriftBuffer
PhpThriftBuffer is dead code. Removing it to make it clear that the debugger is in fact the only consumer of ThriftBuffer.
2013-05-15 13:05:06 -07:00
Owen Yamauchi 745773fd74 Hack-fix logical op types
This badly needs a proper rewrite, but this is intended to be a
low-risk, mergeable change.

These ops' destination type is always marked as Int (wrong), which meant
that the "zero extend if bool" logic was never invoked. Logical ops
always output Bool. Once we fix this, we'll save some instructions
downstream, because right now the Xor (etc.) spend an instruction
zero-extending their result, only for the next instruction to be
(usually) ConvIntToBool.

Also discovered some mildly unsettling "&" vs. "&&" issues.
2013-05-15 13:05:06 -07:00
Jordan DeLong dfbf27d243 Fix a bug with null constants
We end up with uninit nulls in the repo for unit constants.
In RepoAuthoritative mode, we will use m_type == KindOfUninit during
constant lookup to decide whether to cast TypedValue::m_data.pref to a
ConstantInfo*, and then call a function pointer that it contains.  (We
should probably also clean that up to not cast RefData*'s to
ConstantInfo*'s, but I left that out of this diff.)
2013-05-15 13:05:06 -07:00
Sara Golemon 6ec64e8bf9 make #includes consistent
I was learning from @jdelong and he said that you should use
double quotes for local includes and angle brackets for library
includes. I asked why our code was the way it was, and he said he wanted
to clean it up. I beat him to it :)

Conflicts:

	hphp/runtime/base/server/admin_request_handler.cpp
	hphp/runtime/vm/named_entity.h
2013-05-15 13:05:06 -07:00
Paul Tarjan fef62f03a2 kill VM namespace
Now that HHVM is the default runtime, this namespace doesn't mean anything.
2013-05-15 13:05:05 -07:00
Paul Tarjan b24ca4a2b1 flakey test 2013-05-15 13:05:05 -07:00
Mark Williams aacaa37ad5 Opimize re-entry path
Use the jitted prologs, and add a "few args" re-entry
point to avoid the overhead of creating an Array
2013-05-15 13:05:05 -07:00
bsimmers 72d0e84e1b Optimize string offset setting
I was looking at this code while working on a vector
translator diff and noticed that we're doing some unnecessary
refcounting.
2013-05-15 13:05:05 -07:00
bsimmers e518e102e6 Predict that the result of SetM is the same as its input
If we can't prove at compile time that a set operation won't
fail, we don't know the exact type of SetM's stack output. Since these
failures should be extremely rare, we now predict that the set
operation won't fail and side exit if it did. This converts a bunch of
DecRefs to DecRefNZ, and when we get rid of all the SpillStacks for
the helper calls this will allow us to optimize away those
IncRef/DecRefNZ pairs (while pushing the IncRef to the exit trace).
2013-05-15 13:05:05 -07:00
Herman Venter 6afb27bf50 Clean up handling of debugger quit command
Set the stopped flag for the debugger proxy when it receives a quit command, so that the proxy exits a bit quicker and cleaner. Add a timeout to the cleanup quite of test_debugger, so that it does not hang when a test goes wrong. Add some more tracing.
2013-05-15 13:05:05 -07:00
Jordan DeLong 19562faabc Translator analyze assumed strlen($x) is always an int
This was leading to people getting (int)&some_null_variant as
the result of strlen.  I think this came about when we implemented the
5.4 strlen semantics (we stopped returning 5 for strlen(array()),
etc.)
2013-05-15 13:05:04 -07:00
Paul Tarjan 8538894fd4 call autoloader with correct case
on github, closes #738
2013-05-15 13:05:04 -07:00
Drew Paroski a8d84e2f21 Refactor HipHopSyntax and HackMode to play nice 2013-05-15 13:05:04 -07:00
Bert Maher 239c9af6cd Try inlining the LdGblAddr(Def) helpers
LdGblAddr and LdGblAddrDef call helpers that are really thin
wrappers.  Seems like it might be a good idea to just emit code
directly into the TC to avoid the extra call.
2013-05-15 13:05:04 -07:00
Jordan DeLong 66b22c9c52 Don't malloc from a signal handler
This can self-deadlock the process.  Instead, pass the reason
to the server so it can log it after the signal handler exits.
2013-05-15 13:05:04 -07:00
Paul Tarjan 0d2f72307b don't use the whole namespace when we only want one thing 2013-05-15 13:05:04 -07:00
Paul Tarjan 35e75ffd97 getting ready to kill VM::
These will need to stay qualified.
2013-05-15 13:05:04 -07:00
Herman Venter f411d5dde9 Use the same repo for config-debugger-server.hdf as is used by cli.hdf.
When the debugger tests run, the repo location defaults to ~. This leads to failures when the network is slow.
2013-05-15 13:05:04 -07:00
Alok Menghrajani db9577b140 Rename strict with Hack
Strict mode was the old name. Let's avoid any confusion in the future and rename things.
2013-05-15 13:05:03 -07:00
bsimmers 997484ffcd Disable test/zend/good/ext-standard-strings/setlocale_basic2.php
It's failing/flaky.
2013-05-15 13:05:03 -07:00
Paul Tarjan 1e0f032ba7 absorb comments on namespaces
This test didn't really intentionally test this, but it caught us not eating comments on namespaces.

I don't understand the difference between ##ParserBase## and ##Parser##. Maybe this belongs here? It needed to be here to have access to ##pushComment##.
2013-05-15 13:05:03 -07:00
Paul Tarjan 06cb6611dc handle closing tag in ?>
I wanted to get closer to zend's implementation but they seem to do scanning and parsing at the same time. We don't have the state of the parser when the scanner sees the ##?>## token. I think this is the next best thing if we don't want the refactor of D808985
2013-05-15 13:05:03 -07:00
Jordan DeLong 230d2ae5e6 Reduce number of threads during initial hhvm startup
Before we've jitted the first bit of the TC, having so many
threads leads to a pathological situation: we accept a bunch of
requests (135) and have all of them running in the interpeter,
starving the JIT thread that is trying to make them all go faster.
(Perf record of a machine in this situation shows the vast majority of
the time in dispatchImpl, SrcDB::find, and enterTC).  This diff tries
to solve this by limiting the number of threads to the number of cores
for the first N requests.
2013-05-15 13:05:03 -07:00
Jordan DeLong 8bf9e83eaf Delay registration of SIGCHLD handler until after lwp fork
I think the cause of our issues with random failed-to-exec
errors is this SIGCHLD handler.  When the parent process asks a light
process to do a waitpid operation, we now can get EINTR for two
reasons.  It used to use signals only for implementing timeouts with
SIGALRM, but now it appears possible due to the SIGCHLD.  This could
lead us to report the waitpid as failing---which it looks can have
ExecFuture thinking running==false and reading the exit code as -1.

Also, now that we have a SIGCHLD handler (are we sure we want to keep
this?), using waitpid() without an EINTR loop is probably similarly
broken in the parent process.  (Also, isn't it basically incorrect to
use wait functions without an EINTR loop in general, though?)  I
didn't add an EINTR loop in do_waitpid in this diff because it's using
signals for timeout (it really should be checking a volatile
sigatomic_t that gets set by the handler, though)

Also, this means using Process::Exec is suspect in general.  All uses
looked like debugger or tests only (and when hphpc runs hhvm in a
subprocess), so I didn't nuke them (yet).  I deleted some random
network.h dead code that uses it, though.
2013-05-15 13:05:03 -07:00
Jordan DeLong df1308cb9d Add hack to register checker for rbp
Rbp is allocated just as weirdly as rbx.  I was able to hit
this assert on a inlined function that didn't eliminate the ActRec
(there are ReDefSP's that consume rbp).
2013-05-15 13:05:03 -07:00
Paul Tarjan 126594a759 Be less explicit about namespace
I'm getting ready to kill the VM namespace. I'll be doing small cleanups first.
2013-05-15 13:05:03 -07:00
Paul Tarjan 52c9b25ae8 kill dead code
When trying to figure out what this was I figured out it wasn't anything.
2013-05-15 13:05:03 -07:00
Jordan DeLong 6546c3edf6 Don't hoist LdLocs to the top of tracelets.
We have separate GuardLoc instructions now.  This was
originally intended to be an optimization (and LdLoc was
simultaneously acting as the guard back then), but now that
Rematerialization is off (and since we don't do a DCE after register
allocation anyway) I am doubtful.
2013-05-15 13:05:02 -07:00
Jordan DeLong f6a2dd1b4f Move ir inlining tests to slow/ir_inlining, add case for bug @mwilliams found
Mark hit a bug that aravind already fixed where we didn't set
stackDeficit to zero after ending an inlined call.  Adds the repro
case and moves all the tests to slow.
2013-05-15 13:05:02 -07:00
Edwin Smith b4c6a50f78 Add a register-allocator-validator.
This adds a checkRegisters() function so we can assert if the register
allocator botched something.  Our IR already must pass SSA rules after
register allocation, so its enough to scan the code in dominator
preorder, keeping track of what SSATmp is in each register and spill-slot.
Then at the point of each use, we can assert that the register/slot assigned
to the input tmp actually contains that input tmp.

While I was at it, I moved checkCfg() and checkRegisters() to the new
check.cpp file, and factored out findDomChildren().

Also, this checker failed on a tracelet that used exactly 16 slots due
to the +1 fudge factor added by LinearScan::preAllocSpillLoc.  I fixed
this by changing the meaning of spill slots; now they are logical
slot numbers, and we have a dedicated spillSlotOffset() function
to compute the offset from RSP.  This can be updated in the future
to handle more than just the preallocated spill slots.
2013-05-15 13:05:02 -07:00
Paul Tarjan d7ce66ff73 loosen catchable error message
zend emits a special error for typehint violations. We aren't going to be string compatabile with this as they emit 2 line numbers and files. Lets just make sure we fatal at the same point in the test.
2013-05-15 13:05:02 -07:00
Edwin Smith 17a323c050 Rename IRInstruction's iid property to id.
I called it iid because id was taken by the linear-scan specific
'id' field, which really was a linear number and could change.
Now that we have LifetimeInfo.linear[inst], we can use the name
id consistently between SSATmp, IRInstruction, and Block.

This in turn allows StateVector to be one iota simpler.  Renamed
count to numIds while I was at it.
2013-05-15 13:05:02 -07:00
Paul Tarjan 2f023e66db allow \ in function types
I looked at all the other uses of ##ident## and I think they are correct to not allow namespaces but we'll see.
2013-05-15 13:05:02 -07:00
Paul Tarjan efbb53323e clear aliases between namespaces 2013-05-15 13:05:02 -07:00
Guilherme Ottoni 3980fb9ff6 Add missing check for InterpOne following a CG_PUNT
I forgot this check in my original diff: we need to make sure that
bytecode instruction that cause the CG_PUNT has support for InterpOne.
Just a couple of instructions don't have InterpOne support, so this
was not causing any problems.  But the check should be there anyway,
for when we start porting to other ISAs.
2013-05-15 13:05:02 -07:00
Paul Tarjan 96e793360b function and constant fallback for namespaces
It turned out a lot of the namespace stuff still worked. The biggest thing for the first pass is that we don't fallback to the global function or constant if there isn't a namespaced one.

Also, when a constant has a ##\## anywhere in it it throw an error when it isn't defined, instead of assuming the string.
2013-05-15 13:05:01 -07:00
Guilherme Ottoni 8c7ba8c05c interpOne instructions that fail at code-gen
This avoids running to whole tracelet with a backup, slower engine
(interpreter or Tx64).

This will also help with the ARM port: we can initially CG_PUNT on all
IR instructions, and add support for them incrementally (without
sending the whole tracelet to the interpreter).
2013-05-15 13:05:01 -07:00
aalexandre 9559dcf879 PolicyArray initial review
PolicyArray splits the ArrayData implementation in two parts. ArrayShell implements the baroque ArrayData implementation in terms of a much smaller statically-bound core that concerns itself exclusively with the storage strategy for the array. This way the two aspects can be worked on separately, and different stores can be easily plugged into the given ArrayShell.

To give a better perspective, the featured SimpleArrayStore has about 340 lines all told (including solid documentation), whereas ArrayShell has some 1100 lines. The shell can be reused with other stores of unbounded sophistication. The store needs to implement only 22 primitives, some of which are trivial. Basically a new store implementation saves 1100 of difficult-to-get-right lines of code right off the bat, and only needs to focus on implementing 22 well-defined primitives.

Things to watch for when reviewing:

- Is the store API small/expressive enough? What should be added/removed?

- Are various forms of duplication present? If so, how could code be factored better?

- Any subtle change in semantics from HphpArray and friends that should be minded?

Known issues:

* Currently ArrayShell is defined as:

  class ArrayShell : public ArrayData, private SimpleArrayStore { ... };

when in fact it should be:

  template <class StorePolicy>
  class ArrayShell : public ArrayData, private StorePolicy { ... };

Extenuating circumstances related to allocator design prevent use of templates at this point. I'll work on these in parallel with the review.

* growNoResize is almost always prefaced by a test-and-grow. This sequence should be encoded in a function.

* The growth policy is spread all over the place in a subtle form of duplication.

* The current store design makes almost no effort to be particularly efficient.
2013-05-15 13:05:01 -07:00
Paul Tarjan 994ce35b82 cleanup lookupFunc
This func took 2 params and ignored the second one. While I was there I made the functions call eachother. Hopefully inlining is smart enough to let me clean this code.

I got a bit carried away, but I think this is better.
2013-05-15 13:05:01 -07:00
Paul Tarjan 27671d63b9 Update README.md 2013-05-15 13:56:30 -06:00
Paul Tarjan 234e1a5973 fix test whitespace
somehow this whitespace got eaten by the opensourcing
2013-05-13 00:52:37 -07:00
Sara Golemon 239bad931c Localize MySQL.Localize option to Facebook build only
This extension to the mysql php-api relies
on internal libmysqlclient functions which are deprecated
from normal MySQL builds.  Just turn it off and use fallback
behavior instead.
2013-05-10 10:54:42 -07:00
Mike Magruder 4e407b85ad Fix bug with preventing returns to TC for debugger
In order to ensure that we can continue to interpret code when setting up a step out, even if we're stepping out to jitted code, we set the saved RIP in each ActRec on the stack to the retFromInterpretedFrame() helper. However, this is wrong for generator functions. There is a different variant of the function for generators, so use that when appropriate. Also added a check to ensure we only changed return addresses to jitted code. Mark thought of a rare case where we could have a return address to a C++ helper in there, so leave those alone.
2013-05-10 10:54:42 -07:00
Mike Magruder 18528568fa Disable the debugger's Instrument command, and remove the code that checks for instrumentation from the interpreter
The debugger's Instrument command does not work with the JIT; any instrumentation requests will be ignored for jitted code. We believe that no one is using this at this time. I'm starting with a small diff to disable the command and remove the impact it has on the interpreter for now, just in case we're wrong. Once the command has been disabled for a few weeks I'll come back and remove all of the code (task 2376711).

InstHelpers was just pure dead code, so I nuked it.
2013-05-10 10:54:42 -07:00
Edwin Smith 9f338c96f9 Remove Variant::operator[](litstr)
And its remaining call sites.
2013-05-10 10:54:41 -07:00
Herman Venter b91dd81677 Improve readability of break point code in debugger.
Added comments to every method in cmd_breakpoint.cpp. Also renamed some methods to make their intent more obvious. Moved a few implementation methods from the public to protected space.
2013-05-10 10:54:41 -07:00
Paul Tarjan 930d45ceb3 fix flakey test
scanning the current directory sucks
2013-05-10 10:54:41 -07:00
Guilherme Ottoni 39416bcaa5 Use target cache for static properties of persistent classes
Accessibility of properties of persistent classes can be checked at JIT
time, so use the SProp-based fast path for these cases too.

Also, enhance HhbcTranslator to try to emit LdClsPropAddrCached,
instead of relying on the Simplifier to transform LdClsPropAddr into
LdClsPropAddrCached.  Doing this only in the Simplifier results in
unecessary ExceptionBarrier before LdClsPropAddrCached.  However,
there's still value in keeping the optimization in the Simplifier, so
that it can leverage opportunities exposed by other optimizations.  So
factor out the logic to check whether to use the SProp cache.
2013-05-10 10:54:40 -07:00
Bert Maher 083b028a3d Implement fast allocation path for objects in HHIR
Tx64 generates a fast path for allocating objects of a
persistent class that inlines a bunch of the helper work into the TC.
This diff is basically a translation of that path into HHIR codegen.
2013-05-10 10:54:40 -07:00
Herman Venter 3abc997a4e Rewrite parser for break point specification.
The specification string following a break command was parsed by means of ad-hoc string splitting and sub string finding. This scheme cannot deal with namespaces and class names that contain : (such as xhp classes). There is now a proper parser for break point specifications. Also, xhp class names are mangled before putting them in the BreakPointInfo structure, otherwise breakpoints qualified with xhp classes will not be hit. The syntax for namespaces has been changed to fit the language and if present namespaces are used to mangle function and class names, so that they match the names produced by the regular parser.
2013-05-10 10:54:40 -07:00
Ben Maurer e0f8f5bdff Use equals() in equals(StringData, StringData)
Equals is faster in a few ways.
(1) no call to memcmp unless string sizes are the same
(2) does a fast check for either of the strings being static
    before any calls to is_numeric_string
2013-05-10 10:54:39 -07:00
Owen Yamauchi c2e56ad8f3 Implement IsObject in IR
It turns out is_object actually shouldn't be calling isResource, so this
really wasn't as bad as everyone thought. I cleaned up the simplifier
logic for this instruction (even though is_object is weird, we can still
optimize it away when the src isn't even KindOfObject).

A more elegant solution might be to introduce Type::Resource, but that
would be more complex and I just want to get something working for the
purposes of lockdown.
2013-05-10 10:54:39 -07:00
Owen Yamauchi 09639ff073 Fix is_object on resources
PHP certainly never runs out of fun surprises to spring on me!
2013-05-10 10:54:39 -07:00
bsimmers 7bce06f37f Tune some VectorTranslator helpers
vGet*Impl were always returning TypedValues with m_type ==
KindOfRef so I just made them return RefData*. cGet*Impl were doing
some unecessary copying of TypedValues.
2013-05-10 10:54:38 -07:00
bsimmers 9b4e79aa5e tx64's vector helpers are no longer hot
This is cheating wrt tx64 vs. hhir but that battle's already
been decided. We should be able to just remove these completely soon.
2013-05-10 10:54:38 -07:00
Jordan DeLong 4601297ae8 Make a toVariant() function on ArrayInit @override-unit-failures
Suggested by @smith.
2013-05-10 10:54:38 -07:00
Jordan DeLong abd3808eb3 Minor improvements to ArrayInit
Remove implicit conversion operator.  Also found some apc
code that relied on copy elision for correctness.
2013-05-10 10:54:37 -07:00
Owen Yamauchi a6663759d2 Stop boxing everything in the JSON parser
The JSON parser was producing structures that held all arrays in
RefData. This was to defeat copy-on-write, since ArrayDatas were
referenced from multiple places (i.e. the parser's internal stack of
in-flight objects, and the actual structure being built) and mutated. I
rectified this by not adding arrays into the overall structure until
they're done being modified. This necessitated introducing a separate
stack for keys, to handle this structure:

  { "key": { ... } }

When we see the opening { of the inner object, we push "key" onto the
stack, so that when we see the closing } of the inner object, we can
store it into the outer object under the right key.
2013-05-10 10:54:37 -07:00
Edwin Smith 494733bd31 Remove Array::operator[](litstr)
Refactor the remaining uses of litstr-indexed Array, and
get rid of the operator overload.
2013-05-10 10:54:37 -07:00
Mike Magruder e967eb197f Add more server-side debugger logging, small tweaks to server-side error paths
Added some more logging on the server when debugging. Log warnings during shutdown (normal and from the signal handler) when there are debuggers attached. Minor tweaks to some of the error handling paths, with more log messages instead of silent failures. Also moved server-side closing of the thrift buffer to proxy destruction.
2013-05-10 10:54:24 -07:00
Paul Tarjan 0aad5e95bf support pcre ini options 2013-05-09 11:38:06 -07:00
Paul Tarjan b3ededfdc6 fix flakey text
reported by @aalexandre. Sharing filenames is bad.

done with

  ./tools/import_zend_test.py -z /tmp/php-5.4.13/ -o bug41445
2013-05-09 11:37:58 -07:00
Paul Tarjan bb37e7c5f2 Disable flakey test 2013-05-09 11:37:42 -07:00
Mark Williams 1e75626704 Keep track of whether we're jitting or not
Rather than test RuntimeOption::EvalJit and 5 thread locals to determine
whether or not to run the jit on each re-entry, maintain one thread local.
Make various RequestInjectionData fields private to ensure that the jit
flag is kept in sync.
2013-05-09 11:37:41 -07:00
Drew Paroski 7ff13c1906 Remove more ClassInfo goo
Remove more uses of ClassInfo in favor of VM::Class, VM::Func, etc.
2013-05-09 11:37:41 -07:00
Edwin Smith e1ee546e33 Move register allocator fields out of SSATmp
These are not used except between linearscan and codegen,
so put them in a StateVector instead.
2013-05-09 11:37:40 -07:00
aravind b3bcab18be Inline FPushCtor
Similar to FPushCtorD
2013-05-09 11:37:40 -07:00
bsimmers 120ed539e4 Clean up IR printing
This creates a tracemod that does nothing but print the IR
(printir). I reworked the levels a little so you can reduce the number
of passes that are followed by a dump of the IR. I'm open to
suggestions on the order I set up in print.h.
2013-05-09 11:37:40 -07:00
Mark Williams bf0dd20fef Rewrite fb_intercept to use the FunctionEnter hook
This cleans up the code a lot, and takes it out of various hot
paths. It will impact perf for requests where intercepts are used,
but no longer penalizes requests that don't use intercepts.
2013-05-09 11:37:39 -07:00
Paul Tarjan c4357440b0 slice up builtin_extension
This .expectf files turns into a huge regex and is our largest one. Instead lets have many small tests.

I made it with some fancy bash script.
2013-05-09 11:37:39 -07:00
Paul Tarjan 155aeba44b Fix tests not able to run in parallel
Reusing filenames is bad.
2013-05-09 11:37:09 -07:00
Sean Cannella 7651d0d57b Don't show line number/file for generator psuedo methods. 2013-05-09 11:34:36 -07:00
Guilherme Ottoni e4231921e3 Enable translation of BindS
The code was there, but we were still punting.
2013-05-09 11:34:35 -07:00
Paul Tarjan a220ce802f Enforce disable of flakey tests
This will make future imports of these not re-enable them
2013-05-09 11:34:13 -07:00
Edwin Smith 494e87cbd1 Move m_id and m_lastUseId to LifetimeInfo
These two fields represent the results of liveness analysis,
so group them together that way.
2013-05-09 11:34:12 -07:00
Jordan DeLong d467787a45 Use ArrayInit in debugBacktrace
Presize the arrays.
2013-05-09 11:34:12 -07:00
Jordan DeLong 774fbc7d16 Move static strings out of debugBacktrace
We're paying for some null checks here each time we do a
backtrace.  Inspected all usage sites of the other StaticStrings to
ensure adding "consts" shouldn't change behavior (similar to that
ternary operator issue @smith ran into).  Also remove a bunch of
temporary smart pointers that we don't need anymore.
2013-05-09 11:34:12 -07:00
Jordan DeLong 6b8e5611d6 Make it unnecessary to null out locals during RetC
We already look up the PC for every frame as we're taking the
backtrace, so we can just skip them when going through a backtrace
frame.  Also, there is currently a guarantee that if an exception
propagates through a frame where pc was pointing at RetC, all the
locals and the $this pointer have already been decref'd, so we don't
need to use a null check to determine this.
2013-05-09 11:34:11 -07:00
Paul Tarjan 8047bac356 line up stuff
These are the only braces not lined up on that column in this file.
2013-05-09 11:33:53 -07:00
Jordan DeLong 5b7a3e3895 Clean up and document SRFlags
Make it part of abi-x64.h and explain what the flags mean.
2013-05-09 11:33:52 -07:00
Jordan DeLong 27fa04f132 Clear local related helpers out of TraceBuilder
Optimizations went to Simplifier or preOptimize (or were
removed in some cases where they duplicated things already done in
simplifier), php-semantics went to hhbctranslator.
2013-05-09 11:33:52 -07:00
bsimmers ce48632a40 Don't template on op for SetOpProp and IncDecProp
The only difference between each template specialization was
the op they were passing into a rather deep chain of helpers. None of
them are very common either, so it's not worth the code bloat.

Unfortunately the setOpProp helpers now need 7 qwords of arguments so
one of them has to be passed on the stack. I added support for that to
codegen.
2013-05-09 11:33:52 -07:00
Paul Tarjan e731304d3d make test/run work on stock PHP
I want people to start contributing to us from the community. I think them running the tests would be a good idea on any patch. I don't really want to assume they replaced their php binary with hhvm just yet, so I think the test runner should work on whatever php is in the path
2013-05-09 11:33:23 -07:00
Erling Ellingsen 1e78ff4999 Allow type aliases to take (ignored) type arguments
type Foo<T> = Bar<T,T> is treated as Foo = Bar; Foo<T> = @?T isn't supported.
2013-05-09 11:33:23 -07:00
aravind b558f6f118 Inline object constructors
This should automatically handle the case when we had
a generated 86pinit constructor.
2013-05-09 11:33:23 -07:00
Jan Oravec 4780da0ed7 Add missing #include
Add missing #include.
2013-05-09 11:33:22 -07:00
Edwin Smith 8985169828 Move spillslot field from SSATmp to linearscan pass
Spillslot is an internal field for the linear scan pass,
we don't want it in SSATmp.
2013-05-09 11:33:22 -07:00
Jan Oravec f2cf5fbaac Provide safe storage for private PHP data in external thread events
Sometimes, a PHP object (usually defined by extension) is needed to
unserialize the data.

Provide a safe mechanism to store such object with external thread
events.
2013-05-09 11:33:22 -07:00
Jordan DeLong cc57737f6b Disable some flaky zend tests @override-unit-failures 2013-05-09 11:33:21 -07:00
Edwin Smith 957b19d088 Move m_liveRegs out of IRInstruction
The live regs field in IRInstruction is the result of an analysis
pass which can be better encapsulated by moving the field into
its own StateVector.
2013-05-09 11:33:21 -07:00
Paul Tarjan 257825efa5 re-enable tests
These were reported (correctly) as crappy and disabled in D801504. I fixed them.
2013-05-09 11:33:21 -07:00
Andrei Alexandrescu e6ff1ebf2c Eliminate circular dependency in SmartAllocator
SmartAllocator defined and used an enum for each type using smart allocation, thus closing a circular dependency loop. In fact the enum is not necessary and can be replaced with typeid with relative ease. While at it I've also simplified GarbageList a bit.

Also fixed a couple of lint errors.

Perflab completed, looks neutral to good: https://our.intern.facebook.com/intern/perflab/details.php?eq_id=399305
2013-05-09 11:33:20 -07:00
Philippe Ajoux e551d3918f add hooks to ASIO to allow building of dependency graphs in PHP
In order to build a dependency graph of continuation execution and data-fetching in PHP-land, we need a few instrumentation points in the asio_ext HHVM extension. There are 4 additions required:
   1. Callback when a continuation finishes successfully.
   2. Callback when a continuation blocks on a wait_handle.
   3. Get array of WaitHandles a GenArrayWaitHandle is waiting on.
   4. Get WaitHandle that the SetResultToRefWaitHandle is waiting on.
I don't think this should really affect performance, as in the normal case, nothing has changed, but you never know... I'm also not sure who should be reviewing this, so I've just added @jan for now. If you could pile other people on, that would be cool.

sandcastle appears to be broken.
2013-05-09 11:33:20 -07:00
Edwin Smith 4fdec8b2a1 Move pretty-printing code into its own file
Pretty-printing the IR is a kind of pass, and definitely a separate
concern, just like rendering IR as machine code.  Put it in its own file.
2013-05-09 11:33:19 -07:00
Wez Furlong d1e4f65ec9 proc_open should inherit g_context->m_envs
Some head scratching until I realized that my `putenv()` calls
in my PHP script weren't actually changing the environment for subsequent
`proc_open()` calls.

What I'd like this diff to do (and I fully expect that I'm violating some
referencing rules in hhvm) is to fall back to using our current view of
the environment as maintained in the execution context in the case that
proc_open is not explicitly passed an environment array.

I think I've even added a test to prove that this works, but I haven't
read the manual and fbmake runtests takes too long, so I'm just going
ahead to submit this diff.
2013-05-09 11:33:11 -07:00
Sara Golemon 708d16ca32 Merge pull request #758 from tstarling/master
Add missing macros to timelib_config.h
2013-05-08 20:39:07 -07:00
Tim Starling 9832e88a27 Add missing macros to timelib_config.h
The absence of HAVE_LIMITS_H caused timelib_structs.h to define LONG_MIN
and LONG_MAX to be 32-bit values, which caused timelib_date_to_int() to
give an error for a date after 2038, which caused the current time to be
returned for e.g. date_create('28 July 2038')->format('r').

The issue was detected by MediaWiki unit tests, and this fix was tested
by the same method.

While I was at it, I also added HAVE_LOCALE_H, which was checked for in
CMakeLists.txt but not used, and I fixed the definition of SIZEOF_INT
(#cmakedefine doesn't work that way). I arranged the macros in
timelib_config.h.cmake in the same order as they are in CMakeLists.txt.
2013-05-09 12:41:14 +10:00
jdelong dcd704f2f3 Minor cleanup in srcdb.h
Mainly gets rid of the need to pass Asm& a and astubs
to all the patching functions.
2013-05-07 10:56:32 -07:00
Guilherme Ottoni a111aaa518 Streamline exits from HHIR to Interp when Tx64 is off
If Tx64 is disabled, change slow exits to call the interpreter directly.
2013-05-07 10:55:32 -07:00
bsimmers 8436050f1f Use traceRelease for Eval.DumpBytecode
This shouldn't be restricted to debug builds.
2013-05-07 10:55:32 -07:00
bsimmers d559b8f1e1 Disable some zend tests reported as flaky 2013-05-07 10:55:32 -07:00
bsimmers 983a68a4b7 Fix runtime options for tests
My diff to turn the ir on by default missed a few places that
need HHIRDisableTx64=0.
2013-05-07 10:55:32 -07:00
Mike Magruder ed8fb402c0 Improve the Next command to not interpret and single-step ever line under calls from the original source line
This improves both Next and Out to avoid interpreting and stepping everything between when they start and finish. Out now lets the program run free until a pseudo-breakpoint at the return site it hit. Next continues to single-step the source line being stepped over, but now lets the program run free under calls made from that line.

The logic in Next regarding "calls made from that line" is extremely generic. We don't look at, say, call opcodes and decide to do something special. Rather, when we find we're off the original source line and a frame deeper we setup a "step out" operation much like the Out command then let the program run free. When we reach our return point, we continue stepping like normal. This accounts for not just calls, but iterators, and anything else that causes more PHP to run under the original source line.

This change moves the flow control logic down in to the respective cmds: Next, Step, Out, Continue. These cmds get a crack at executing at various points in the interrupt/command processing path. These cmds now own setting up the last location filter, whether they need VM interrupts, and whether they're done or not.
2013-05-07 10:55:31 -07:00
Guilherme Ottoni 0cd3186819 Fix trace exit type for IncDecL of boxed values
For accesses to boxed locals, if the inner type changes, we can
retranslate using HHIR: the new translation will inspect the live type
and be able to execute the instruction.  While looking at something
else, I noticed that in such cases IncDecL was taking a slow exit
(which avoids using HHIR).
2013-05-07 10:55:31 -07:00
Jordan DeLong 2d376658d9 Move remaining stack optimizations to simplifier
Removes all their genFoo functions and does the corresponding
work in Simplifier, since it requires no state.
2013-05-07 10:55:31 -07:00
Jordan DeLong f8ae6b7149 Add a OpNot to HHIR; remove TraceBuilder::genNot
There's always been a little weirdness in the simplifier with
regard to negation.  Apparently I used to think it could lead to
losing a ConvToBool (I am not 100% sure what the case that comment
refered to was now though).  It definitely lets us avoid some
zero-extending bools to ints though (since our binary arith guys don't
support bools yet), and with this the last "dubious" genFoo is gone.
2013-05-07 10:55:30 -07:00
Jordan DeLong 71a51b31ec Minor tweaks to StateVector @override-unit-failures
- Move to state_vector.h
- Use smart::vector instead of std::vector
- Make factoryId and count helpers private
- Add const_iterator support
- Make grow() use resize() instead of looping push_back().
- Use assign() in reset().
2013-05-07 10:55:30 -07:00
Edwin Smith 08693f9d6f Only rematerialize instructions when its safe to.
Only rematerialize an instruction if its inputs are still live
and in registers at the point we're cloning it, which, given the current state of flux in the register allocator, is restricted for
now to just instructions that consume rVmSp, rVmFp, or immediate constants.
2013-05-07 10:55:30 -07:00
Sara Golemon 497a22c04f Fix endianness for all tiger algos
The PHP version the implementations in hphp were based off of
had wrong byte ordering.  Fix them in line with PHP having been fixed.
2013-05-06 10:31:24 -07:00
Sara Golemon 2dcca1dded Add fnv1a?(32|64) hash algos
Split out of my previous "fix varios hash algos" diff.
This diff adds the fnv132, fnv1a32, fnv164, and fnv1a64 algorithms
2013-05-06 10:31:24 -07:00
Sara Golemon c121b10e13 Add SHA224 hash algo
Split out of my earlier "fix varios hash algos" diff
This diff only adds sha224.
The fix for tiger and the add of fnv are in different diffs.
2013-05-06 10:31:24 -07:00
Edwin Smith bdb7e9428e Remove emitSmashableFwdJump() and appendSrc()
Dead code.
2013-05-06 09:53:49 -07:00
Rasmus Lerdorf 2b23084f39 Fix program args not having a space
When inputs.size() is 1 and we have programArgs,
we wind up squashing those two values together.

Be pessimistic and always add the space in.
2013-05-06 09:53:36 -07:00
Edwin Smith 36a27765d2 Use a DCE-local state vector for use counts
Moving more pass-specific information out of SSATmp.
2013-05-06 09:31:45 -07:00
Drew Paroski 697bca0182 Improve var_export for collections
The current output of var_export for collections isn't very useful. It
outputs a call to __set_state like so:

  Map::__set_state(array(..))

This isn't particularly useful since collections don't implement the
__set_state() method, and it is also suboptimal for the design of
collections since it relies on using PHP arrays.

This diff changes var_export to use collection literal syntax for
collections instead of generating a call to __set_state().
2013-05-06 09:31:44 -07:00
Drew Paroski 7f97e9d784 Remove "const char* cls" parameter from cppext static methods
For cppext static methods we have a "ti_" method that takes an extra unused
parameter "const char* cls" and then a "t_" wrapper method that calls the
"ti_" method.

This makes things unnecessarily complicated when writing HipHop extensions.
Let's get rid of the extra unused parameter "cls" and the unnecessary "t_"
wrapper method.
2013-05-06 09:31:44 -07:00
Paul Tarjan 6589da0e87 lots of race conditions in zlib 2013-05-06 09:31:39 -07:00
Sara Golemon 0bfab33ce9 Fix logic fail and unsets in DefineConstant()
If we infer the type, then we already know
its integer type ID.  Trying to then parse that type
leads to "Undefined type" errors (but it still functions
due to the fallthrough).

This diff skips trying to parse a known type and thus
avoids the misleading error message.

Also guard against missing funcs/consts elements in
global scope and classes.
2013-05-06 09:31:38 -07:00
bsimmers 59beab1596 Don't dereference a null array in our SIGCHLD handler
Sometimes this array is destructed by the time the handler is
called.
2013-05-06 09:31:38 -07:00
Mark Williams 270227c36c Don't leak cloned closures/continuations
Instead of appending the new closure to the end of the list,
the list was being cleared, and then the new closure was added.

Most closures only get one clone (since we don't yet support bind)
but occaisionally, closures (or continuations in closures) inside
traits can end up with more than one. In that case, we ping-pong
between the different clones, generating new clones, and new code
as we go.
2013-05-06 09:31:38 -07:00
Edwin Smith 302acd0941 Remove extraneous trace->print() causing double listings
Accidental call.
2013-05-06 09:31:38 -07:00
Mark Williams a32d993f1f Fix remaining QuickRepoJitIR test, and enable them
We intentionally drop some notices in production by default.
Add an opts file to prevent that.
2013-05-06 09:31:37 -07:00
Drew Paroski 21b8949d23 Make array_key_exists support collections efficiently
array_key_exists() was converting collections to arrays before checking if
a key exists, which is an O(n) operation (which also has the annoying side
effect of changing int-like string keys to int keys.)

This diff makes array_key_exists natively support collections (which also
addresses the pesky int-like string key -> int key issue).
2013-05-06 09:31:37 -07:00
Jan Oravec 4e169c6bda Remove deprecated ContinuationWaitHandle::start()
ContinuationWaitHandle::start() was deprecated in favor of Awaitable
interface's getWaitHandle().

Remove ContinuationWaitHandle::start() from public API and rename it
internally to c_ContinuationWaitHandle::Create() that is called only from
Continuation's getWaitHandle(). Since it is guaranteed that the
Continuation does not have associated any wait handle, we can remove the
code that handles that case.
2013-05-06 09:31:36 -07:00
Sara Golemon 16e0a5bdf0 Fix race condition in ext/sockets/tests
This time the race condition comes from binding sockets!
2013-05-06 09:31:36 -07:00
Edwin Smith d15e609333 Revert "Do copying with the AttachLiteral constructors."
Revert "Explicit CopyString, remove (const char*) constructors."
2013-05-06 09:31:26 -07:00
Sean Cannella 9bc56bdeb5 use byte instruction for boolean binary ops in hopt
- use byte instead of qword instructions to perform binary operations on two booleans
2013-05-06 09:09:05 -07:00
Sara Golemon 3858cae7e8 Generated ext_hhvm files live in CMakeFiles not next to what they're wrapping 2013-05-03 12:02:55 -07:00
Sara Golemon cf076e8972 Link dl, pthread, and glog into gen-ext-hhvm, gen-infotabs, and folly 2013-05-02 16:21:02 -07:00
Mark Williams 57e10942ba Undo systemlib change
Put systemlib in the repo again, and use it for repo-authoritative builds
2013-05-02 10:14:16 -07:00
Andrei Alexandrescu 11151fe1ea Eliminate unnecessary and unawesome instances of dynamic_cast<HphpArray*>
There are two dynamic_cast<HphpArray*> instances in bytecode.cpp that cause code to fail when using other types of arrays. However, the necessity of those casts seems to have disappeared in the meantime because simply removing them compiles and runs. I have ran full 'fbmake runtests' after removing the first cast (all passed). Then I removed the second cast (in lexical order) and ran the tests again. This time test/zend/good/ext-hash/hash_file_basic.php failed, but when I ran it again in separation it passed.
2013-05-02 10:14:16 -07:00
Jan Oravec 88687ba6f7 Add support for external thread events
Add support for external thread events.

See asio_external_thread_event.h for details about usage.

This is the first version that compiled, the code was not executed even
once, but wanted to get it out early to unblock @hannesr. Thus the [RFC]
flag.

My next step is to implement asio-compatible equivalent of
fb_call_user_func_async() that will make it possible to easily test the
new functonality by simulating async stuff with sleep(), etc. on the PHP
side.

There are 2 major mostly lockless synchronization points that needs
careful review:

- queue of ready external thread events (asio_session.{cpp.h})
- shutdown cleanup (asio_external_thread_event.{cpp,h})
2013-05-02 10:14:16 -07:00
Jan Oravec 8f3e34430c Remove deprecated WaitableWaitHandle::getStackTrace()
WaitableWaitHandle::getStackTrace() is not used anymore. The stack trace
is computed on the PHP side using the provided reflection API.
2013-05-02 10:13:57 -07:00
Mark Williams b38422cfa1 Close the file handle after finding a section
The code to find an elf section in the binary left the
binary open.
2013-05-02 10:13:39 -07:00
Mark Williams 30075b74c9 Reduce repo contention issues
If there were multiple processes (or threads) trying to write to
the repo, we were spending a lot of time in raw_spin_lock, resulting
in almost no forward progress. The new test case runs in about 8
seconds on my dev server, with a debug build, but didnt complete in
20 minutes when using the current release build of hhvm.

I also removed the 20 thread limit on the test runner, which
drops the time for SlowJit from about 1:45 to 1:30, and should
no longer cause repo-contention issues.
2013-05-02 10:13:38 -07:00
Drew Paroski a3620e7758 Remove hphp_get_iterator and related dead code
This code is no longer used, let's get rid of it.
2013-05-02 10:13:38 -07:00
Owen Yamauchi e6a3807f23 Support generating ext_hhvm files with ARM ABI
ARM's convention for returning bigger-than-a-register types is
different; there's a register reserved for the purpose of passing the
return-value pointer. On x64, it just gets added as a hidden first
parameter.
2013-05-01 23:01:13 -07:00
Jordan DeLong eec5d43e4c Remove legacy makefiles (take 2)
We need to leave runtime/tmp for TestServer and TestDebugger,
but they don't actually use the old makefiles.
2013-05-01 21:00:49 -07:00
aravind a5102a5d5e Implement FCallArray in IR 2013-05-01 21:00:49 -07:00
Sara Golemon 32b76a7a3c Fix race condition in test/.../ext-hash/hash_file_(basic|error).php
Fix pushed upstream already
2013-05-01 21:00:48 -07:00
Paul Tarjan c11c56d9f9 fix dupe filename
./tools/import_zend_test.py  -z /tmp/php-5.4.13/ -o filesize_variation3
2013-05-01 21:00:48 -07:00
Jordan DeLong effe6d71f3 Omit stack overflow checks on leaf functions
I did an experiment turning off all stack checks, and it
looks like it does cost something.  This seemed like an easy way to
turn it off some of the time, but maybe we should resurrect the SEGV
handler.
2013-05-01 21:00:48 -07:00
Drew Paroski 9a804f6463 Implement Set 2013-05-01 21:00:47 -07:00
Jordan DeLong 0a4bb765e0 Move ConvFooToBool selection to Simplifier
This is stateless---and it's possible the second
simplification pass may be able to perform more of it if operand types
change somehow (wishful thinking?).
2013-05-01 21:00:47 -07:00
Jordan DeLong 1e1166d4d4 Remove genAssertStk/genCastStk and move their optimizations to Simplifier
The elimination of these is stateless, so it's going to
simplifier (along with getStackValue).  Other stack functions are
still here until I move EvalStack to tracebuilder.
2013-05-01 21:00:47 -07:00
Jordan DeLong c3619ecd7b Remove some easy remaining TraceBuilder::genFoo functions
This diff should have nothing very interesting in it.
2013-05-01 21:00:46 -07:00
Jordan DeLong d936b8e120 Document TraceBuilder/HhbcTranslator/Simplifier @override-unit-failures
Adds comments explaining the role of each of these modules.
The comments explain the roles as I am planning to make them, not as
they actually are, so they are currently partially lies.  (I will move
EvalStack into TraceBuilder, and get the remaining "dubious" gen
routines out to HhbcTranslator on top of this diff.)
2013-05-01 21:00:46 -07:00
Jordan DeLong 0f752932cf Move gen{Guard,Assert}Loc logic to updateTrackedEffects/preOptimize
GuardLoc drops into preOptimize.  genAssertLoc did two things
based on a bool---one of which needed logic in preOptimize, and the
other which implied something for updateTrackedEffects (and was
handled in hhbctranslator).  Also removes genLdAssertedLoc---it's not
an instruction; I considered an emitLdAssertedLoc but since this is
only used in a few places (less than a LdIncRefLoc would be) it seemed
fine to just flatten.
2013-05-01 21:00:39 -07:00
Jordan DeLong 3e93f5404e Remove genDecRef from TraceBuilder
Replace with a preOptimizeDecRef.  Also caught a pseudo-issue
where we relied on the isRefCounted short-circuit for correctness (we
called genDecRef on Type::Cls).  That short-circuit is duplicated in
simplifier, and is stateless, so let's leave it there.  Remove some
dead code about BoxedCells and replace it with a comment in
ir.specification based on a conversation with @bsimmers.

(This is on top of all the other related diffs.)
2013-05-01 21:00:39 -07:00
Jordan DeLong a2eec97e62 Rename TraceBuilder::genDefConst to cns()
Closer to the same instruction creation api in each.
2013-05-01 21:00:32 -07:00
Jordan DeLong 0903f92a76 Fix arithmetic op uses of type paramters, get rid of gen{Sub,Mul,...}
These guys were determining their output type with DParam,
even though the output type was a function of the input types.  Fixed
this and then get rid of the genFoo wrappers.  Move binArithResultType
out of Type.  OpMod didn't need a type parameter.
2013-05-01 21:00:32 -07:00
Jordan DeLong 406eb59593 Simplifier gets gen()/cns(), replace genDefConst with cns outside tracebuilder
Also removes simplifier's genDef{Bool,Dbl,Int}.
2013-05-01 21:00:31 -07:00
Jordan DeLong 68cfa7c17e TraceBuilder and VectorTranslator get forwarding gen() helpers
s/m_tb(->|\.)gen/gen/
2013-05-01 20:59:46 -07:00
Jordan DeLong 858731971a Remove many of the genFoo functions from tracebuilder
Removes most of the wrappers in favor of gen(). Does two
cases that actually had logic by adding a new "preOptimize" pass where
TraceBuilder can use tracked state to modify instructions before they
go to the simplifier.
2013-05-01 20:59:46 -07:00
bsimmers 66f23c5c06 Kill alwaysLowMem
We're hitting the assert in some jobs (see task) and it's not
a measureable win.
2013-05-01 20:59:45 -07:00
jdelong b26e59a920 Inline the outer functions for continuations with no arguments
We store a bunch of data into an ActRec on the stack, then
call a php-level function that calls a C++ function to copy it into an
ActRec on the heap.  This should hopefully be a little better.
2013-05-01 20:59:45 -07:00
Jan Oravec 102c37cdcb Remove deprecated asio_* methods
Remove unused deprecated methods:

- asio_enter_context()
- asio_exit_context()
- asio_get_current()
2013-05-01 20:59:45 -07:00
Sara Golemon 38f9fab773 Fix __HALT_COMPILER() support
Actually halt the compiler, and set __COMPILER_HALT_OFFSET__ constant
2013-05-01 20:59:44 -07:00
Drew Paroski 6a2c5150ed "trait implements" syntax 2013-05-01 20:59:44 -07:00
Andrei Alexandrescu e434a1872d Simplify test output 2013-05-01 20:59:37 -07:00
Mark Williams 6cb23e0f56 Don't cse LdCns
Because in php, constants aren't.
2013-05-01 14:47:14 -07:00
Mark Williams 17a8693f65 Don't crash reversing empty Vectors
In a new, empty vector start and end are null.
2013-05-01 14:47:14 -07:00
Sara Golemon 2aa8ed4814 Sync parser generator with upstream 2013-05-01 14:47:13 -07:00
Sara Golemon 85cd3df409 Require CMake version 2.8.5 or higher
Support for hand-written assembly was "experimental" in older
versions and would select the wrong compiler yielding a build
failure.

2.8.5 and later do the right thing.
2013-04-30 10:20:41 -07:00
Mark Williams 6f4b1c76a8 Fix issue with call_user_func_array and by-ref params
We can't box a non-ref value for a ref param because
we could be modifying an array with refCount != 1.

zend warns, skips the call and returns null. For now, this
makes us warn, but do the call (without modifying the array).

A file scope flag controls whether to skip the call or not,
and should be changed (and eliminated) once all our tests pass.

With the flag turned on, we still dont match zend's behavior,
because its happy to go ahead and call the function with no
warning in the case of a literal array parameter
(cuf('foo', array(1))), even though it warns and skips it when
the array is in a variable ($a=array(1); cuf('foo', $a)).
2013-04-30 09:58:57 -07:00
Jordan DeLong b3ae38b6c0 A few minor tweaks about HPHP_HOME
I think everything should work without it now.
2013-04-30 09:58:56 -07:00
Owen Yamauchi a57ae0488a Generate the parser at build time, part one
Update a number of things to make optionally generating the parser at
build time possible.  @sgolemon will add the OSS pieces of this in a
separate commit.
2013-04-30 09:57:57 -07:00
Dario Russi 36326b4de0 rename getReturnTypehintText() to getReturnTypeText() to be consistent with the new API that drops the 'hint' part in the method name
Simple renaming of method for consistency reasons
2013-04-30 09:27:08 -07:00
Guilherme Ottoni 7900cb18d1 Move translation counters after tracelet guards
With HHIR, I noticed they were being emitted before the guards.
Instead of having the insertion logic check for first marker, add an
IR instruction for incrementing the counter.

Also, got rid of firstMarkerSeen flag.

And also fixed lint warnings while here.
2013-04-30 09:27:07 -07:00
Owen Yamauchi 79b8d27a80 Add a bit of graceful error handling to C++ IDL code
Instead of failing obtusely, do some checking of the JSON schema so we
can produce useful error messages. This doesn't strictly check
everything that could be checked, but it will catch the most common
errors (i.e. the ones I discovered while making this change originally).
2013-04-30 09:27:07 -07:00
Jordan DeLong d5bfa422b8 Do assertOperandTypes on each instruction after each pass
Check for broken invariants.
2013-04-30 09:27:07 -07:00
Jordan DeLong 8fb0544504 Fix a bug in HHIR's emitParent
We actually grabbed the parent of the parent.  This means
things like parent::foo() were skipping the immediate parent.
2013-04-30 09:27:07 -07:00
Edwin Smith 12c676bc8b Litstr must die, episode V.
Removed the litstr overloads of Array::rvalAt, rvalAtRef, lval,
lvalPtr, lvalAt, and set.  The main one left to do is operator[].

Fixed a bug in f_get_html_translation_table() where we were copying
the null terminator of what should be a one-character string, thus
creating a two-character string with s[1] == 0.  (cc @jdelong)

In class Extension, store a String for the name instead of
const char*.  cc @sgolemon
2013-04-30 09:27:06 -07:00
mwilliams db271750c3 Allocate registers for the main trace first
Linearscan placed the exit traces immediately after
the branch to them. This meant that they could cause spills in
the main trace. This diff re-orders things so that they come last,
but saves the state at each exit point, and restores it before
allocating each exit trace.

I've not yet dealt with the "live across native calls" case, so
this does cause more registers to fall into that category. I'll
tackle that in a follow up diff. But this already seems to be on the
good side of neutral.
2013-04-30 09:27:06 -07:00
Mark Williams 825ba1200f Don't issue MissingAbstractMethodImpl warnings unless WholeProgram
Local linting just looks at the files that were changed,
so we dont always see the implementation of an abstract method.
Disable the warning in that case. We'll still catch it when
we do whole program linting later.
2013-04-30 09:27:06 -07:00
Jordan DeLong e7999d34bc Keep simplifyCall stateless
Read the stack out of the instruction instead of out of
TraceBuilder's current stack pointer.
2013-04-30 09:27:05 -07:00
Paul Tarjan 51151a407f import non-predictable number tests
I couldn't handle these until we had ##.expectf## support. Now we do.
2013-04-30 09:27:05 -07:00
Paul Tarjan 5ca1e9b337 make test runner work in open source repo
Our contributors should be able to run the tests.
2013-04-30 09:27:05 -07:00
Drew Paroski 86a616a220 Add KeyedTraversable interface 2013-04-30 09:27:05 -07:00
Drew Paroski aa8b2afc7d Make new reflection API instead of changing getTypehintText()
A bunch of tests were failing because the behavior of getTypehintText()
changed. Instead of changing how getTypehintText() behaves, let's just
introduce a new reflection API, and then tests and application code can
be changed to use the new API later.
2013-04-30 09:27:04 -07:00
Mark Williams f48de277d4 array_values dropped references
It should preserve them. This was breaking pass-by-reference
via ReflectionFunction::invokeArgs.
2013-04-30 09:27:04 -07:00
bsimmers 603d50c7b1 Shorten SSATmp::getInstruction, SSATmp::getType, IRInstruction::getOpcode
The function names were too damn long.
2013-04-30 09:27:04 -07:00
Paul Tarjan 90e7a30404 fix shared test name
This test was imported WITHOUT hard-coded output. Meaning it was compared to zend. It so happened that I had cleaned my repo after any runs of ##TestExt## so the file they both created (and sometimes didn't clean up) didn't exist. So that is the output I recorded.

@mwilliams do you think you intended for the file to exist? It wasn't in the repo.

With this diff I'm using a unique filename so it doesn't matter if ##TestExt## hasn't cleaned up perfectly.
2013-04-30 09:27:04 -07:00
Edwin Smith b7cc57a8db Explicit CopyString, remove (const char*) constructors.
This gets rid of the (litstr) StringData and StackStringData
constructors, but keeps String(litstr).  Also rename all
the instances of AttachLiteral to CopyString, since they now
mean the same thing.
2013-04-30 09:27:03 -07:00
bsimmers 8760794304 hhir punting to interp by default, master version
Let's do this. It's already on in the current rc; this is
mostly to get another test run on current master.
2013-04-30 09:27:03 -07:00
Dario Russi 6e510c2081 fix reflection parameter problem where type and type hint were made to collide. Separated the two...
ReflectoinParamenter was fetching both type and type hint from the same field. That created an incompatible change with existing code and broke the mocking framework. Separated the type and type hint field to contain the possible different values.
2013-04-30 09:27:03 -07:00
Paul Tarjan 5aede8cba8 fix segfault
Don't assume we are in a function.
2013-04-30 09:27:02 -07:00
Rasmus Lerdorf 441c137dcb Implement PHP 5.4's short array syntax
We have traits and some other PHP 5.4'isms why not the short array syntax as well?
2013-04-26 13:28:39 -07:00
jdelong b6c11c0fc0 Add SpillStack's sources to the instruction type assertions @override-unit-failures
Check the types on its sources.
2013-04-26 12:59:48 -07:00
jdelong 9749e6bd54 Initial support for inlining small functions
Sets up the translator analyze pass to create a Tracelet for
the callee at every statically-known FCall.  If the callee has an
appropriate shape (in this diff, it must be a function consisting of
"return $this->foo" for a declared property), we can inline it in
HHIR.  Restructures the IR relating to frames some so we can eliminate
the stores relating to ActRec in this simple case (see the comments in
dce.cpp and hhbctranslator.cpp for details).  Includes partial support
for inlining callees with locals, but it's disabled for now because
they will keep the frame live.
2013-04-26 12:59:48 -07:00
Mark Williams 3b8b611627 Fix a missing SpillStack
LdClsPropAddr can throw if it doesn't have a target.
2013-04-26 12:59:47 -07:00
bsimmers 41f2b117ee Revert "Fix varios ext/hash algorithms"
This was causing an unexplainable perf regression.
Revert it for now pending deeper analysis.
2013-04-26 09:31:13 -07:00
Bert Maher cea48118bf Create a FramePtr type for the IR and use it where appropriate
Even though a stack pointer and a frame pointer are pretty
similar things, it's nice to be able to tell just by looking at the
type whether we're dealing with something on the eval stack or
something at a frame pointer offset.  Adding this type makes it clear
where things need to change to modify the ABI.
2013-04-26 09:31:07 -07:00
bsimmers 1c2a22180d Don't check surprise flags in onFunctionExit
It's causing unwinding problems.
2013-04-26 09:31:00 -07:00
Paul Tarjan 2da286594d fix race in mkdir 2013-04-26 09:30:54 -07:00
Paul Tarjan fe7efe7192 fix race condition in SplFileInfo_getInode_basic
These failed once on @smith's diff and I think it was from them both running at the same time.

I'm not really sure why the others changed their path, but that is the original zend file.
It shouldn't matter as it is a error line that will be set to whatever we print out if the test passes.

Done with:

  tools/import_zend_test.py -z /tmp/php-5.4.13/ -o SplFileInfo_get
2013-04-26 09:30:15 -07:00
Paul Tarjan 52305fda58 read all of stdin 2013-04-26 09:29:56 -07:00
smith a73e674aea Litstr must die, episode IV.
Removed Array::remove(litstr).  Grouped the other litstr overloads
together and reimplemented each one in terms of the CStrRef overload.
2013-04-26 09:29:53 -07:00
Edwin Smith 410a105184 Do copying with the AttachLiteral constructors.
And, remove the IsLiteral string kind.  This removes the hazard of
creating a string whose data is freed before the string.  Callsites
passing in a literal should use StaticString.  Everything else
can use CopyString or AttachString.
2013-04-26 09:29:48 -07:00
Sara Golemon 4c4d11304a Add a rule for generating the parser from util/parser/hphp.y 2013-04-25 19:40:25 -07:00
Sara Golemon 065ac81ee8 Hunt down pthread instead of just assuming that we'll find it. 2013-04-25 16:42:05 -07:00
Sara Golemon b10a27e178 Generate ext_hhvm/infotabs files on the fly rather than as pre-builds 2013-04-25 15:33:05 -07:00
Sara Golemon c2d720b1a6 Clean up some leftover pieces of unused stuff 2013-04-25 15:13:59 -07:00
Mark Williams 72ae1b9f85 Get rid of o_isClass 2013-04-25 11:34:23 -07:00
Mark Williams 6dc8c10bae Fix types for builtins
Unknown types should generally be Type::Variant, except
in the case of parameters, where they should be Type::Any.

The difference is that coercing to type Any doesnt affect the
existing type, where coercing to type Variant forces it to
type Variant.
2013-04-25 11:34:22 -07:00
Jordan DeLong 1bcfc357fd Rename equals/hash to cseEquals/cseHash and assert canCSE() 2013-04-25 11:34:22 -07:00
Jordan DeLong 55ba7a9279 Adjust an expression I forgot from earlier code review 2013-04-25 11:34:22 -07:00
Herman Venter 1bf6c5d588 Keep the hphpd alive and responsive after the run command.
When debugging a script using a local VM (i.e. when there is no remote VM),
the cleanup actions performed by the run command caused the debugger client
to shut down as well. Since this seems to be intentional, processing of the
run command now restarts the debugger client and proxy. Also, following a
ctrl-C, the m_lastLocFilter field must be cleared, otherwise an empty endless
loop cannot be broken into for a second time.
2013-04-25 11:34:21 -07:00
Edwin Smith f29ee5314d Remove String::operator const char*().
Too many ways to shoot self in foot with this gem.
2013-04-25 11:34:21 -07:00
Paul Tarjan 991fef8842 import zend standard tests
Lots of the win32 ones work for creating but not removing.
2013-04-25 11:34:20 -07:00
Paul Tarjan 7bf0846868 fix flakey gztests
I noticed on one of my diffs that one of these tests failed and I think it is because they were all sharing a file.
2013-04-25 11:34:12 -07:00
Paul Tarjan 650171dc17 factor out a function
I meant to do this when I wrote it. Less scope leakage.
2013-04-25 00:50:12 -07:00
Mike Magruder 0e88603b5d Merge DebuggerProxyVM into DebuggerProxy, InterruptSiteVM into InterruptSite
The separation between these classes was a vestige of days gone by. Combined them. I ran into issue with having the proxy split up in particular when working on stepping, so doing this now as a separate diff to keep things cleaner.
2013-04-25 00:50:12 -07:00
Mike Magruder 7a928e7689 Consolidate client/server functions in debugger commands
Cleaned up some of the superfluous variations of onServer*()/onClient*() in the debugger commands. The separation was a leftover of the days when we had the VM and the compiler. The entire DebuggerCommand interface, what's public/protected/private, etc. could use a serious cleanup, but I'm not going that far now. I mostly wanted to clean this up to make some other work we need to do server-side less complicated.
2013-04-25 00:50:12 -07:00
Jordan DeLong cb57a50c01 Allow temporary ExtraData objects in instruction generation
Brett said the inability to pass temporaries here made him
not a huge fan of extra data, so this adds that.  Also simplifies the
int,SSATmp** case a bit by packaging them into a pair (this makes it a
bit less subtle to understand why go2 terminates, which was going to
get way more complicated after Tail becomes Tail&& if I wanted to keep
it that way, so I didn't).
2013-04-25 00:50:12 -07:00
Jordan DeLong ca902ff1e8 Fix an updateTrackedEffects bug for InterpOne
InterpOne was not properly tracking its effects on the stack
offset.  The return-type-means-an-extra-push thing was compensated for
in both hhbctranslator and tracebuilder.
2013-04-25 00:50:11 -07:00
Paul Tarjan a4fc1c7bbd import zend spl tests
Lots of these tests spewed files
2013-04-25 00:50:11 -07:00
Sara Golemon dd8d33fc7f Silence undefined property error when functions are defined without flags 2013-04-25 00:50:04 -07:00
Owen Yamauchi 781359b60d Rewrite gen_ext_hhvm and gen_infotabs in C++
This is a near-straight translation of gen_ext_hhvm.php into C++. The
main goal of this change is to break the bootstrap cycle in the build
process: we have to run PHP scripts to build our PHP interpreter. This
isn't so bad for us internally, but in the open-source build, it's
philosophically lame to depend on an external PHP interpreter (i.e.
Zend) to build HHVM. To get around this, we have to check in the
generated ext_hhvm files: no good.

There's nothing particularly sophisticated in this program; it's just a
bunch of grunt work. I took the opportunity to make a few improvements
to the generated code -- there was some int-width confusion, and a bunch of
duplicated code to transfer return values to the right place.
2013-04-25 00:50:04 -07:00
Paul Tarjan 8cf864ef14 import zend pdo_sqlite tests 2013-04-25 00:50:04 -07:00
Paul Tarjan 49b97d2aad import zend pdo_mysql tests
I did some minor surgery to the import script to always copy in the php files. This is because zend has ##config.phpt## files which, as their name doens't reveal, aren't really tests but instead are config files.

After all that, the tests still didn't work because I'm not running mysql on localhost.
2013-04-25 00:50:03 -07:00
Paul Tarjan 61b57050a4 import zend mysql tests 2013-04-25 00:50:03 -07:00
Paul Tarjan 42ad0071ab import zend xmlwriter tests
a few spews
2013-04-25 00:50:03 -07:00
Paul Tarjan ef61c8dd30 import zend sqlite3 tests 2013-04-25 00:50:03 -07:00
Paul Tarjan c7466541f8 import zend pgsql tests
We don't pass a single one because of

  Undefined function: pg_connect
2013-04-25 00:50:02 -07:00
Paul Tarjan a9861a4c53 read tests from stdin
Sadly when I do the full zend import the command line gets too big.
2013-04-25 00:50:02 -07:00
Paul Tarjan ab4929477c fully quality paths
I was pretty inconsistent in here. It is better to be explicit.

To keep myself honest, I did:

  rm -r test/zend; tools/import_zend_test.py -z /tmp/php-5.4.13/

Of the changed files:

* type_hinting_005a.php was missed in the original import
* closure_033.php someone changed by hand before
* date and posix tests now pass magically
* bug43703 too

The rest are whitespace updates
2013-04-25 00:50:02 -07:00
Paul Tarjan 7d3eb74b6a print out hphp command too 2013-04-25 00:50:02 -07:00
Paul Tarjan 2589e072fb mark 3 tests as segfaulting 2013-04-25 00:50:01 -07:00
Keith Adams 98483c74d6 Lift a lot of stuff out of HPHP::VM.
This is a partial step towards merging the HPHP::VM namespace
up into its parent. To keep it reviewable/mergeable I'm not doing
everything at once here, but most of the code I've touched seems
improved. I've drawn an invisible line around the jit, Unit and
its cohort (Class, Func, PreClass, etc.); we'll get back to them
soon.
2013-04-25 00:50:01 -07:00
Sara Golemon d5ea8ff20f Add PHP 5.5's array_column() function
http://wiki.php.net/rfc/array_column
2013-04-25 00:50:00 -07:00
Sara Golemon 182995353f Fix varios ext/hash algorithms
Added sha224 algo (derivative of sha256)
Added fnv132, fnv1a32, fnv164, fnv1a64 algos
Fixed tiger* finalization (endianess was backwards)

I fixed the endianness of tiger*,* and added Zend's
unit tests, but I forgot to update these tests.
2013-04-25 00:50:00 -07:00
Owen Yamauchi 05b6e5be7d Rename lexer source and add generator rule 2013-04-25 00:50:00 -07:00
Mike Magruder a41a8a74f0 Remove the Jump command from hphpd.
Hphpd's Jump command has been fundamentally broken for a long time. It was originally implemented to run the byte code in a modified way which didn't make state changes, and wait for the destination offset to be reached. We lost the ability to do that long ago, and the implementation of this command has atrophied since. As it stands now, if you're lucky it might act like "run until", which is the opposite of what it is documented to do.

I've removed the command entirely. Fixing it is a very large effort which we might consider some time in the future.
2013-04-25 00:49:59 -07:00
Paul Tarjan 2980d466f2 import zend zlib tests 2013-04-25 00:49:59 -07:00
Paul Tarjan 5646a4ee78 import zend posix tests 2013-04-25 00:49:59 -07:00
Paul Tarjan c3901f775f import zend xmlreader tests 2013-04-25 00:49:59 -07:00
Paul Tarjan fd1c19c741 import zend soap tests 2013-04-25 00:49:58 -07:00
Erling Ellingsen 48e0cf8479 Don't send URL in redirect body
If you put a CR in the redirect URL, the response splitting protection refuses to send the Location header, and the body is rendered in the browser; instant xss. It would not surprise me if some browsers ignore the Location header for less obviously broken URLs, so let's just remove the URL entirely.
2013-04-25 00:49:58 -07:00
Paul Tarjan 51807939d1 import zend xml tests 2013-04-25 00:49:58 -07:00
Paul Tarjan bd5e0b1f7b import zend simplexml tests 2013-04-25 00:49:58 -07:00
Paul Tarjan 82cc511666 import zend session tests 2013-04-25 00:49:57 -07:00
Paul Tarjan 155a38ea1d import zend sockets tests 2013-04-25 00:49:57 -07:00
Paul Tarjan acf7de7e64 import zend mcrypt tests 2013-04-25 00:49:57 -07:00
Paul Tarjan f5ef2a06f0 import zend mbstring tests 2013-04-25 00:49:57 -07:00
Paul Tarjan 648d190d9a import zend ldap tests 2013-04-25 00:49:56 -07:00
Paul Tarjan 99310da27c import zend openssl tests 2013-04-25 00:49:56 -07:00
Paul Tarjan 70befd44fb import zend intl tests 2013-04-25 00:49:56 -07:00
Paul Tarjan cb0fea957d import zend gd tests
They didn't create any extra files so it was straightforward
2013-04-25 00:49:56 -07:00
Paul Tarjan f5f8d4ec40 import zend exif tests
It seems we emit an error on unknown file and they don't.
2013-04-25 00:49:56 -07:00
Jordan DeLong 158d32fab5 Make cseKill tolerate temps from non-cseable instructions
If you have a killsSources instruction where one of the
sources comes from a non-CSEable instruction that has extra data, this
currently aborts because it tries to call hash() for the extra data
but can't.
2013-04-25 00:49:55 -07:00
Mark Williams a2981eaf25 Embed systemlib.php into hhvm
Also, since its always present, remove the special case
code for adding systemlib to a RepoAuthoritative repo,
and clean up all the magic variables for finding systemlib.

If HHVM_SYSTEMLIB is set, and the file exists, it will be
used as systemlib, otherwise, the embedded one will be used.
2013-04-25 00:49:50 -07:00
Jordan DeLong c39252e9f9 Determine hphp_home in test/run via __DIR__
The system() here was echoing to stdout.
2013-04-24 22:32:36 -07:00
Sean Cannella 54efa29d5f Fix off-by-one in multi-line function call traces
Fixes off-by-one in line number reporting in multi-line function calls
2013-04-24 22:32:36 -07:00
Paul Tarjan 3f880f93e2 fix bz2 race
Since we run these in parallel then there is a bad ordering of these where they eat eachother's files.
2013-04-24 22:32:28 -07:00
Mark Williams 3e75f5b7e4 Fix issue with Unit::merge
A recently introduced bug could cause classes and
interfaces to be silently dropped in repo-authoritative mode.
2013-04-24 17:13:58 -07:00
Mark Williams d0e1d78cd5 Implement Cns in hhir
Thats it
2013-04-24 17:13:58 -07:00
Sean Cannella 87f9e8cd1c add mod_apache_log %I support to HHVM webserver
- added support for %I (bytes received / request size with headers) in HHVM access logs
2013-04-24 17:13:58 -07:00
Herman Venter 1d6efdcbb4 Rename DebuggerProxy::send, DebuggerClient::send and DebuggerClient::recv
I found myself getting confused, thinking that proxy->send(cmd) sends a command to the proxy, when in fact it causes the proxy to send the command to the client. These are now named sendToClient, sendToServer and recvFromServer so that future readers (including my future self) will not make this mistake again.
2013-04-24 17:13:58 -07:00
Paul Tarjan ede4f96d4e fix pcre whitespace 2013-04-24 17:13:54 -07:00
Mark Williams 0526e973c5 Fix literal string to int/double conversion under hhir
The simplifier would convert strictly-integer strings to their
integer equivalent, and all other strings to zero. This meant
that eg "1.1" became zero, as did "1x". Normally, such strings
are converted at the ast level, so it was hard to expose the bug,
but eg test/quick/cnvInt.php would fail if you turned off
JitEnableRenameFunctions (and its turned off in repo mode, so the
repo mode test was failing).

The same issue was present in ConvStrToDbl, but there was a bug in
StringData::isNumeric causing it to return true for a weakly-numeric string,
where its contract is to return false (and it did return false for an
equivalent, non-static string). Once I fixed that bug, I had to fix the
bug in ConvStrToDbl.
2013-04-24 12:42:45 -07:00
Paul Tarjan e0b5db348a import zend pdo tests 2013-04-24 12:42:45 -07:00
Paul Tarjan 71113aef61 import zend pcre tests 2013-04-24 12:42:44 -07:00
Paul Tarjan 4710a5538a import zend pcntl tests 2013-04-24 12:42:44 -07:00
Paul Tarjan 042ea354d0 import zend imap tests 2013-04-24 12:42:44 -07:00
Edwin Smith f0394e1d0d Lint fixes for type_array.h
Just tackling one file at a time.
2013-04-23 12:59:00 -07:00
Paul Tarjan 8d15db5860 import zend libxml tests
only 1 good test? *sigh*
2013-04-23 12:58:59 -07:00
Paul Tarjan 44e8962b85 import zend json tests 2013-04-23 12:58:59 -07:00
Paul Tarjan f9b83dc6af import zend iconv tests 2013-04-23 12:58:59 -07:00
Paul Tarjan dba18c78ed mark oci8 unsupported
these tests require an oracle server be set-up? That's pretty rough... We'll tackle these later when they become the lowest hanging fruit.
2013-04-23 12:58:59 -07:00
Paul Tarjan ad74e1f391 import zend hash tests
not bad. >50%
2013-04-23 12:58:59 -07:00
Paul Tarjan 306686be70 No need to support opcache for test parity 2013-04-23 12:58:15 -07:00
smith c646a30002 Litstr must die, episode III.
Many callsites of Array.set(litstr, ...)
2013-04-23 12:57:40 -07:00
Herman Venter 71a6e2b628 Add TRACE calls to debugger code.
Added a new trace flag and added TRACE calls to all functions in files living directly in the hphp/runtime/eval/debugger directory
2013-04-23 09:52:58 -07:00
Jordan DeLong 094a729549 Kneecap an ext_spl test that had too many filesystem things going on
It was failing intermittently in contbuild and in different
fbcode checkouts.
2013-04-23 09:52:58 -07:00
Jordan DeLong 469afe85d9 Remove old HHVM_GC code
This was left over from GC-related experiments, and isn't
needed now.
2013-04-23 09:52:58 -07:00
smith 46f11e95d0 Remove bool key overloads from Array smart pointer
They were dead code.  Removed weakRemove() methods, also dead code.
More importantly, foo("something") binds to foo(bool) if there
is no foo(litstr), so this avoids accidentally calling the wrong
overload as I'm ripping out litstr overloads.
2013-04-23 09:52:58 -07:00
smith 37e49ba6e4 Remove dead ConnectionInit class
thats it
2013-04-23 09:52:57 -07:00
Mike Magruder ac9665e148 Remove old vestiges of frame injection.
Nuke a little dead code that is leftovers of the old frame injection goo.
2013-04-23 09:52:57 -07:00
Paul Tarjan 017b6f231b spill the inputs of CreateCl onto the stack
I did this for the IR but didn't do it for the JIT :(
2013-04-23 09:52:57 -07:00
Mike Magruder 76db66ec82 Add comments to some of the debugger code to aid in understanding it more clearly, plus minor code cleanup.
Add a lot of comments to the debugger based on my current understanding of it. These may change in the future as we learn more, but they're helpful right now.

Also moved a few small things around in the code to clarify their purpose or scope. I.e., making a few things private, renaming a few functions, etc. No real logic changes, though. Also minor dead code removal. Also a few lint errors.
2013-04-23 09:52:57 -07:00
Mark Williams 9a8b0d3ba4 Respect ignoreRedefinition in repo mode
In repo mode, we kept the builtin. Keep the user function
instead.
2013-04-23 09:52:57 -07:00
Mark Williams b8c78a9141 Get rid of some hphpiCompat brokenness
These were strictly to avoid people writing code that
worked under hhvm, but then fataled under hphpi. Since hphpi is
long gone, its time we removed it (no danger of breaking real code
since anything that worked before continues to work - and hphp
was already "doing the right thing" because it flattened traits).
2013-04-22 14:43:52 -07:00
Mark Williams a2e46efe38 Make sure we raise a warning in repo mode
Repo mode can skip undefined variable warnings,
if they're known to be uninit at compile time, and eliminate
expressions whose only side effect might be to raise a
diagnostic.
2013-04-22 14:43:52 -07:00
bsimmers fa0a201dde Revert "name anonymous continuations as Class::Method$continuation" 2013-04-22 14:43:52 -07:00
Mark Williams e0995af8dc Turn off optimizations in repo mode for some tests
They don't seem worth fixing.
2013-04-22 14:43:52 -07:00
mwilliams 0a70a77f42 Fix an issue with exit/include/etc
Various unary operators have arbitrary effects. Dont assume we
know anything about locals when we see one.

Fix an expect for differences in line numbers.

Prevent a use of an undefined constant from being optimized away.
2013-04-22 14:43:51 -07:00
Paul Tarjan eca135cb31 delete most PHP in C++
Sadly I can't get TestDebugger, TestServer, TestExt, QuickTests, or TestPerformance as they are all unsuported by verify. Someday.
2013-04-22 14:43:51 -07:00
Paul Tarjan 53d1db1669 revert over-zealous simplification
I was trying to simplify code flow by removing things with tainted variables. I got too carried away and thought tainted wait handles were the same.
goodcatch
@override-unit-failures
2013-04-22 14:43:51 -07:00
Jan Oravec e42d42d35e Rename AsioContext members to be camelCase
All m_* object members in ext_asio are camelCase, except in AsioContext.
Rename them. Also, m_queue_ready became m_runnableQueue, as with the
introduction of async functions a new abstract RunnableWaitHandle will
be introduced.
2013-04-22 14:43:51 -07:00
Jordan DeLong f650635e0b Define __STDC_FORMAT_MACROS in build configuration
Avoids some header order dependencies.
2013-04-22 14:43:51 -07:00
Jordan DeLong a70b1bf8f7 Ad few more lint fixes under runtime/vm/translator 2013-04-22 14:43:50 -07:00
Jordan DeLong 80dece2b6b Fix a (smart heap) leak in Variant's move constructor @override-unit-failures
When unboxing a ref, the Variant move constructor is leaking
the RefData.
2013-04-22 14:43:50 -07:00
Jordan DeLong a2df3fcf9a Fix lint errors about catching exceptions by value 2013-04-22 14:43:50 -07:00
Jordan DeLong e287f5e5ff Fix some mismatched include guards 2013-04-22 14:43:50 -07:00
Jordan DeLong 7449c3afea Remove util/lfu_table.h
This is unused.
2013-04-22 14:43:50 -07:00
Jordan DeLong 3af00dc1b1 Fix various lint warnings stemming from hphp/util 2013-04-22 14:43:49 -07:00
Jordan DeLong 24cb23f21b More fixing lint: various conversion constructors in compiler/
Left one implicit, but it's arguable.  Inspected manually.
2013-04-22 14:43:49 -07:00
Jordan DeLong 3db2140e3e Fix some cpplint errors about illegal symbols
Various perling.
2013-04-22 14:43:49 -07:00
Edwin Smith 22d70113c7 hphp/src is now hphp/hphp
That's it
2013-04-22 14:43:48 -07:00
Jordan DeLong 04f4f27eba Fix stack offset tracking in emitPrint, caught by zend test
The emitPrint function failed to pop the cell when it decided
to nop out the print.  This led to the stack being off by one when we
got to the RetC in this test.
2013-04-22 14:43:48 -07:00
Mark Williams 2a759db5e6 Fix reflection for default values that were optimized
If a default value is optimized from a class constant,
to the value of the class constant, then reflection needs to
be able to get the text of the original class constant.
Fortunately hphp tags that onto the replacement expression for
just this reason. Lets use it in the emitter.
2013-04-22 14:43:48 -07:00
Mark Williams b28254c8f2 Fix a crash if an exception is thrown in a constructor's surprise check
The unwinder assumed that if the actrec's constructor flag
was set, then there must be a $this. But the $this is cleared during
the return sequence.
2013-04-22 14:43:48 -07:00
mwilliams fb214b9655 Better dynamic constant support in repo mode
A constant defined in a function/method should be treated as
dynamic.
A class constant with a dynamic initializer should evaluate to
the value of its initializer at the time the constant was first
seen; so the optimization should be all or nothing - either
turn the class constant into a scalar, or leave it in its original
form.
2013-04-22 14:43:48 -07:00
Paul Tarjan 91db25c8e1 use run_test_other.sh for 5 C++ test suites
This will make things less error prone. If we fork early in the makefile instead of sharing some infra then changes to the PHP-based test infra won't break c++ tests.

While I was there, I tried to fix the weird order that some tests had
the suite first and some had the set first. It got hard since D773384 hasn't
landed yet. When we do that, then I'll cleanup that stuff.
2013-04-22 14:43:47 -07:00
Paul Tarjan 72dffc0aef kill TestPerformance
deadcode
I think perflab is a better tool
@override-unit-failures
2013-04-22 14:43:47 -07:00
ptarjan 387369de96 import random crap zend files
Many zend tests require files which aren't in their .phpt files. We need these extraneous files if we want these tests to pass.

Zend isn't nearly as clean as I would hope. Here is how I did it:

* Move EVERYTHING from the directories to test/zend/all
* run the tests thre with all the random crapy files
* move things in the whitelist to good
* move everything else to bad

@override-unit-failures
2013-04-22 14:43:47 -07:00
Paul Tarjan 25b842d845 fix 3 zend tests for whitespace problems
Rebase ate my whitespace :(

I added mutliple ##-o## support to easily support fixing some tests like this:

  ./tools/import_zend_test.py -z /tmp/php-5.4.13/ -o ctype_space_variation1.php -o ctype_xdigit_variation4.php -o bug33957.php
2013-04-22 14:43:47 -07:00
Sara Golemon 82489e1fd1 Make generators always-enabled
Zend supports generators now, so it's not
really HipHop specific syntax anymore
2013-04-22 14:43:46 -07:00
Jordan DeLong 347aad68c8 Add a few things to hphp/test/.gitignore 2013-04-22 14:43:46 -07:00
Owen Yamauchi bc47e4aa91 Rebuild parser, move test into test/slow
@override-unit-failures

D774978 was checked in with a broken test. New tests go in test/slow
now. The test was broken because @drussi apparently didn't rebuild the
parser after his last diff update (changing 's' to 't').
2013-04-22 14:43:46 -07:00
Paul Tarjan 6f932592ea fix some lint
I tried to remove the namespace thing but that rabbit hole went too deep. When I hit ##OPCODES## I stopped.
2013-04-22 14:43:35 -07:00
Paul Tarjan 5decac3716 add zend shortcut
This should be here for completeness. And so @jdelong can easily fix them :)
2013-04-22 14:43:35 -07:00
Paul Tarjan be05d0d87a style changes
I'll do the nitpicks, sorry @jdelong.
2013-04-22 14:43:21 -07:00
Mark Williams 983a59a000 Add hphp_opts file for types
fixes test/quick/parse_type_not_typedef.php
2013-04-22 14:18:05 -07:00
Mark Williams 29ff6382e2 Prevent an equality check from being optimized away
We were depending on a side effect of the string conversion
2013-04-22 14:18:05 -07:00
Mark Williams 0b7e8d1251 Check accessibility before replacing static props with their value
If a static property is provably not modified, and it has
a literal initializer, it is optimized away at translation time.
We should check that its accessible before doing that.
2013-04-22 14:18:05 -07:00
Mark Williams 2294a515f6 Fix poly-torture to avoid order of eval issues
Normally, hhvm will translate

  echo "x $x";

as

  echo "x ".$x;

Which fully evaluates the rhs, then starts to output it.

hphp will transform it to

  echo "x ", $x;

Which avoids the concat, but outputs "x " before evaluating $x. hphp wont
perform the transformation if there are obvious side effects, but it will
treat a simple variable as having no side effects - even though it may
be uninitialized.

Im just fixing the test by performing the transformation manually. I don't
think anyone cares whether the $x undefined notice appears before or after
the "x ".
2013-04-22 14:18:05 -07:00
Owen Yamauchi 008387c504 Minor tweaks to the IDL
While rewriting gen_ext_hhvm in C++ I discovered these little
anomalies: the "return" field of a function has to exist, and has to be
a dictionary.

I'm also removing the specific class name of hphp_create_continuation as
per the discussion, and removing the support for parsing
types like that.
2013-04-19 22:53:58 -07:00
Jordan DeLong f3c2ab5d77 Fix runtests to make it workable for contbuild
It wasn't actually decoding test names anymore due to paths
changing; also several slow tests failed when run from the root (which
is where contbuild is going to run them).  Added stuff to make
$HPHP_HOME unnecessary for runtests (contbuild wont have it set), and
fixed a use of $GLOBALS in hphp/test/run to be more php-idiomatic.
2013-04-19 22:53:31 -07:00
ptarjan 4c77061e3f import curl tests
Not very good coverage here, but @sgolemon predicted that.
2013-04-19 17:13:24 -07:00
Mark Williams 39df1a8b20 Free the VarEnv the correct way
detach, rather than destroy.
2013-04-19 17:13:23 -07:00
Mark Williams a988bdb73e Fix a couple of include tests in repo mode
One just needed to have the file included in the repo.
One was getting the wrong return value (true vs 1).
2013-04-19 17:13:23 -07:00
ptarjan a4334f1870 import ext-date tests
We aren't doing so well on these. Some are ##false## vs ##NULL## but others are ##DateInterval## which sucks to not have.
2013-04-19 16:42:20 -07:00
ptarjan 3932003411 import ctype tests
All pass, yay.
2013-04-19 16:42:12 -07:00
ptarjan b719d1947d blacklist all zend tests
Instead of having to remember which -o params to pass, I'll just put everything as blacklisted that we havn't import.
2013-04-19 16:42:02 -07:00
ptarjan 70a6d9cde9 import bz2 tests
I had to edit ##bzopen## so that it handles file handles or else the test makes files called ##Resource #5## in the current directory.

The big problem with the broken tests is we return ##NULL## on too few args and Zend returns ##false##. I want to get a feel for other extensions before changing this.

I also imported ALL the files in the directory since the ##.phpt## files overflow.
2013-04-19 16:41:53 -07:00
ptarjan fb9b8c1552 support 2 more sections
Support two more section keys and only print the message when using /all
2013-04-19 16:41:46 -07:00
Mark Williams 95251c59cf Fix fbcufa.php in repo mode
just need to ensure its found at compile time
2013-04-19 16:41:41 -07:00
ptarjan e36e75fa5f remove duplicate tests
I imported these with my old zend importer. Now that we have zend/good, these are duplicated.

There are 3 zend tests left:

* zend_closure_005.php
* zend_closure_020.php
* zend_indirect_method_call_005.php

Which we've hand-edited to be similar to zend but not exactly the same. I'm going to leave them for now.
2013-04-19 16:41:29 -07:00
ptarjan 0edeb118db fix zend importer
I broke this during the test refactor. And now a few more tests pass, yay.
2013-04-19 16:41:12 -07:00
jdelong 4be0858c63 Add 'convenience' name aliases to test/run
This was the main feature in my wrapper script.  Allows
running tests by more terse names.
2013-04-19 12:21:56 -07:00
mwilliams 6f223125a5 Prevent more optimizations in repo mode
"$unused_local = UndefinedConstant;" was being optimized away, so
we didnt get a warning for the constant. return it instead.

  $unused_local = new Object;
  return;

became

  new Object;
  return;

This affected the (unspecified) order of destruction of $this
vs $unused_local. Since we're specifically trying to test that
we dont crash when a local generates a backtrace after $this
has been destroyed, force the variable to be used.
2013-04-19 12:21:56 -07:00
mwilliams ad30d03b8c Fix order of evaluation for unused binary operators
eg

  (new X) == (new X);

Was converted to something like:

  (new X);
  (new X);

Which calls the destructor for the first X before constructing the second.

I tried a fix where we used an ExpressionList with ListKindLeft, which
would preserve both expressions until after both objects are created;
but that ends up calling the second object's destructor first. Thats
much better; its not clear to me that there's any guarantee about which
object's destructor is called first when they both go out of scope at
the same point; but currently hhvm and zend seem to aggree, so Im
going with a solution that preserves the left-to-right order.
2013-04-19 12:21:55 -07:00
aravind 2137af76be Fix bug in shuffleArgs
This diff fixes a bug in shuffleArgs when there
are three register arguments in a cycle, and one
of them needs a zero extend.

Assume the shuffle that needs to be performed is
rdi -> rsi, rsi -> rdx, rdx -> rdi. doRegMoves()
determines the sequence of moves to be:

  xchg rdx, rsi
  xchg rsi, rdi

Assume also that the second dest reg (rsi) needs a zero extend.
The current implementatin will spit out the code
sequence:

  xchg   %rdx, %rsi
  movzbl %sil, %esi
  xchg   %rsi, %rdi
  movzbl %sil, $esi

Basically, the problem is that if a move sequence uses
two xchg's for a cycle of three registers, we should not perform
the zero extending (and address-lea) till both the exchanges are done.
2013-04-19 12:21:55 -07:00
mwilliams 0f9e81197b Prevent some repo mode optimizations
Since its seen the whole program, it optimizes class_exists
to false if there's no definition anywhere.
Replace local variables with globals so that assignments can't
be optimized away (since we're gathering coverage information).
2013-04-19 12:21:55 -07:00
aravind 97766b0367 fix for ConvToString
When we do CastString on an object, the ConvObjToStr helper
may throw if it does not have a __toString() function.
When spilling the stack before calling the helper,
we must push back the popped object.

Also convObjToString helper should not decref its object if the conversion failed.
2013-04-19 12:21:55 -07:00
drussi 6e8178da16 expose type annotation to reflection including generics, function types and tuples
This is intended so reflection can be used (via getTypehintText and getReturnTypehintText) to regenerate code the user annotated with types. Essentially using reflection to intrispect code in order to generate type safe
(hack safe) code. That is particularly important for the tools that do dependency injection. The runtime should be oblivious to the change as the rich type annotation is currently only stored for the sake of reflection. For
functions the values are in the shared portion which is cold and should also take care of traits.
2013-04-19 12:21:55 -07:00
mwilliams bdddf9f01d Arrays as class constants should be a parse time fatal
We were detecting this in the emitter, which is too
late, because the definition could be optimized out by then
2013-04-19 12:21:55 -07:00
jdelong cbbc3a4906 Make $HPHP_HOME optional for hphp/test/run, change default bin_root()
If it's not set, let's just use git rev-parse.  If you don't
have FBMAKE_BIN_ROOT in your env, use _bin/ by default (for the last
thing you built) instead of <root>/bin/, which is only around for
perflab compat.  Made the help a little more to my liking (and not
ruin syntax highlighting in emacs).
2013-04-19 12:21:55 -07:00
ptarjan cabe5aa8e7 escape glob
The current dir might have ##php## files in it.
2013-04-19 12:21:55 -07:00
ptarjan a8fa0afffc kill dead param
I'm digging in here, and saw relative is always false.
2013-04-19 12:21:55 -07:00
Owen Yamauchi 34fdda13e1 Convert the IDL to JSON
It's data, not code.

My primary motivation for doing this is to make the IDL accessible from
languages that aren't PHP. (This, in turn, is motivated by a desire to
eliminate PHP scripts from the build process.)
2013-04-18 16:44:16 -07:00
bsimmers 5d1c69b048 Revert Generator changes 2013-04-18 14:24:56 -07:00
ptarjan 04cc89a235 Remove one level of indirecation
Instead of the python script calling the php script which calls the perl script, now the python script returns a command to run.

I was thinking about chaging the jenkins output to mention the php script intead of the makefile target, but sadly there are a few things that aren't scripts and are just makefile targets so it was too much work and I just stopped here.
2013-04-18 13:55:38 -07:00
hermanv 5e6cce4db5 Conversions in IR
Rolls up all previous diffs into a single diff and uses the CALL_OPCODE macro.
2013-04-18 13:55:38 -07:00
mwilliams c68de03df2 Don't fold invalid string operations at compile time
It turns out the String::rvalAt and String::set don't raise
warnings on invalid offsets, so check explicitly before using them.
2013-04-18 13:55:38 -07:00
bsimmers d94be65db1 Disable test/quick/serialize.php 2013-04-18 13:55:38 -07:00
bertrand 6a93844442 Add support for safe (un)serialization using (un)serialize()
The unserialization of random objects may be dangerous because the destructor of the object will be called when the unserialized objects are out of scope. However, the person who wrote the class may not be aware of the danger of unserialization. Therefore, we would like to require every users of the unserialize() to provide a whitelist of the class names that are authorized to be unserialized so that we can make sure the object is safe to be unserialized.

Add a parameter 'class_whitelist' to unserialize() function to determine whether to raise warnings for unsafe unserialization. If the class to be unserialized is not an instance of Serilizable or not in the whitelist, warnings will be raised. For the detailed reason why we need this, please see http://fburl.com/SafeSerializable for more information.

Add a parameter 'all_classes_enabled' to allow  those hphp functions that need to unserialize any class. For example, fb_call_user_func_async() will need to serialize and nserialize the given parameters.
2013-04-18 13:54:55 -07:00
ptarjan 2e5d5fbb15 fix SlowRepo tests
Yay, back to the glory days of having repo tests.

The problem was that we weren't being smart about ##__DIR__.'/some/string'## during the compile step. Now we are.
2013-04-18 12:19:35 -07:00
ptarjan b6f60e2f2c fix runtests 2013-04-18 12:19:35 -07:00
aravind 1fddbbebc9 Cleanup for debugging IR under gdb
update block range on each IR instruction
add CodeGenerator::print()
2013-04-18 12:19:35 -07:00
jdelong 74202fab80 Remove drawCFG and tcdump trace module
We have tc-print now, and I don't think people use this
anymore.
2013-04-18 12:19:35 -07:00
mwilliams d39bf0bcfe Method names should not be coerced to string
Zend fatals if the type is not string, where hphp would
coerce to string. In RepoAuthoritative mode, this meant that
scalar expressions would be converted to strings at bytecode
emission time, bypassing the fatal (or, in most cases, resulting
in a different fatal).
2013-04-18 12:19:35 -07:00
mwilliams 6df0912bc0 Get rid of baseStrOff
It was unnecessary book keeping, and caused us to differ
from zend's behavior
2013-04-18 12:19:35 -07:00
ptarjan 6eef35d561 nicer message on failure
smith asked for this. Prints out the exact options to run it by hand. If it is in repo mode, it uses the already built repo. Otherwise it just runs the file. If you are only running 1 test, it does the FILENAME sustitution for you. I thought it would get pretty ugly if I printed out that line for every test.
2013-04-18 12:19:06 -07:00
smith 89f5f70e42 Litstr must die, episode II. 2013-04-18 12:19:06 -07:00
jdelong 89e34e12e6 Disable memelim
It's causing issues with the vector translator.
2013-04-18 12:19:06 -07:00
ptarjan 61973ed25c fix 1798 output
It seems calling ##fileinfo->getFilename()## twice outputs the empty string the second time. Document that in the test for now and look at it later.
2013-04-18 12:19:06 -07:00
ptarjan a974f84f15 try to fix machine dependant problems again
I think these are dependant on relative directories. Seeing if this helps.
2013-04-18 12:19:06 -07:00
jdelong 2e3445bf38 Add a tvIsPlausible assertion in vectortranslator @override-unit-failures
We were hitting an assertion due to a type error in a vector
translation far downstream.  Assert up here to keep it closer to the
TC.
2013-04-18 12:19:06 -07:00
mwilliams c203d5a772 Dont box by-reference params that would warn/fatal
If we know at emission time that an argument is by reference, we box
it, and use FPassV with a NopOut meta tag. But that bypasses the
mechanism for warning/fataling when passing a Cell. So skip the
optimization in those cases.

Fixes two more QuickRepo tests:
test/quick/FPassC-2.php
test/quick/FPassC.php
2013-04-18 12:19:06 -07:00
mwilliams 27b4b0b53c Don't profile 86ctor
Its an implementation detail, and we may or may not end up
calling it.
2013-04-18 12:19:05 -07:00
mwilliams 5f9df0e7c6 Rework constants to use the target cache exclusively
Make the targetcache the one true home for constants,
so we dont need to (also) insert them all into
VMExecutionContext::m_constants (which is now gone).

By also making "non-volatile" constants persistent, we save
initializing most of them at all in RepoAuthoritative mode.
2013-04-18 12:19:05 -07:00
smith 98466ea3fd Litstr must die, episode I.
Converted lots of callsites to StaticString, removed a few
dead overloaded litstr functions.
2013-04-17 10:12:48 -07:00
Paul Saab 1097d2dcb5 Count active threads in PageletServer
We were not counting the active running threads in PageletServer
which made /check-pl-load on the admin port return zero always.
2013-04-17 10:12:48 -07:00
jdelong ee3628c272 Relax an assert slightly after the change to unbox keys in-TC 2013-04-17 10:12:48 -07:00
jdelong 17344c4b5a Don't spillStack as much for CGetM
I forgot to test wantPropSpecializedWarnings for simple
CGetMs that don't have an hphpc-infered type.
2013-04-17 10:12:48 -07:00
bsimmers be6394b828 Disable HhbcTranslator::emitMod 2013-04-17 10:12:47 -07:00
mikemag 17731f2252 Let destructors run after main for Zend tests.
Added EnableObjDestructCall=true to the config for zend tests.
2013-04-17 10:12:47 -07:00
mwilliams b5f81ab942 Constant propagation was too aggressive
it assumed that $a = 5; echo $a; would echo 5, which isn't
true if $a is the last reference to an object whose destructor
can get hold of $a.
2013-04-17 10:12:47 -07:00
ptarjan 6e899255c6 move .php files to .inc in test/quick that aren't tests
Instead of having a blacklist on name, how about we use a different file extension for included files? Many PHP installs do this for files that are in the document root but shouldn't be served.
@override-unit-failures
2013-04-17 10:12:47 -07:00
bsimmers 4fd5886617 Unbox vector helper keys in translated code
Instead of creating a template specialization of each helper
that unboxes the key, do the unboxing in the TC when applicable. This
will shift a few instructions from helpers to the TC but greatly
reduces the number of helpers needed by the vector translator.
2013-04-17 10:12:47 -07:00
bsimmers 6b552c7e77 Don't type-specialize helpers for uncommon vector operations
Many of these helpers are fairly infrequently called so it
doesn't make sense to have a different version of each one for the
different key types. This will slightly increase instructions but
should help icache performance.
2013-04-17 10:12:46 -07:00
mwilliams d8f5055660 Fix Repo config settings for test/quick
Also clean up some cruft in test/config.hdf
2013-04-17 10:12:46 -07:00
ptarjan c3699bb8e3 fix slow tests
These tests have machine dependant things in them. Copy Zend and change the machine things to %s.
@override-unit-failures
2013-04-17 10:12:46 -07:00
ptarjan 4c2b9a3bc2 rewrite test running in php
It turned out to be more lines but feels a bit more maintainable. Thoughts? I personally would like python more here but I think @kma likes php for scripting.
2013-04-17 10:12:46 -07:00
mikemag 5240dae6a9 Add a new option to control args in backtraces
Add Eval.EnableArgsInBacktraces, which defaults to !Repo.Authoritative. This allows us to test what happens when backtraces keep references to function arguments even when testing in authoritative mode. Modified the test harness to set this to true when using Repo.Authoritative.
2013-04-17 10:12:46 -07:00
bmaurer ea2b1a06ec Use bstrcaseeq in isame
bstrcaseeq is a bit less complex and should be faster for this case.
2013-04-17 10:12:45 -07:00
aravind 4d0ab6d254 Null check for colorize 2013-04-17 10:12:45 -07:00
jdelong cff9360510 Fix a bug in CreateCl, combine helper calls and use precoloring
The CreateCl translation dereferenced its targetcache handle
at compile time instead of in the TC, so we could get "class
undefined" errors if the targetcache slot in the thread that jitted it
didn't happen to have that closure defined.  Fix that, combine the two
helper calls, and use nativecalls so we get register precoloring.
2013-04-17 10:12:45 -07:00
mwilliams 4842f4ee1d Flatten fast path in GetNamedEntity
While investigating why gcc-4.7.1 is slower than gcc-4.6.2,
I noticed that under 4.6.2 the tbb code was being inlined into
Unit::GetNamedEntity, but under 4.7.1 it wasn't. Perf showed that
the inclusive time for GetNamedEntity was about .4% higher under
gcc-4.7.1.

Meanwhile, after various code changes, gcc-4.6.2 is no longer
inlining the tbb code either. Playing with the inlining options,
I wasnt able to get either version of gcc to inline it anymore,
but using __attribute__((__flatten__)) works for both. But that
also causes a bunch of other, slow-path code to be inlined, so
split it into a hot and a cold function, and flatten the hot
function.

Perf shows about a .2% win for Unit::GetNamedEntiry under gcc-4.6.2
2013-04-17 10:12:45 -07:00
smith 88f2ec2fb9 Remove ArrayData litstr overloads
Some were dead.  Refactored the rest to use the CStrRef overload
instead, while still supporting litstr in the Array, ArrayInit, and
Variant apis.
2013-04-17 10:12:44 -07:00
ptarjan db6f5f3d54 s/QuickTests/TestUnit/g
I looked at all the tests, and they seem to be unit tests for small parts of hphp.

They were run at the start of every TestExt test too, so I changed that so they are really just their own test now.
2013-04-17 10:12:39 -07:00
jdelong abc9170968 Fix typedefs/shapes for whole program optimization
Needed a few cases for KindOfTypedefStatement,
EnableExperimentalHipHopSyntax, and passing it through to the scanner.
2013-04-17 09:51:40 -07:00
mwilliams 62315ccb15 Fix crash in linting
Redeclared functions in non-whole-program analyze mode caused
an assertion failure.

Test Plan:
  % cat bug.php
  <?php
  if (isset($g)) {
    function f($x, $y) {}
  } else {
    function f($x) {}
  }
  f($x);
  % hphp -vWholeProgram=false -t analyze bug.php
2013-04-17 09:51:40 -07:00
chip fe9373358e Add function to get the async status for a mysql connection
This will allow for php code to better verify the async state
of the mysql connection and aid in debugging.  This diff adds
mysql_async_status as well as associated constants.
2013-04-17 09:51:40 -07:00
ptarjan 9db58086ac rename all the tests
After the "Great Test Refactor of 2013" these names didn't make sense.

After this diff, we now have 3 suites:

* Quick (old vm)
* Slow (old TestCodeRun)
* Zend

I like that Quick tests aren't in sub-suites and the Slow tests are. So that is a good litmus tests of what to put where.

I left all the old Makefile rules. I'll blow them up in a few weeks.

This diff is based on a simple unreviewable diff of

  $ mv test/vm test/quick
  $ mv test/tcr test/slow
2013-04-17 09:51:29 -07:00
ptarjan fca7a90240 Rename test directories
These names don't make sense now that we run both suites the same
way.
2013-04-17 09:08:16 -07:00
ptarjan 503f75d08b Rename test directories
These names don't make sense now that we run both suites the same
way.
2013-04-17 09:06:51 -07:00
ptarjan f42dbb6ddf delete repo file before trying
I've noticed that sometimes it won't rebuild the repo. Delete it just to make sure.
2013-04-17 08:55:07 -07:00
ptarjan ea27bcf156 rename /tools/run_verify.sh to /test/run
I'd like to make people use the script for running tests. With all the different options, the matrix of Makefile rules is getting pretty big. And with all the makefile magic, they aren't very discoverable what is runable.

The old name was pretty bad for tab completion. Since we have a dedicated test directory, why not put the script there? I'm not in-love with `run` but there are no other `r` files there so it is nice for tab completion.
2013-04-17 08:55:07 -07:00
ptarjan e35c2971c2 start running TCR tests with verify
I went a bit crazy and supported all the quick and zend tests in the same format. Or do you think we should normalize the other way? Or are there better names? I think if you like this, I should move the "vm" directory to "quick" and the TectCodeRun to "slow" directory or something so we put tests into nicer suites.
2013-04-17 08:54:58 -07:00
mikemag 602b1bd64f Ensure C++ exceptions eventually propagate out of destructors.
This diff addresses what we called "step 1" in the task: simply ensure that any C++ exceptions that escape a destructor get rethrown and can continue to propagate naturally. The exception is remembered on the thread, and rethrown when we check for surprises later. If multiple destructors let C++ exceptions escape the last one to escape will be the one rethrown at the next surprise check.

This also ensures that C++ exceptions prevent more PHP code from running, by omitting calls to __destruct methods as we unwind the stack.

Finally, this also enables surprise checks for OnFunctionExit unless we're unwinding, in which case surprises remain unchecked so they can propagate later.

This is different than Zend's behavior, where destructors do run as fatals unwind.
2013-04-17 08:54:58 -07:00
mikemag b677c776df Fix bug in heredoc processing
My recent change to now/heredoc processing resulted in variables in heredocs mistakenly being tacked onto the end of the previous line in the output. This tends not to be a problem when emitting things that get parsed by something else, like emitting PHP. But it's noticable when emitting raw text.
2013-04-17 08:54:58 -07:00
smith cc0ef7c456 Change copy-on-write protocol to always return valid pointers
Streamline the array access methods by always returning an array
pointer instead of a new pointer or null.  Callsites compare
(new != old) to detect escalation, rather than (new != null).
2013-04-15 13:03:16 -07:00
smith 8cd07ce9f6 Rename RuntimeType/DynLocation::isVariant() -> isRef() 2013-04-15 13:03:16 -07:00
jdelong 2ef635db28 Optional syntax-highlighted HHIR dumps
It's enabled if the HPHP_TRACE_FILE is "/dev/stdout" or
"/dev/stderr" and also isatty(), or you can set HPHP_TRACE_TTY in your
environment to override it (e.g. if you like to pass to less -R).
2013-04-15 13:03:16 -07:00
ptarjan 4bd0cdb05e Support repo mode in run_verify.sh 2013-04-15 13:03:03 -07:00
ptarjan dd36937f94 new opcode CreateCl
This is the bottleneck for closure perf. Instead of all the code in the prologue, it turned out the expensive thing about closures was constructing them. This bypasses all the roundabout copying involved with __construct and makes a new opcode to do the same thing.
2013-04-15 13:01:49 -07:00
ottoni da37a0ae8f interpOne instructions that fail the HHBC->HHIR translation
This diff adds full support for doing general interpOnes in HHIR.
Whenever a bytecode instruction fails (punts) in the HHBC->HHIR
translation, the NormalizedInstruction is marked with an 'interp' flag
and the HHIR translation for the whole tracelet is retried.  This
forces an InterpOne of such instruction, preventing HHIR from
attempting to translate it again, which then allows the HHBC->HHIR
translation to make further progress.  If another instruction in the
sequence punts again, the process is repeat and so on.
2013-04-15 13:01:49 -07:00
Owen Yamauchi b3d14bfdda ifdef out rdtsc in hotprofiler
I'm punting on this for now. I'm afraid of violating assumptions about
how the clock behind this interface works (and we do very specific stuff
like calculating CPU clock speed), so I don't want to try to replace it.
We'll revisit when we need to do serious profiling on ARM; we'll
definitely notice that this functionality is missing when we try to use
it.
2013-04-15 13:01:48 -07:00
ptarjan eb401ae91f move TestCodeRun tests from strings to files
I changed the ##run_verify.sh## script to recursivly search for a ##config.hdf## file and use that one. This allows us to easiy customize the options for each suite.

I converted the 6 different runtime options we supported to symlinks of ##.opts## files to the option that the test wants. If I was smarter I would then convert these to ##config.hdf## if the whole suite wanted the same options, but I'll save that for later cleanup if we want it.

I moved the config files around a bit. `test/cli.hdf` became the default `test/config.hdf`. `test/config.hdf` became `test/tcr/config.hdf`. `test/zend/config.hdf` is also now an empty file so it doesn't inherit `test/config.hdf`.

I'll handle the Repo part of the tests in the next diff. Then the next one after that will delete all the cpp code and Makefile targets and force you to just use ##tools/run_verify.sh## which I think we should rename ##test/run## or something easy.
2013-04-15 12:56:31 -07:00
Owen Yamauchi 743f51e107 Separate handwritten assembly helpers into a .S file
This feels like a cleaner approach. It separates code that's
arch-specific by nature, lets us avoid all the ugly quote marks and \n
sequences, and lets your editor do real syntax highlighting of asm.
2013-04-12 13:07:23 -07:00
ptarjan 0038b76a58 kill TAINTED code
While I was working on the TestCodeRun refactor I found two tests about Tainted code. I looked into it and coulnd't get HHVM to compile with TAINTED=1. Then I checked and none of the extension functions we exposed about tainting were used in WWW. Scratching my head I asked, @srenfro and @jdelong, who  thought it was dead. So I killed this zombie.
2013-04-12 12:04:04 -07:00
bsimmers b8ae94e039 Implement FPushCuf* in hhir
This handles almost all the cases tx64 does. It takes a slow
exit when a Class or Func that was around at translation time doesn't
exist at runtime, which never happens in prod (as of right now).
2013-04-12 12:04:03 -07:00
kma 197305cc45 HHIR mod. 2013-04-12 12:03:57 -07:00
bsimmers 0dd21ce600 Disabled non-refcounted locals optimization
It's still flaky, and I'm hitting asserts related to it on
trunk right now.
2013-04-12 11:22:45 -07:00
jdelong d432f19ae1 Allocate unit bytecode and metadata in a read-only memory region
Only in RepoAuthoritative mode, where units can't be
deallocated.  I have a semi-reproducable bug where a unit's m_bc
region is getting corrupted (only occasionally in perflab).
Presumably moving it out of the malloc'd heap will make the bug
corrupt something else, so this probably doesn't really help much, but
it seemed like having a separate region for some cold, read-only,
process-lifetime metadata might make sense.
2013-04-12 11:22:45 -07:00
jdelong 9e7de4a990 Use hphpc-provided property types in CGetM prediction
We still need to check that the types aren't null, but we can
continue traces with a side-exit guard.
2013-04-12 11:22:45 -07:00
jdelong 264500f5f9 Add a few traces in annotation.cpp 2013-04-12 11:22:45 -07:00
bsimmers 547a45231d Shut down if we lose a LightProcess child
This should only happen if there's a bug in our code and the
child process crashes, or if one gets killed by the OOM killer. In
either case, it's probably not safe for the parent process to continue
uninterrupted, so shut down.
2013-04-12 11:22:44 -07:00
kma 4f8bcc9f6c Remove HPHP_LIB as a place to find systemlib.php 2013-04-12 11:22:44 -07:00
ptarjan 36b9a96335 stop prefixing test to TEST_PATH
It is good design to not repeat things that are redundant,
but this keeps anoying me that I can't tab complete this.
no-one should be used to the syntax yet so now is the time to change it.
2013-04-12 11:22:44 -07:00
ptarjan c19b117f6b use sample dir for TCR
I made a sample directory with a file, a symlink, a dir, a recursive symlink and an empty file. Hopefully that is enough edge cases.

I tried to find all the places that used weird files and ##test## in TCR and used this dir instead.
2013-04-11 14:34:56 -07:00
ptarjan 568f06d05d remove conflict markers
Summary:
If I try to split these into non-strings, I get a commit hook error.

To get rid of them I did this:

  %s/=======*/------------------------/g
2013-04-11 14:34:14 -07:00
ptarjan 9b1dc0f963 create .diff file even for .expectf
I'm having a tough time debugging the ##.expectf## tests because I don't have an easy diff. This is a poor man's one unless someone else is aware of a nice regex debugging thing.
2013-04-11 14:34:14 -07:00
bertrand b31744c3da Optimize NewObj when no constructor is needed
Tx64 has this optimized helper path for object creation when the
default 86ctor construction is used.  Ported this to HHIR.
2013-04-11 14:34:14 -07:00
Sara Golemon 5323725b0c Kill off .inc files
Import data from ClassInfo (sourced from class_map) instead
2013-04-11 13:54:52 -07:00
seanc 0840deb71a Use name to be consistent with Zend in backtraces
Generators should specify function names as the name instead of the
full name for consistency with Zend 5.5 (and more importantly because
this breaks PHPUnit), this was exposed by the backtrace removal of
file and line info
2013-04-11 12:13:43 -07:00
bsimmers 284d8f144d Implement StaticLocInit in hhir
This is almost the same as tx64's implementation, with one
substantial difference: the targetcache slots hold RefData* instead of
TypedValue*. This is ok because cache handles aren't shared between
translations. I also had to rework some code in dce to handle
consuming a reference through a phi node.
2013-04-11 12:13:43 -07:00
bertrand a2ffc03900 Always inline opPre
opPre is marked as inline, but our current gcc version isn't
actually inlining it anywhere.  I find that surprising, because it
seems like a no-brainer: the function is small and the code gets
better when inlined (e.g., it gets rid of stores to reference params).
This diff makes the text very slightly bigger but should have good
effects on locality within the helpers.
2013-04-11 12:13:42 -07:00
mwilliams 26cf67d974 Fix interface1.php's expected output
Somewhere in the .filter consolidation and cleanup,
the bit that stripped the function name was removed. Add it
back.
2013-04-11 12:13:42 -07:00
mwilliams dd56c6821f Util::string_printf should do printf style argument checking
I made a mistake adding persistent target cache to
TranslatorX64::getUsage that would have been caught.

Also adds the persistent target cache stat.
2013-04-11 11:03:49 -07:00
bertrand 7de123db40 Only compile one instance of member_operations functions
Functions declared as "static inline" in member_operations.h
end up getting compiled into each translation unit that includes that
header, leading to a lot of duplicated code.  Changing them to just
"inline" causes only instance to be used globally, which seems likely
to be friendlier to icache.
2013-04-11 11:03:49 -07:00
ptarjan 4dfde31584 remove support for .exp
I left in a message to read the README, but I don't know if people will see it mixed into the output.
2013-04-11 10:58:54 -07:00
ptarjan ac1d69902e name anonymous continuations as Class::Method$continuation
As a user, this often annoyed me that I couldn't get any debugging info
out of the name and then @ahupp asked for it.

I didn't really know what to name closure ones as the name is done at
emission time. So I went with ##{closure}##. I'm not sure how I feel
about that since it will be uncorrelated with the emitted name.

While I was in there, I deleted a lot of unused code.

I'm totally open to other names and ideas.
2013-04-11 10:58:54 -07:00
ptarjan 25b9556349 kill dead code 2013-04-11 10:52:54 -07:00
ptarjan 8b3bb26b22 kill default.filter and switch everything to .expect or .expectf 2013-04-11 10:52:48 -07:00
ptarjan 27dc48a6bf kill all .filter files
.expectf can do everything these do in a more readable way.
2013-04-11 10:52:18 -07:00
ptarjan 7a6aeba983 Support zend's test formats
Zend tests have 3 possible sections for test output. EXPECT, EXPECTF, and EXPECTREGEX. I think we should do the exact same thing. The .filter thing is difficult to write tests that have random numbers involved and the PHP community should already be familiar with the EXPECTF format strings.

Migration plan:

  * Kill all .filter files
  * Rename all .exp to .expect
  * Stop supporting .exp

I'm basically planning on suporting all of zend's sections as file extensions. Basically, if they have a section ##FOO## we will have a file ##test.php.foo## (where we need them).

I changed the import script to use our json encoding instead of deciphering what happened from the ##.diff## files (since not everything will have a ##.diff## file now)

We have 50 ##.filter## tests. I'll go convert them to expectf and see if they are easier to read.
2013-04-11 10:38:43 -07:00
jdelong 00380e6ba7 Don't generate RaiseUndefProp in RepoAuthoritative mode
This avoids a SpillStack for simple CGetMs.  Gated under a
flag that defaults to true.
2013-04-11 10:38:10 -07:00
andrewparoski e63a9b3d63 Remove a few more uses of ClassInfo 2013-04-11 10:38:10 -07:00
hermanv 874dee78fd Split ConvToInt into subopcodes specialized by argument type.
We now have ConvArrToInt, ConvDblToInt, ConvObjToInt, ConvStrToInt and ConvGenToInt. This allows these opcodes to have separate flags.
2013-04-11 10:38:10 -07:00
bsimmers 882ef43fbb Disable TestExtMysql 2013-04-09 15:33:09 -07:00
Sara Golemon 9381ab39e7 Improve idl.php generator
Output constants and class implementations in .cpp file
Include base.php via __DIR__ rather than cwd for calling from outside hphp/idl
2013-04-09 15:33:09 -07:00
andrewparoski ecdd701952 Clean up ArrayData APIs for mutable iteration
Replaces the awkward getFullPos() and setFullPos() methods with a more
intuitive advanceFullPos() method. This refactoring also reduces the number
of virtual calls made when doing mutable iteration on an array.
2013-04-09 15:33:09 -07:00
jdelong 486ca81213 Use hphpc-inferred object property types to avoid KindOfUninit checks
The frontend appears to alread pessimize its prediction of
object property types whenever an UnsetContext might affect a given
property.  We can use this to avoid checking for KindOfUninit when
doing specialized prop gets in the vectortranslator.  This is
hopefully going to be worth more than it sounds, because it will let
us avoid a spillStack, which is a use of the frame and will prevent an
inlined getter from removing the ActRec (unless we implement some kind
of sinking for frames).
2013-04-09 15:32:17 -07:00
jdelong 37f5f9cb5a Some comments about use of rVmFp and rVmSp in codegen
We shouldn't be using these registers directly nearly as much
as was appropriate in tx64.
2013-04-09 15:32:17 -07:00
jdelong 9dc66f2f40 Fix an exception safety issue for undefined properties in vectortranslator
I think the only case where we currently don't spillstack as
part of a vector translation is CGetM of a defined property.  However,
this can still raise exceptions in the unlikely case of an unset
property.  For now, just spill before any vector translation---a
follow up diff relaxes this to not do it in cases where we know the
property can't be undefined.  Presumably later we'll push the
spillstacks into the unlikely paths for these translations (or put
them in unwind handlers)---currently we can't handle control flow
where the join point has a different stack.
2013-04-09 15:32:17 -07:00
hermanv 090bc82fa2 Specialized code generation for more of the ConvXxxToDbl instructions.
Rather than using just two general purpose helpers, there are now some specialized helpers and more inline code. Also, the flags in ir.h are now more accurate.
2013-04-09 15:32:17 -07:00
mwilliams e350aa5461 Prevent elimination of stores to generator params
After some recent cleanup to generators, local analysis was
able to remove some stores that it shouldnt have done, because
it didnt take account of the fact that the locals were
generator parameters.
2013-04-09 15:32:17 -07:00
bsimmers 15d4e7d7fe Move a couple zend tests back to bad 2013-04-09 15:32:17 -07:00
jdelong 96d22113c9 RFC: Pass the assembler to use to unlikelyIfBlock
In tx64, a common bug (for me) was to accidentally type "a."
instead of "astubs." when writing code inside an UnlikelyIfBlock,
since your fingers get used to the former.  More generally, it seems
like we should abstract the target assembler from actual codegen in
most cases (we currently really do this in the IR only insofar as
"m_a" might be pointing at "m_astubs", but it's only safe sometimes).

This is just an RFC, because otoh there are less significant chunks of
direct assembler code in codegen.cpp, and maybe it doesn't matter much
unless we also switch "m_as" to be "a".  Thoughts?
2013-04-09 15:31:41 -07:00
jdelong 22005c4cfc DecRefKillThis needs the frame as an SSA dependency
We couldn't see this during ActRec elimination for inlining,
leading to bugs where the wrong this pointer would be decref'd and
then zero'd.  Also take the opportunity to remove a boolean parameter.
2013-04-09 15:31:41 -07:00
mwilliams 57a5cb6be7 Partition the tc into hot/cold sections
We already generate the data for this, so lets use it.
2013-04-09 15:31:40 -07:00
mikemag ab9e26f8af Avoid stack overflow on super-large expressions of binary operators.
A small change to optimize very simple binary operators in the parser. This avoids building very large parse trees for super-large expressions and folds binary operators involving two scalars directly in the parser. I've limited this to simple scalars since it's easy to prove they don't have anything too interesting going on in the other analysis phases leading up to BinaryOpExpression's normal folding. This works for all binary operators.
2013-04-09 15:31:40 -07:00
drussi bf740ca345 expose return type constraint (aka hint) from the AST to the runtime and reflection
This is the first part of the work to expose type constraint and generic all the way to reflection. This first DIFF exposes the return type with generic types coming next.
2013-04-09 15:31:40 -07:00
Owen Yamauchi 95afc7f255 Make NaN -> int casting explicit
See the task for details, but the bottom line is that casting NaN to an
int in PHP is passed straight through to the hardware's
convert-floating-point-to-scalar instruction. This implementation
explicitly spells out the Intel instruction's behavior. The ARM
instruction always outputs zero instead, resulting in inconsistency.

To be clear, I'm OK with not checking this in. For one thing, I'd bet
that if you compiled Zend on ARM, it would cast NaN to zero (I haven't
tried it). The advantage that this gets us is consistent output on all
platforms.
2013-04-09 15:31:40 -07:00
ptarjan 829a86d468 disable broken tests
@bsimmers says they are bad. I'll disable while I debug.

  mv test/zend/good/zend/bug31102* test/zend/bad/zend/
  mv test/zend/good/zend/ns_029* test/zend/bad/zend/
  mv test/zend/good/zend/ns_030* test/zend/bad/zend/
2013-04-09 15:31:40 -07:00
Owen Yamauchi 2755ecc9e5 Someone might want to run this test in another timezone 2013-04-09 15:31:40 -07:00
ptarjan 73663a2512 Allow script to be run without -z option
I switched to using a temporary directory for the test run, but never wrote a way to use the existing bad tests. Now it just copies the bad tests to ##all## and runs them there.

Should I rename this script? ##tools/zend_tests.py## or something?
2013-04-09 15:31:40 -07:00
jdelong c869cb47d8 ContEnter needs to depend on the frame pointer
ContEnter used rVmFp without making it visible in SSA.  This
didn't cause any issues yet because I've never tried to inline
functions that contain a ContEnter.
2013-04-09 13:01:47 -07:00
jdelong 6faa7cbea1 @override-unit-failures Initial support for <?hh typedefs and shapes
Adds runtime support for non-class typehints.  Typedefs are
introduced using type statements, and autoloaded via a new autoload
map entry.  Shapes are parsed but the structure is currently thrown
away and treated as arrays at runtime.  This extends the NamedEntity
structure to sometimes cache 'NameDefs', which are either Typedef*'s
or Class*'s.  VerifyParamType now has to check for typedefs if an
object fails a class check, or when checking non-Object types against
a non-primitive type name that isn't a class.
2013-04-09 13:01:46 -07:00
andrewparoski ebeecdb417 Add map(), filter(), zip() APIs for collections 2013-04-09 13:00:24 -07:00
ptarjan 4e16e58ef4 give up on matching Zend's error messges 2013-04-09 11:11:36 -07:00
ptarjan d8c3398698 Explicitly mark unsupported extensions 2013-04-09 11:07:59 -07:00
ptarjan 40583eaaa0 re-import everything with the new scanf implementation 2013-04-09 11:07:59 -07:00
ptarjan ecec3698d4 fix string funcs to return Variants
Convert another return type to Variant. I'm worried there are going to be lots of these. Thoughts?
2013-04-09 00:31:49 -07:00
bsimmers e55bfbe03c Better register allocation for DefLabel sources
Looking at some of the code generated by control flow was making me a
little sad, since it had avoidable register to register moves in hot
paths. This diff attempts to assign the same register to the destination of a
DefLabel and the corresponding sources of Jmp_s to that label. It works in the
small examples I've tried, but Perflab doesn't seem to care much (not
surprising since at best it'll eliminate some reg-reg moves).
2013-04-08 22:02:21 -07:00
jdelong c6770b6788 Disable HipHop syntax for verify_zend
A zend test defines a class called shape.
2013-04-08 22:02:20 -07:00
kma 8325c73d4e Stop constructing Strings for o_invoke.
Grepping around for string literals passed to o_invoke turned up these suspects. It's not a great practice. The only one that might matter to perf is the "count" invocation in ext_array.
2013-04-08 22:02:10 -07:00
andrewparoski d0321ec5aa Rename Tuple to Pair, restrict them to having exactly 2 elements 2013-04-08 21:41:07 -07:00
jdelong 7b243f97ed Remove enum abuse in recordSyncPoint 2013-04-08 21:17:46 -07:00
mwilliams ec35f444ee Get rid of contEnterHelper* (revert the revert)
It was identical to fcallHelper, except that if it couldn't get
a translation, it skipped over the prolog (and didnt call
the FunctionEntry hook, for example). That seems like a bug.

This removes it, cleans up funcBodyHelper to remove the special
cases for isGenerator, and modifies ContEnter to use
Func::prologTable()[1], rather than Func::funcBody() to dispatch.
2013-04-08 21:17:46 -07:00
mwilliams b9e7308acb Fix some bugs when we fail to get a translation
If we failed to get the translation for a cloned closure, we didnt
clean the registers.

VMRegAnchor::VMRegAncor(ActRec*,bool) didnt know how to set things
up for continuations, and had an unused bool parameter.

RetFromInterpretedFrame isnt suitable for returning from a
generator - so just preserve m_savedRip across the doFCall.
2013-04-08 21:17:46 -07:00
Owen Yamauchi 9c453b1ad0 Get rid of ext_hhvm_noinline.cpp, part 2
unserialize() and call_user_func_array() were straightforward. They were
called from all over the runtime, but I renamed those implementations
and codemodded the runtime.

The is_* functions were only ever being called by the CVarRef signature,
so I deleted all the other ones (same for f_gettype). Only some of the
is_* functions were being called from the runtime, so I made inline
versions of those without the f_ prefix.
2013-04-08 21:16:48 -07:00
kma 19e1eb22a3 Fix type buglet in RetC.
We can decRef an unguarded local from RetC now. This seems
like the right approach, so promote its type to Gen.
2013-04-08 14:05:20 -07:00
mwilliams dbf9403077 Revert "Get rid of contEnterHelper*"
This reverts commit 94d9bf9a5f
2013-04-08 14:05:20 -07:00
seanc b1e00e219b Add original filepath for continuations in backtrace 2013-04-04 15:39:04 -07:00
mwilliams 46e547b907 Use Func::m_funcBody to avoid SrcDB lookups 2013-04-04 15:39:04 -07:00
mwilliams 94d9bf9a5f Get rid of contEnterHelper*
It was identical to fcallHelper, except that if it couldn't get
a translation, it skipped over the prolog (and didnt call
the FunctionEntry hook, for example). That seems like a bug.

This removes it, cleans up funcBodyHelper to remove the special
cases for isGenerator, and modifies ContEnter to use
Func::prologTable()[1], rather than Func::funcBody() to dispatch.
2013-04-04 15:39:03 -07:00
kma b082ed0432 All inc and dec, all the time.
On older processors, inc and dec have some specific hazards associated with their preservation of the CF flag. Sandy Bridge doesn't suffer from this, so let's take the code size wins here. Thanks to Guilherme for updating my dated priors on this.

Also fix a pair of assembler bugs: no such thing as decl r32 on x64, and some decs were really incs.
2013-04-04 15:39:03 -07:00
mwilliams c4b56e312d Fix UnsetM with global base
If the global was not defined, it would try to return
a pointer into the MInstrCtx, which was not passed in.

We dont actually need it though, because in that case we can
just return a pointer to init_null_variant.
2013-04-04 15:39:03 -07:00
ptarjan 20ed47c5a1 kill dead code 2013-04-04 15:39:03 -07:00
ptarjan 0fbd3e35c7 add bcmath tests
All the bad tests seem to be error mis-matches. I already changed one error message about arguments so I think I should just make all these too many too few errors match.
2013-04-04 15:39:03 -07:00
ptarjan 2b85ccec0f switch to the same system as run-tests
My %s implementation needed backtracking, and instead of working on fixing that up, I switched to the same system as run-tests. This will serve way better as it is exactly their implementation.

Basically, instead of using the .diff I do the comparisson manually of .out and .exp using regexes. I'll go back through and re-import the other test diffs and see if things change. It worked well for the bcmatch tests (which is what I needed the backtracking %s for).

I used code from: https://github.com/php/php-src/blob/master/run-tests.php#L1895
2013-04-04 15:39:03 -07:00
ptarjan 339e0bfe26 don't import sapi tests
For things that we are intentionally not implementing, I don't think they should live in our repo at all. Do you agree? Or would you rather them all in the bad directory?
2013-04-04 15:39:03 -07:00
ptarjan 8e0f4cf43c import all tests from 'tests' and subdirs
I changed the import script to use a temporary directory instead of the bad directory. This makes is much faster to import only some files.

Done with:

  python tools/import_zend_test.py -z /tmp/php-5.4.11/ -o php-5.4.11/tests/
2013-04-04 15:39:03 -07:00
ptarjan e50740dd02 I found more tests...
So, I was being dumb and thought that that only tests zend had were in the folder called Zend/tests. On happenstance I typed a bad find command and found tons more tests all over the directory structure. I sort of figured out their directory structure and changed the importer to do all of it. Now we have an order of magnitude more tests. I didn't want a very deep directory structure so I replaced their ##/## with ##-##, but I'm open to other ideas.

The import script simulation of sscanf got crazyier since it now sees all sorts of nutty things like ##'%\0'##. I left the exception handing for errors incase zend adds more things that we need to parse.

Some of these tests are really really bad. They spew files all over your directory tree. Some with names that have nulls in them and other wonderful things. I'll start monkey-patching them. Only 1 test in the good directory does that, so I'll do that first.

Our coverage is MUCH worse now, but there are lot of unimplemented extensions and non .phpt file dependancies (@sgolemon not everything is encapsulated as tightly in one file). I'm sure I'll have some fun going through these.

We are at 2836 good and 9176 bad.

I've debated to use the actual php ##run_tests.php## but it seems very specialized. @sgolemon do you think it can't be wrangled into our tests? Or maybe output a compatible format?

I'm splitting the diffs up so we have a hope of hudson running them. I added the ##-o## option to help in that. This first diff basically moves all the tests into another dir but shouldn't change any. I'll send many other diffs for all the others tests.
2013-04-04 15:39:02 -07:00
mwilliams 016c4abe84 Fix issues with dead locals in backtraces
The specialized RetC sequence in tx64 destroyed each local,
and then set it to null in case onFunctionExit captured a
backtrace. But if the destructor of a sub-object captures
a backtrace, its already too late.

The same code in hhir didn't null out the local at all.
2013-04-04 15:39:00 -07:00
hermanv 1256f940ab Add the K flag to ConvObjToArr and ConvGenToArr.
Brett commented on another differential: CRc means the opcode takes ownership of a (probably recently created) reference to its source, either by decreffing it or by storing it into an object property, array, etc... It's true that these are generally used right after an incref, but the design of the opcode shouldn't assume anything about its use, especially for opcodes like this that can be generically useful.

Any opcode that decrefs one of its sources without guaranteeing that the refcount won't go to zero should kill that source. If you can guarantee that these instructions will never destruct their source then they don't have to kill the source.
2013-04-04 15:39:00 -07:00
ptarjan 78df5374d5 change func_num_args() from parser error to warning
I also introduced some code that I'll use to map their error messages to ours.
2013-04-04 15:39:00 -07:00
ptarjan 7cb07d22cf stop segfaulting in propery_exists 2013-04-04 15:38:59 -07:00
ptarjan 6e2868de3e allow recursive test running
I found a bajillion more tests in the Zend repo, and I'm going to have to namespace things. I think this solution will also be nice for the porting our C++ strings. One directory per package and then when you want to run them all you run the top-level.
2013-04-04 15:38:59 -07:00
ptarjan f7b2fac580 become consistent with zend for too few param error
I've been fighting with these in the importer. What do you think about being consistent? It gives an extra param of info too.
2013-04-04 15:38:49 -07:00
jdelong e72045d0e3 Remove some codegen traces 2013-04-04 12:20:04 -07:00
mwilliams 39ba801ffc More smart containers
And use them for VariableSerializer/VariableUnserializer
2013-04-04 12:20:04 -07:00
mwilliams 8dd81181b7 Fix cgJcc for bool comparisons with constants
The bool value is in the bottom byte of the register,
with the rest of the register undefined, but we were doing
a 32 bit compare.
2013-04-04 12:20:04 -07:00
kma 68ac3730f4 Do away with DumpIR.
DumpIR inconsistently interacted with the trace facility.
Move it to the hhir trace module. Compress a bunch of copy-pasta.
2013-04-02 15:01:37 -07:00
bsimmers 691b231fd1 Emit UnsetProp in VectorTranslator
I added this punt as a correctness fix while implementing
UnsetElem. It does show up as ~6% of remaining punts and it's easy to
do, so here it is.
2013-04-02 15:01:37 -07:00
bertrand d181040b4b Fix CreateCont for HHIR 2013-04-02 15:01:37 -07:00
jdelong c5db7e39ab Fix a bug with boxed static/counted types
When we box things, we need to forget whether we knew it was
static or not because we don't track when that might change.
2013-04-02 15:01:37 -07:00
jdelong eee109bdd5 SpillStack of an ActRec is a use of the old fp
A bug like this was bound to happen.  Thanks to whoever added
the assert for saving me from real debugging (@smith?).
2013-04-02 15:00:53 -07:00
ptarjan 2a9d6ec34d disallow Variant(TypedValue*) constructor
I was being dumb and hit this bug. Never again shall someone have this problem.
2013-04-02 15:00:53 -07:00
mwilliams 4e7457bd8c Fix FPushClsMethodD in hhir
Non-persistent classes can't be burnt in (or at least,
you have to check the target cache before using it).
2013-04-02 15:00:53 -07:00
jdelong eea87e32c6 Remove m_fpiStack
It doesn't appear possible to get a Func this way that we didn't
already have from static analysis.
2013-04-02 15:00:53 -07:00
ptarjan c04652f7aa fix test zend_import_test 2013-04-02 15:00:53 -07:00
mwilliams 1c329e4ba8 Add a test case for the scope of a closure generator 2013-04-02 15:00:53 -07:00
ptarjan f31278175a allow zend importer to run without zend directory
Most people won't have a full zend checkout, but I expect people to want to import zend tests. That's the whole point of having them checked in to the bad directory. Now you just do

  python tools/import_zend_test.py

and it will run all the bad tests and move the working ones to the good directory. The old way of doing it is now

  python tools/import_zend_test.py -z /tmp/php-5.4.11/

and if you don't want to re-run the binary (way faster) just do

  python tools/import_zend_test.py -n
2013-04-02 15:00:53 -07:00
hermanv 2a75bbce25 Introduce more helpers like Type::isArray.
class Type had methods isArray and isNull, but not methods like isBoolean. This change introduces helpers for the other types that frequently need to be tested for in type specialization code. The change is kept small so that is is obviously correct and easy to push quickly. Making all type tests consistent will have to be achieved incrementally.
2013-04-02 15:00:46 -07:00
jdelong 6ddd4be669 Fix an assertion in traceRet, relating to generator frames
This was firing in my sandbox.  I didn't find anything that
looked like it changed it recently, so I'm not sure why it wasn't
firing earlier.
2013-04-02 15:00:45 -07:00
mikemag e8c06b0312 Fix heredoc/nowdoc bugs with large docs, docs crossing buffer boundaries
Fixed a few issues in the lexer for heredocs and nowdocs. The source file is read in 64k chunks, and any time a doc was split across a buffer boundary the lexer would fail to consume the doc properly. Modified the lexer to refill the file buffer when it is used, or when more data is needed in a variety of cases. Also fixed a number of other corner cases where we'd fail to recognize the doc end label or other special characters. The old code was also a bit over- and under-flowy.
2013-04-02 15:00:45 -07:00
andrewparoski 31173142e1 Implement collection interfaces 2013-04-02 15:00:24 -07:00
andrewparoski f6ec5180bb Add addAll() and setAll() APIs 2013-04-01 14:26:59 -07:00
ptarjan 3b3963727d change exactly message
This fixes 005.php.

Shoudld we change our error message instead? We aren't even consistent with the error message for 001.php for func_get_args().
2013-04-01 13:48:59 -07:00
ptarjan 0defae9799 first monkeypatch of zend test
This test keeps making a file in my directory :(. How does this look for a monkeypatching setup?
2013-04-01 13:48:59 -07:00
ptarjan 5a094b72f2 Parse sscanf stuff from php tests
I originally just started copying their script which transforms %s to a regex, then run the regex. Then I realized their script does a ton more than they use in their test and was getting super compliected. This simple walking parser seems to do the trick. Escaping the regex for python's re was also being difficult.

This got us 145 more tests. yay.
2013-04-01 13:48:59 -07:00
andrewparoski 6e7b02933c Fix bugs with unserializing collections
The 'r' encoding for unserialization was broken for collections because the
code was calling Variant::unserialize() on a temporary Variant, which is a
no-no. unserialize() must be called directly on the value where it resides
in the collection.

Second, there was an inconsistency between serialize and unserialize with
how id numbers worked for the 'r' and 'R' encodings. This diff fixes
serialize and unserialize to count collection keys when assigning id
numbers. I also took the opportunity to tighten up enforcement to prevent
collections keys and values from being taken by reference when during
unserialization.
2013-04-01 13:48:59 -07:00
mwilliams 17f2ae8df7 Fix the context class for continuations in closures
The late static bound class was being used for the context. This
was wrong, but before this change there was no context at all, so
it would have taken newly written code to expose the bug.

However, a given continuation can be instantiated from a large number
of different lsb classes (but only one context class) which meant that
we got an explosion of unnecessary translations.
2013-04-01 13:48:50 -07:00
mwilliams bfd325be43 Prevent a race in RecordFunctionInfo
We were calling RecordFunctionInfo on every builtin function/method
every time we parsed a file (in non-repo-auth mode). Once this has
been done once, its just a no-op. But if multiple threads try at the
same time, we can get a race inserting into an unlocked hash table.

Move the calls into ParseExtFunction which avoids the race (we
guarantee to call BuiltinFunctions::Load from a single thread at
startup time), and avoids doing redundant work for each file parsed.
2013-04-01 13:48:50 -07:00
bsimmers b7d72e3894 Fix baseValChanged check for empty base promotion in VectorEffects
I thought I'd have to teach memelim about the PtrToBoxed*
srcs for vector instructions but it turns out the refactoring I did in
the UnsetElem diff was enough. It already clears out the local map for
instructions that may modify refs.
2013-04-01 13:48:50 -07:00
mwilliams 5b0c146e4a Fix a crash in exif processing
Given a zero length string, the pointer was left unset, but
later code checked if the value of the pointer was non-null,
and ignored the length.
2013-04-01 13:48:50 -07:00
ptarjan 329d6c3aa3 Handle "line %d" and extra lines for errors in expected output 2013-04-01 13:48:50 -07:00
jdelong 40f61f6686 Remove ... when hphpc prints the hhvm command line 2013-04-01 13:48:50 -07:00
ptarjan be704f1faf import zend tests
This is a first pass looking for suggestions.

    348 / 1268 passed (27.44%)

I modified the script, then ran:

    ./tools/import_zend_test.py /tmp/php-5.4.11/

which created all the zend tests. When they send out a new update, this script is idempotent so running it on the new tests should just make the working directory in a good enough state to commit.
2013-04-01 13:48:31 -07:00
mwilliams ec4e62d602 Fix closure dispatch when there's more than one Func*
We need to make sure that we execute the code
corresponding to the actual Func*. This re-uses the
prolog array to hold the entry points for the cloned
Func*.
2013-04-01 13:47:50 -07:00
bsimmers b8ebb48421 Profile vector instruction shapes
This adds a new profiling mode for vector instruction
shapes. I'm planning on using this to identify any common cases that
may be worth special casing, like we do for simple SetM, CGetM, and
IssetM instructions. Instead of adding Yet Another Hashtable Stats
Map, I created a generic version and changed TRACE=punt:1 to use it as
well.

I also changed emitInterpOneOrPunt to use a more specific name.
2013-04-01 13:47:50 -07:00
bsimmers 66a84f861d Implement VectorTranslator::UnsetElem
Fairly straightforward. The only interesting part is the
addition of ElemUX, which behaves similarly to ElemDX in terms of
side-effects (but not exactly the same).
2013-04-01 13:47:50 -07:00
seanc c6d10ce255 Add HPHP support for newInstanceWithoutConstructor
Add support for PHP >=5.4 ReflectionClass::newInstanceWithoutConstructor
2013-04-01 13:46:30 -07:00
bsimmers 7d7edb8be2 Implement all of VerifyParamType in hhir
TranslatorX64 interps cases that it expects to fail but I
didn't like that, so the hhir version never punts or interps. The fast
path code reuses the stuff Jordan added for InstanceOfD and should be
the same as tx64's, modulo some branch fusing that doesn't appear to
matter in perflab.
2013-04-01 13:46:30 -07:00
bsimmers 88f1bcf907 Strengthen filepath.filter and make it run for all tests
It now handles filenames in strings that have been
var_dumped, without having to special case them. I also renamed it to
default.filter and changed verify to run it on every test. This lets us
remove a lot of symlinks that used to point to filepath.filter and
changed the expected output for a bunch of tests.
2013-04-01 13:46:30 -07:00
seanc 4a6ae52f5d Generators should show original name in backtrace
Use the original name instead of the outer name for generator
functions in backtraces
2013-04-01 13:46:30 -07:00
ptarjan a2c5921413 fix double space after notice and warnings
We are inconsistent with how many spaces happen after ##:## Errors have one, but warnings and notices have 2. I went with 1 because that is what Zend does.
2013-04-01 13:46:30 -07:00
Owen Yamauchi 0fd0fa814c Get rid of ext_hhvm_noinline.cpp, part 1
Post-hphpc, declaring builtins as inline is useless, which obviates the
need for this layer.

This doesn't fully delete the file, because I wanted to keep mindless
parts and use-your-brain parts separate. This is the mindless part. The
remaining functions in noinline.cpp are no-inline wrappers around
(a) a function that isn't defined in an extension, call_user_func_array,
and (b) calling polymorphic is_* functions, which can probably mostly go
away now. But I wanted to exercise more care around those, so they'll
come in a followup diff.
2013-04-01 13:41:49 -07:00
mwilliams ed6ac5d10f Fix refcounting issues with string SetM
The code was assuming that the result of the assignment
would be the value assigned, but its actually a new string
containing the first character of the value assigned. The result
was that the SetM had already decRef'd the rhs, and then the
jitted code decRef'd it again. Since that last decRef was a decRefNZ,
we would often get away with simply leaking both the original rhs and
the value of the SetM. But the new testcase crashes in a DEBUG build
without the fix.
2013-04-01 11:51:38 -07:00
smith 22058efe41 Allow different RefData and TypedValue layouts
Fixing various bugs all over the VM that make assumptions about RefData
and TypedValue layout.  Here are the assumptions fixed by this diff:

offsetof(RefData, m_tv) == 0.  Both JIT's assumed this in many subtle
ways, by punning RefData* as TypedValue* without adding an offset.
This assumption also causes RefData._count to overlap TypedValue.m_aux,
which constraints TypedValue layout.

offsetof(TypedValue, m_data) == 0.  gen_ext_hhvm.php assumes you
can cast TypedValue* to Value*; the JITs often weren't using
offsetof(TypedValue, m_data) in their addressing calculations.  HHIR
assumed return-by-value TV's have m_data/m_type in rax/rdx, which
can change when TV layout changes.

offsetof(TypedValue, m_type) > 8 is an assumption baked into the
pass-by-value register assignment logic in HHIR's codegen.cpp; if
the type is in the low word, register assignment is swapped.

sizeof(TypedValue::m_type) == 4.  We used dword-sized operations
in both JIT's when accessing m_type.  Now, we use helper functions
that are sensitive to sizeof(DataType)

Configuration:
DEBUG=: (opt)  same layouts as trunk for RefData & TypedValue
DEBUG=1: (dbg) new RefData layout (m_tv doesn't overlap RefData::_count)
PACKED_TV=1, DEBUG=*:  new RefData and TypedValue layout.
2013-04-01 11:51:31 -07:00
smith 55c20f79c1 Tighten tvIsPlausible() checks
I've found several bugs recently due to the TypedValue plausible
check being too loose.  Our DataType enum values are now sparse,
and we miss garbage that happens to fall inside the [-10, 127]
range, which is >50% of possible garbage values.
2013-04-01 11:51:31 -07:00
andrewparoski 5b8111f402 Chip away at ClassInfo::FindClass() and ObjectData cruft 2013-04-01 11:51:31 -07:00
mwilliams 0ddaed959d Fix assert in CodeGenerator::emitTypeCheck
The vector translator produced a type that was
boxed-array-or-string, which we couldnt guard on.

Since applying a SetM to a string will almost always produce
a string, change it to report string instead (which will still
be guarded on).
2013-04-01 11:51:30 -07:00
mwilliams 4976bf8379 __lvalProxy needs to be request local
But it was recently made thread local. If the value left
in it at the end of one request was smart allocated, the
next request would try to free it - but after its already
been swept.

We could make this RequestLocal, but that seems to add even
more overhead. We could probably make it a __thread TypedValue,
and just set it to uninit at the start of each request (and then
tvAsVariant() where its used). This just puts it back to how
it was, since global_variables() is already being dealt with
appropriately.
2013-04-01 11:51:30 -07:00
smith 13394d0525 Remove dead lvalPtr(int-key) API 2013-04-01 11:51:30 -07:00
Sara Golemon f436534766 Add install target (and remove errant install targets from 3rd party)
make install
  Installs hhvm and systemlib.php to CMAKE_INSTALL_PREFIX/bin

To override the default location define it during cmake:
  cmake -DCMAKE_INSTALL_PREFIX=/usr/hphp .
2013-03-28 23:53:20 -07:00
Sara Golemon 316f2b13db Update folly 2013-03-28 23:09:16 -07:00
Sara Golemon ba168876d3 Remove unused files and set master branch to declare HPHP_VERSION==2.1.0-dev 2013-03-28 16:07:30 -07:00
mwilliams f03fb8ca06 Fix TestServer/TestXboxServer
A recent change to xbox makes it reset after every request.
This broke a test which was testing that threads only get
reset when they ask to be reset.
2013-03-28 12:28:17 -07:00
jan 1da3705450 Cleanup Static{Result,Exception}WaitHandle construction interfaces
Provide a Static{Result,Exception}WaitHandle::Create() static method for
internal use, use it by GenArrayWaitHandle.

Avoids one inc/decref (Array -> Variant -> m_resultOrException) if
GenArray received an array of finished dependencies.
2013-03-28 12:28:17 -07:00
Sara Golemon 1a579441fb Switch to reentrant safe calls in posix
posix_getpwuid()
posix_getpwnam()
posix_getgrgid()
posix_getgrnam()
posix_ttyname()

were using non-threadsafe posix calls.
Most using AttachLiteral for shared space as well.
2013-03-28 12:27:01 -07:00
jdelong 7baa9acbaa Move some cold stubs from a to astubs
Bertrand's profiling data showed we're wasting the first 3
cache lines of a.  Move defClsHelper and the (now rarely used)
non-generic decref stubs to astubs.  Also adds some tracing I was
using to see how big and where things are.
2013-03-28 12:03:11 -07:00
jan 3adce96fdc Remove markCurrentAs{Succeeded,TailCall}
Tail calls were eliminated, results are set thru ContRetC opcode, these
functions are no longer needed.
2013-03-28 12:02:53 -07:00
jan 20b8aeea2f Consolidate ContDone into ContRetC
Merge ContDone+ContExit into ContRetC with added support of passing results. This variable passing mechanism is not exposed to the PHP as the ReturnStatements in generators do not contain result expression. However, this is exposed by restored hphp_continuation_done() built-in to allow experimentation.

The idea is that once we introduce ContYield opcode (merge of all opcodes used by YieldExpression), we could change ContRetC and ContYield to leave result and done-status on the stack and leave it up to the caller (ContNext/ContSend/ContRaise) to fill in Continuation fields. This will make these opcodes more generic and useful for other things, while allowing us to move some properties to the VM and kill opcodes like ContCurrent.
2013-03-28 11:05:47 -07:00
hermanv cd6fa358d5 Split up ConvToDbl into sub-opcodes.
Split up ConvToDbl into ConvArrToDbl, ConvBoolToDbl, ConvIntToDbl,
ConvObjToDbl, ConvStrToDbl and ConvGenToDbl, so that different flags
can be set for each instruction.
2013-03-28 11:05:43 -07:00
jan 6822bc55cc Early release of m_received value
Continuation::send() uses m_received field to transfer the value inside
the continuation. This field remains set until the continuation is
iterated the next time.

Unset this field early by ContReceive so that the memory can be
reclaimed.
2013-03-28 11:05:42 -07:00
bsimmers a15b680acc Remove special cases for vector instructions in the ir
VectorTranslator is now good enough that all of this code can be
removed without causing a perf regression. Instructions, loads, and stores are
all slightly up, but CPU time looks like noise.
2013-03-28 11:05:42 -07:00
bsimmers 3ec24e45d6 Fastpath for simple array IssetM
TranslatorX64 has a fast path for this case so I thought I'd
try it out in the ir. It's a small but apparently real win in Perflab.
2013-03-28 11:05:42 -07:00
ptarjan 3710ac0713 Remove duplicately named variables from a closure class
Remove it from the usevar list. Also, add assert to catch stack pointer bugs.
2013-03-28 11:05:42 -07:00
Sara Golemon b8868a1c40 Cast result of unpack to uint64_t when requesting unsigned type 'I'
ZendPack::unpack() always returns a signed int32_t,
regardless of actual storage type being unpacked.  For 32bit
unsigned types ('L', 'N', 'V', and 'I'(on I32 systems)) this
means overflowing in the helper and we have to explicitly
recast it to a uint64_t to get the data back out.

For LNV, this was already handled, it was missed for I.
2013-03-27 17:39:44 -07:00
Sara Golemon 463ce4edd5 Remove dead extprofile generators
While looking into another matter I noticed this dead code lying around.
It has no callsites because we don't have extprofile files anymore.
2013-03-27 17:39:44 -07:00
kma 5e603184f5 De-virtualize ArrayData::release.
Of the four horsemen of the SmartAllocator, ArrayData was the only virtual
call. This meant an extra layer of indirection when coming from the TC
to allow the c++ compiler to emit its virtual call, and slightly larger
callsites when using non-generic paths.

While we're moving in this direction, consolidate ArrayData introspection
on its type enum. isSharedMap() was previously implemented with a vtable
slot, and we had no way of asking if an ArrayData was a NameValueTable.
2013-03-27 17:39:41 -07:00
ottoni 56cfa9c73c Eliminate IncRef/DecRef pair when a method returns $this
Instead of generating IR like:

   t1:Obj = LdThis t0:StkPtr
   t2:Obj = IncRef t1:Obj
   ...
   DecRef t1:Obj
   RetVal t2:Obj
   ...

This diff changes HhbcTranslator to produce:

   t1:Obj = LdThis t0:StkPtr
   t2:Obj = IncRef t1:Obj
   ...
   DecRefNZ t2:Obj
   RetVal t1:Obj
   ...

This enables the ref-counting optimization to kick in.
2013-03-27 17:39:41 -07:00
jan c2469a8f85 GenArrayWaitHandle: import all children on enterContext
If a GenArrayWaitHandle is imported, the current implementation imports
only the active child. Try to import other children as well to increase
parallelism.

enterContext() can throw an exception if a cross-context dependency
cycle is found. It is safe to ignore such exception when importing
non-active children. The import will be attempted and fail again once
onBlocked() reaches the dependency that causes the cycle.
2013-03-27 17:39:41 -07:00
jdelong 2c72411dae Don't use LdClsPropAddrCached for properties that might not be accessible
Tx64 only translates CGetS when you do it with the context
class the same as the class being looked up, to avoid the need for
accessibility checks.  The IR can translate it more often, but was
using its fast path even when it was not safe to do so: if a previous
(safe) access had allocated a targetcache entry, later accesses would
be able to get to the property without an access check.  For now just
limit the optimiation to safe cases.
2013-03-27 17:39:41 -07:00
jan 4a2dc584f8 GenArrayWaitHandle: verify input array in advance
Verify sanity of input array of dependencies in advance. Callers get the
error earlier and it also makes it easier to work with the array outside
of the main loop.
2013-03-27 17:39:19 -07:00
mwilliams 46fe09ca5e IncDec bool needs to push a value
In the ir, it didnt, resulting in crashes/bogus values
2013-03-27 17:39:18 -07:00
andrewparoski ee2d13b031 Add add() API for collections 2013-03-27 17:38:50 -07:00
smith d55c44a8ca Fix some RefData<->TypedValue<->Variant<->Value type puns
Our ext_hhvm generated code is casting TypedValue* to Value*
on the assumption that the offset of TypedValue::m_data is 0.
Fix this assumption, and also while in the same code, replace
some (t == KindOfString || t == KindOfStaticString) with
IS_STATIC_STRING(t), which does a single bit test instead of
two comparisons.
2013-03-27 16:52:16 -07:00
bsimmers b4ed082dd7 Add a fastpath for simple array CGetMs to VectorTranslator
This is modeled after TranslatorX64's emitArrayElem.
2013-03-27 16:10:46 -07:00
Alex Suhan fb121815dc Merge {get, set}HelperPre 2013-03-27 16:10:46 -07:00
kma aa3487dc78 Get rid of some destructor wrappers.
Many destructors were going through a C++ trampoline that did
nothing but turn a C call into a method call. Get rid of these where
possible. ArrayData still uses a virtual release, which is unfortunate
but cannot be helped at the moment.
2013-03-27 16:10:46 -07:00
steveo b4ca4bbbd0 change use of html_supported_charset to avoid duplicating work
change callers of determine_charset to check for nulls, instead of calling html_supported_charset (to pre-validate charset name) and then calling this (which has to run through a list of names anyway).
2013-03-27 16:10:33 -07:00
andrewparoski d61c30ded8 Add containsKey() API 2013-03-27 15:56:06 -07:00
andrewparoski bb2df58a2f Add items(), keys(), and fromItems() APIs for collections 2013-03-27 15:30:16 -07:00
Sara Golemon 0690c787e4 Prevent non PHP licensed files from being overwritten 2013-03-27 13:06:09 -07:00
aalexandre 42ec075946 ArrayData.* improvements
A few simple refactorings and optimizations for array_data. Perflab results (CPU time %) are on the desired side of noise: 22/23 show reduced times, 12/23 green, no red, best -2.2%, worst +0.3%.
2013-03-27 11:40:17 -07:00
jan a131e5232e Handle invalid Continuation state at start time
In an unlikely situation a user of ext_asio may tamper with Continuation
before passing it to the ext_asio extension. Let's fail with an
exception if this happens. Previously, a user bug would stay unnoticed,
but would not harm the ext_asio code.

This check will be needed once we implement optimistic execution. With
optimistic execution, we iterate continuation and defer construction of
ContinuationWaitHandle until the first blocking event occurs. During
this phase, a standard dependency loop detection is skipped and the code
would try to iterate a continuation that is already being iterated.
2013-03-27 11:40:17 -07:00
bsimmers afc455cf07 Put VectorTranslator helpers in a namespace
By making them not static they'll show up in TRACE=stats
output and when printing IR.
2013-03-27 11:40:17 -07:00
Sara Golemon 3a6c4e2626 Minor cleanup to hphp/CMakeLists.txt
ext/sep no longer exists
Make test exclusions generic
2013-03-26 12:06:47 -07:00
bsimmers 1467bee4a5 Add null base support to VectorTranslator
The only changes necessary were splitting PropX into PropX
and PropDX/PropDXStk and loosening the type check in
VectorTranslator::getInput.
2013-03-25 13:31:17 -07:00
mwilliams 73f6c7f9c4 Add option to not delete perf-pid.map on exit
Its useful to keep it around for command line scripts
2013-03-25 13:31:17 -07:00
smith e82aaf0281 Removed unused helperFromKey() function in translator-x64-vector.cpp 2013-03-25 13:31:17 -07:00
ptarjan 6e8eb46729 convert init_closure into assembly
I got to do a few optimizations:

* burn in the number of use vars
* not write out uninitialized use vars
* use the staticness of the method as a hint for the incRef
2013-03-25 13:31:17 -07:00
ptarjan bb40c64e25 fix this callsite incase someone ever does the TODO for setting valueClass() 2013-03-25 13:31:17 -07:00
ottoni afe1b1a705 Don't spill to mmx.
There is not a clear path forward to safely using MMX registers as
scratch storage. Doing so spoils the state of the legacy x87 FPU, and the
x64 ABI uses the x87 FPU to implement long double. Our options are to
either:

  1. Prohibit use of long double in source code (or x87 instructions in
     machine code). Given that we have a dynamically linked binary that
     includes system libraries outside our control, open source that needs
     to be patched, fbcode, etc., this could prove difficult.

  2. Always execute an FPU resetting instruction before transitioning from
     TC code to C++. For all I know, these instructions are cheap, but it
     still seems like an unfortunate overhead to impose everywhere; since
     we don't want to mark every helper with a "reset fpu" call, we'd
     probably end up bloating callsites.

  3. Admit this doesn't work.

In the absence of evidence this matters for perf, I lean towards 3.
2013-03-25 13:31:17 -07:00
mwilliams 4c6cb0a577 Fix getContextClassName and getParentContextClassName
They both returned the late static bound class, not the context
class. This meant that eg "constant('self::FOO')" was actually
returning what "constant('static::FOO')" should have done.

In addition, we often want the Class*, not its name, so
change them to return Class*. The remaining places that then
read the name from the Class* should be fixed to use the Class*
directly (in a later diff).

Finally, noticed that while "defined()" was recently fixed to
support "static::", "constant()" was not. Pulled out a common
function to find the correct Class*.
2013-03-25 13:31:17 -07:00
mwilliams b387d70e70 RetC needs to zero ActRec::m_this before destroying it
In the case where m_this was already in a register,
and known to be non-zero, we would fail to zero the ActRec's
m_this field, which could result in a dangling reference
to $this being captured by debug_backtrace.

Put the store on the presumably cold path. Fix DecRefThis to
do the same.
2013-03-25 13:31:16 -07:00
smith 768a8bd238 Fix type-puns in FCallBuiltin
Avoid punning TypedValue* to String&/Array&/Object& in FCallBuiltin
(all three implementations).  Our native function calling conventions
require passing pointers into a TypedValue for these types, and
pointers-to-scratch for return values.

In the HHIR case, I removed the optional "return pointer" argument
from the IR CallBuiltin instruction.  The C++ value-passing ABI details
are now handled in cgCallBuiltin and are no longer exposed in the IR.
The argument types are still PtrTo*, but we handle the address fixups
in CodeGenerator.
2013-03-25 13:31:16 -07:00
ptarjan a5b7b243d6 add test
Never shall this happen again
2013-03-25 13:31:16 -07:00
ottoni 659da8c6b1 Fix assertion in ref-count optimization
MemElim may transform the source of a DecRefNZ into a constant,
so we shouldn't assert that it's coming from an IncRef.
2013-03-25 13:31:16 -07:00
Alex Suhan b41346c929 Fix ext_asio callback checks
The callback passed to asio_set_on_{failed, started}_callback was
never null because the way types for input parameters work in
extensions. Null from user PHP code was converted to a stdClass
object, triggering an exception.
2013-03-25 13:31:09 -07:00
hermanv e778550bef Break up IR ConvToArr into sub opcodes.
ConvToArr has at least two variants: one that holds on to the object being converted and the other that does not. Having separate opcodes allow this distinction to be made. Making separate opcodes for each type of operand makes for a more consistent IR.
2013-03-25 12:44:12 -07:00
ptarjan 6b61441bd9 more isStatic fixed for closures
The interpreter fix was different than the jit/ir fix because ##translateFPushObjMethodD()##'s ##i.inputs[0]->rtt.valueClass()## is null (with a TODO in the code to make it not null). It then goes into the slowpath.

Another one like this and I think I should have a different attribute for static closures :(
2013-03-25 12:44:12 -07:00
jan 10b770d342 Simplify hphp_unpack_continuation
Do not generate yield labels as normal goto labels in the parser. Create
them at YieldExpression and use m_yieldLabels array in emitter.
2013-03-25 12:43:42 -07:00
jan 06713e6226 Eliminate transform_yield_break()
The only places where ReturnStatement is constructed are:

- onReturn(check_yield=true) -> not allowed in generator
- onReturn(check_yield=false) -> coming from transform_yield_break, right after creating hphp_continuation_done()
- MethodStatement, end of function call -> hphp_continuation_done() is created at end of generator in prepare_generator()

Emitter is emitting ContExit in ReturnStatements used in generators. As
can be seen from the analysis above, it's always preceded by emitting
ContDone from hphp_continuation_done(). Let's emit ContDone inside the
ReturnStatement directly and kill usage of hphp_continuation_done().

transform_yield_break() becomes a simple onReturn(check_yield=false), so
let's inline it into onYield and create ReturnStatement directly. After
this change, check_yield flag is always true and can be killed.

ContExit was also used after emitting a generator method in case the end
of method is still reachable. ContDone is added so that the generator is
properly closed. I believe this is never actually used, as MethodStatement
creates ReturnStatement at the end of method anyway.
2013-03-25 11:31:17 -07:00
ptarjan 5ce11ce940 get static locals from the first local AFTER the params
I directly copied continuations for this, but they never have params. Closures sometimes have params, and the closure itself will be the first local AFTER those.
2013-03-25 09:49:51 -07:00
alia c3130d24f6 Added DecRefNZOrBranch and basic memory tracking to enable additional IncRef-DecRef elimation for Set[S,G,M].
Added a new IRInstruction, DecRefNZOrBranch, that decrefs but
branches out of the trace if the reference count is about to go to
zero. This guarantees that no destructor will run, and thus no memory
side effects on trace. Tracked the last value available in memory in
TraceBuilder and used it to convert DecRef instructions to
DecRefNZ. These 2 changes allow us to eliminate more IncRef-DecRef
pairs, in particular cases due to SetS, SetG & SetM; for example:

85: SetS
    (20) t12:Cls = LdStack<Cls> t10:StkPtr, 1
    (21) t13:Str = LdStack<Str> t10:StkPtr, 2
    (23) t15:PtrToGen = LdClsPropAddr t12:Cls, t13:Str, Cls(0)
    (24) DecRef t13:Str
    (25) t16:PtrToCell = UnboxPtr t15:PtrToGen
    (26) t17:Cell = LdMem<Cell> t16:PtrToCell, 0
    (27) t18:Obj = IncRef t11:Obj
    (28) StMem [t16:PtrToCell]:Obj, t11:Obj
    (36) DecRefNZOrBranch t17:Cell -> L4
  L5:
    (38) DefLabel
  86: PopC
    (39) DecRefNZ t18:Obj

In the above example, memory tracking and DecRefNZOrBranch allowed us
to change instruction (39) from a DecRef to a DecRefNZ. Subsequent
dead-code elimination will remove the IncRef instruction (27) and
DecRefNZ instruction (39).

This diff does not handle SetM.
2013-03-25 09:49:51 -07:00
jan 7b7343b56a Introduce YieldExpression
Unhack the parser and introduce YieldExpression that emits the
equivalent set of opcodes that were emitted by bunch of
expressions/statements generated by parser before.

YieldExpression expects evaluation stack to contain just the value
being yielded, so {,List}AssignmentExpression need to evaluate RHS
first. The previous code had the same behavior.

This will let us consolidate continuation-related opcodes and make
them less tied with continuation objects.
2013-03-22 13:01:05 -07:00
jan 8fa1c51ee8 Fix ref generator parameters
Alias manager does not know whether generator parameters are passed by
reference. This didn't matter, because every generator had at least one
function call (hphp_continuation_done()) that pretty much disabled unused
variable elimination.

This diff fixes that, lets us get rid of artificial function calls in
generators and will allow later improvements in alias manager.
2013-03-22 11:48:50 -07:00
mwilliams 8ad18a7be9 Filter strict_warnings like notices
There is a runtime option to filter out notices and warnings,
but strict_warnings were left out. Bundle them with notices.

We raise a lot of strict_warnings; and when we fix hphpiCompat
(to match zend better) we will raise a lot more, so this could
matter.
2013-03-22 11:48:50 -07:00
bsimmers 7219dec255 Implement more final operations in VectorTranslator
Most of this is pretty boring and mechanical. I added
VectorProp and VectorElem flags to help deal with the increasing
number of vector-related opcodes.
2013-03-22 11:48:50 -07:00
ottoni 5e6a53319f Disable spilling into MMX registers 2013-03-22 11:48:50 -07:00
Drew Paroski e421b15e38 Update README.md 2013-03-21 22:01:03 -07:00
Drew Paroski fb520b5351 Update README.md 2013-03-21 21:59:48 -07:00
Drew Paroski ee8aa92547 Update README.md 2013-03-21 21:58:41 -07:00
Drew Paroski eabe841fcd Update README.md 2013-03-21 21:53:37 -07:00
Drew Paroski 90a5b30639 Update README.md 2013-03-21 21:51:58 -07:00
Drew Paroski 450a0fb2f5 Update README.md 2013-03-21 20:48:14 -07:00
Drew Paroski 1dbb3c6423 Update README.md 2013-03-21 20:47:22 -07:00
Drew Paroski 6e030ca9d1 Update README.md 2013-03-21 20:44:37 -07:00
Drew Paroski 07504c37e8 Remove outdated info 2013-03-21 20:43:28 -07:00
jan f9765d1c58 Fix local propagation of generator parameters
Alias manager does not know that generator parameters are populated and
assumes they are uninit. The current code works because control flow
algorithm gives up while trying to deal with the continuation switch
statement full of gotos.

This diff fixes it by setting isGeneratorParameter flag in symbols
representing parameters of enclosing generator wrapper and use variables
of enclosing closure.
2013-03-21 19:33:53 -07:00
aravind 7a58a78ef1 Don't handle signals in non-HPHP threads
This is not correct, as we are dropping signals because
they got sent to non-HPHP threads.
2013-03-21 19:33:53 -07:00
jan fcb32cf8ac Kill needs{ObjTemp,RefTemp,CheckMem} and cppTemp 2013-03-21 19:33:53 -07:00
kma 4fcf2ec200 Get rid of a dead load from some tx64 unboxes.
Slight change to assign operations that affect the inner type.
This gets rid of an unnecessary load in some cases. I have little evidence
that this is practically important, but when debugging on 7pack I found the
dead load confusing.
2013-03-21 19:33:53 -07:00
hermanv c23fe753c5 Fix refcounting problems in convToArr.
This set of changes fixes problems pointed out in earlier diffs by Ed and Brett, mostly centered on redundant ref counting. It will be followed up by another diff that does a mechanical refactor to introduce variants of convToArr, specialized on the types of it operand.
2013-03-21 19:33:53 -07:00
philikon d79cb16bfe Implement UConverter::getStandardName()
Making ucnv_getStandardName() available as
UConverter::getStandardName().
2013-03-21 19:23:54 -07:00
mwilliams 737a8c87b1 Cleanup more unused code in Continuation
m_method was unused, and __construct had a couple of
unused parameters. Also bring the idl back into sync.
2013-03-21 17:52:28 -07:00
Owen Yamauchi b5a11c6139 Fix the RIP_REGISTER macro
Pretty simple. This makes me slightly nervous because I've only
confirmed it works in my stupid OpenEmbedded ARM SDK; a different Linux
might call this something else. But we'll cross that bridge when we get
to it, and this works for now.

I'm also sneaking in a change to remove x29 from the list of
callee-saved regs; I put it in there by accident last time.
2013-03-21 17:31:37 -07:00
jan 06aefe7e37 Remove deprecated support for priority in ContinuationWaitHandle::start()
PHP code does not use this anymore. Let's remove the support.
2013-03-21 17:31:09 -07:00
jan 6d3f04d0a9 Remove deprecated yield array(...), try #2
Our PHP code no longer yields arrays. Remove.
2013-03-21 16:51:06 -07:00
ptarjan a6d70040fa fix static closures
I added the check for this in the interpreter but ##f_array_map## re-enteres the VM via a different path than FCall. Here is the equivilent check for the VM.
2013-03-21 16:51:06 -07:00
mwilliams 9c78f77577 Fix args for embedded repo
When we generate a binary with an embedded repo,
we add various args (-vRepo.Authoritative etc) to the end
of the command line. But the argument "--" is taken to mean
"pass the rest of the args to the script". So if you use
"--" on such a binary, it gets rather badly broken.

Reorder the args so that the inserted ones come first.
2013-03-21 16:50:55 -07:00
mwilliams 97eb859975 Remove unused nextImpl template from c_Continuation 2013-03-21 16:50:55 -07:00
ptarjan a1802db1d2 allow static keyword before closure
PHP added this in 5.4 so that you can say your closure shouldn't capture ##$this##. https://wiki.php.net/rfc/closures

Should we add it? Many of their unit tests use it.

Instead of putting a boolean somewhere I used the same attr framework and set the static bit there. Thoughts? It only needs one change in the ##FPushFunc##.
2013-03-21 16:50:55 -07:00
ptarjan 4d7004e955 :Allow $this on closures
In Zend 5.3 they decided that closures should inherit the ##$this## from the containing scope. This brings us close to paraity with them. The remaining thing is to make

    function() use ($this) {}

fatal after we purge it from WWW.
2013-03-21 16:50:12 -07:00
hermanv 3718c612ed Split Conv<T> into type specialized ConvToArr, ConvToBool, ConvToDbl, ConvToInt, ConvToObj and ConvToStr instructions.
This is a "mechanical" refactoring that is not supposed to introduce any new behavior or to fix anything. It sets the stage for further changes that will reduce the number of places where code generation punts.
2013-03-21 16:13:35 -07:00
jdelong dd71b738dd Fix ODR violation in TestExtCurl
TestExtCurl was failing in the fbmake build, because for some
reason the other TestServer was being used.  AFAICT it's within the
compiler's rights to do whatever it wants here, though.
2013-03-21 16:13:21 -07:00
hermanv 186882bae7 Add more unit tests for conversion operations.
A batch of small sanity tests for the new conv instructions.
2013-03-21 16:13:21 -07:00
chip f258edcbc5 Re-enable millisecond mysql timeouts 2013-03-21 16:13:21 -07:00
mwilliams 1d68430f6a Always setup Repo paths in hphp mode
We didnt do it for the analyze target, for example,
which resulted in hphp hanging on some machines due to
trying to create ~/.hhvm.hhbc
2013-03-21 16:13:21 -07:00
bsimmers 62710cb083 Disable flaky TestExtPdo-test_pdo_mysql 2013-03-21 16:13:20 -07:00
ptarjan cc37fe637a add Callable typehint
php-5.4 has it http://www.php.net/manual/en/language.types.callable.php
2013-03-21 16:13:20 -07:00
ottoni 041d737d3f Avoid storing to the stack the same value just loaded from there
Sometimes SpillStack and Call end up storing onto the stack a value
that was just loaded from the same stack location.  There was already
code in cgSpillStack to avoid the extra stores in some cases, but that
still kept the LdStack alive.  This diff detects some of those cases
with SpillStack in the Simplifier, which allows the LdStack to be
eliminated by DCE.  This diff also adds similar support for Call.  The
operands that don't need to be store onto the stack are replaced with
None.

Note that the optimization in cgSpillStack is not subsumed by this
diff.  In the Simplifier, we cannot chase through IncRefs as done in
cgSpillStack -- that would result in an IncRef that is not consumed.
2013-03-21 16:13:20 -07:00
jdelong d44f93f14e Remove unused buildTarget function in compiler.cpp 2013-03-21 16:13:06 -07:00
jan c2b38ad2b1 {,List}AssignmentExpression: add support for RHS first evaluation order
Add a flag to {,List}AssignmentExpression that changes evaluation order
to RHS before LHS.

This will be used by YieldExpression.
2013-03-21 16:13:06 -07:00
Alex Suhan 1742a79189 Add on started callback to AsioSession
The PHP code using Awaitable interface will need this.
2013-03-21 15:55:58 -07:00
jdelong 6f82cce043 Update Setprofile test 2013-03-21 15:17:33 -07:00
mwilliams cbf041b01b Remove Option::OutputHHBC and Option::SystemGen 2013-03-21 15:17:33 -07:00
ottoni d996ae0065 Fix HHIR simplification for missing bool-to-int promotions
The simplifier was not promoting the boolean to integer in some
cases. I hit this for the add-zero case, and code inspection revealed
similar bugs in sub-zero and multiply-one cases.
2013-03-21 15:17:24 -07:00
mwilliams 63f228d614 Fix nemo warnings about undefined $this
The fix for the crash caused us to take a different path
when checking locals.
2013-03-21 15:17:24 -07:00
Alex Suhan 903a2444bc Add Awaitable interface
Our PHP code can be simplified by using a common interface
instead of relying on instanceof for proper dispatch.
2013-03-21 15:01:49 -07:00
jdelong 90fa863d44 Put compiler_id in a .cpp file on every link line, remove generated/
Instead of stashing compiler_id in a header that causes rebuilds,
regenerate on every build and list on every link line,
without depending on them.
2013-03-21 14:07:59 -07:00
kma 8c980d31d1 Fix a pair of missing emit*TVType calls.
Reviewing the diff between feature and trunk revealed these two
instructions that still hardcode dwords for types.
2013-03-21 11:31:29 -07:00
jan 2db40741d0 Remove transform_foreach
Iteration opcodes work with locals that are correctly suspended/resumed
thru yield, transform_foreach not needed anymore.
2013-03-21 11:31:29 -07:00
jan 2ebb2a93a1 Eliminate {get,set}NthKid() usage with known specific kid
{get,set}NthKid() should be only used to walk thru all the kids and not to get/set a known specific kid. Replace its use by direct helper method.

All remaining callers of {get,set}NthKid() were audited and there are no instances left accessing specific kid.
2013-03-19 14:11:17 -07:00
bsimmers 3f829f3ede Print relative offsets in Eval.JitCompareHHIR
This diff adds a relativeOffsets option to Disasm, which will print
code addresses as relative offsets from the beginning of the tracelet instead
of absolute addresses. This format makes it much easier to compare the relative
sizes of the instructions selected by the two jits. I also changed the runtime
option to be a double instead of a bool, which is used as the cutoff ratio for
which tracelets to print. Setting it to 1 will print tracelets where the ir
made larger code than tx64, setting it to 2 will print tracelets where the ir's
code is at least twice as big as tx64's, etc...
2013-03-19 14:11:16 -07:00
bsimmers 02e0774721 Implement support for stack bases in VectorTranslator
Any vector instructions that take a pointer to a base and might modify
it are now flagged with MayModifyStack. Any that actually do modify the stack
(this can be determined by looking at the input types) will produe two dests:
their original result and a new StkPtr. getStackValue calls into VectorEffects
to extract the new type and/or value. The instructions currently assume that
the stack cell they might be modifying is already synced to memory. This may
change in the future when we don't have to do a full SpillStack before the
helpers.
2013-03-19 14:11:16 -07:00
bsimmers ea56a8383e Implement specialized array setting in VectorTranslator
This mimics what TranslatorX64 does in translateSetMArray,
but it does it with fewer helpers and (often) fewer instructions in
translated code. I also found a bug in both jits and the interpreter
when dealing with arrays that hold refs to themselves. The new test
case exercises the fix, which involved a bit of refactoring of the
refcounting logic.

Enabling VectorTranslator while punting to tx64 is no longer a
regression so I removed the punt in emit().
2013-03-19 14:11:16 -07:00
smith c3a15af2e5 Re-Tighten live register calculations
Compute the registers that are live across each IR instruction, rather
than the live-out set.  I noticed this while working on a fix for the
CallBuiltin instruction.

We currently compute which registers are live-out from each instruction,
then use the sets to push/pop callee-saved registers around native calls.
cgCallHelper() has a hack to remove destination registers from this set,
but it's not always precise, because we sometimes call cgCallHelper with
different dest registers than were assigned to the instruction, which
(rarely) can cause unnecessary spilling.

In one case cgLdClsMethodFCache(), one of the src tmps is copied to a
destination before the internal call; in that case the dst is not live
across the whole instruction but the value must still be preserved
across the call.  Easy fix: mark it live before cgCallHelper().
2013-03-19 14:11:16 -07:00
Owen Yamauchi 36afbda910 Introduce callee-saved-regs clobber macro
Self-explanatory. The list of callee-saved regs on ARM comes from the
ARMv8 Procedure Call Standard.
2013-03-19 14:11:16 -07:00
alia 9690cc4f52 Fixed problems with HHIR's LdObjMethod instruction
This diff fixes problems with FPushObjMethodD stack unwinding, to HHIR.
This diff simply moves the try-catch into the methodCacheSlowPath.
This should also improve the code generated by gcc for the fast path.
2013-03-19 14:11:11 -07:00
hermanv b3b767d6b2 Initialize local that receives an error code only if there is actually an error.
uidna_openUTS46 overwrites its error code argument only if
there is actually an error. Hence, if the variable is not initialized to
zero it may seem to the calling code that an error has ocurred. This
diff initializes the variable and re-enables the failing test.
2013-03-19 14:11:11 -07:00
mwilliams 63fd7967b2 Fix StringBuffer::resize()
capacity doesnt include the terminating null, so len is
allowed to grow to capacity (not capacity - 1).
2013-03-19 14:11:11 -07:00
mwilliams d8846c5733 Fix assertion when target==analyze
Option::OutputHHBC should always be true.
2013-03-19 14:11:11 -07:00
andrewparoski a8b6ba6962 Implement Tuple
Implement a Tuple class as part of collections.
2013-03-19 14:11:00 -07:00
alia ea03ae9b15 HHIR: Optimized useless incref-decref pairs.
Incref-Decref pairs whose incref'ed SSATmp is not used by any
other instruction other than the decref can be eliminated when the
type of the refcounted value has no destructor (i.e., strings and
boxed strings). This commonly occurs for stores to memory (e.g., SetS,
SetG, and SetM) followed by PopC.

For example:

  47: SetS
    (32) t16:PtrToGen = LdClsPropAddrCached t9:Cls, "s1", "c", Cls(0)
    (33) t17:PtrToCell = UnboxPtr t16:PtrToGen
    (34) t18:Cell = LdMem<Cell> t17:PtrToCell, 0
    (35) t19:Str = IncRef t15:Str
    (36) StMem [t17:PtrToCell]:Str, t15:Str
    (37) DecRef t18:Cell
  48: PopC
    (39) DecRef t19:Str

In this example, eliminating the DecRef instruction (39) along with
its IncRef (35) may cause the string referenced by t19 to be destroyed
earlier in the DecRef instruction (37), but this is safe because
destroying strings has no visible side effects.

This diff eliminates these pairs.

Note that its not safe to do this for types that have destructors with
side effects. Applying this optimization to decref'ed types that have
destructors could change the order of those side effects with respect
to the side effects in instruction (37). A follow-on diff will change
the DecRef (37) to bail the trace when it has to run a destructor to
enable this for the general case.
2013-03-19 13:04:09 -07:00
mwilliams c489379fca Most constructors return null
So annotate the PopR to avoid generating code.
2013-03-19 13:04:09 -07:00
Owen Yamauchi 0323ec38e5 Fix includes in curl_tls_workarounds.cpp
raise_notice() wasn't declared in this file, so include runtime_error.h.
This caused further problems with ATTRIBUTE_PRINTF not being defined
yet, so include some more stuff.
2013-03-19 12:44:39 -07:00
Sara Golemon 1f19c6f051 SSL_OP_NO_TLSv1_2 is not supported by all openssl versions 2013-03-18 18:18:26 -07:00
ottoni 389fa818a9 SIMPLIFY_COMMUTATIVE only handles Type::Int
So check that the inputs are really Ints.
2013-03-18 18:18:26 -07:00
bsimmers 322f6b1b3b Disable test/vm/idn-uts46-errors.php 2013-03-18 18:18:26 -07:00
aravind 647d306c96 Don't simplify Same to Eq to arrays 2013-03-18 18:18:26 -07:00
aravind 42e3a2a7b1 Call IncDecHelper only for Ints 2013-03-18 16:06:01 -07:00
smith 884ff2d218 Use IRExtraData to link ExitTrace[cc] with smashable jumps
Use a new ExitData subclass of IRExtraData to link ExitTrace[Cc]
with the Jmp or Jcc that ends the trace, so the Jmp/Jcc can be
smashed later.  SSATmps should represent runtime values, whereas
these instr->instr pointers are for internal compiler use.
2013-03-18 16:06:01 -07:00
aalexandre 505c17f357 replaced null with uninit_null() 2013-03-18 16:05:53 -07:00
bsimmers 5759bd051b Add assert_throw and assert_log
This diff introduces assert_throw, assert_log, and always_assert_ versions of
the two. They behave similarly to assert, but assert_throw throws a
FailedAssertion exception instead of calling abort. This lets us catch the
exception and add additional debug info to the stacktrace file. In the case of
the IR, this is the current Trace. assert_log takes the condition to check and
a lambda that is expected to return a std::string. If the condition fails, the
lambda will be evaluated and the text returned will be included in the
stacktrace file.

I've left assert_throw off by default so people have to opt into it
locally or in Perflab (see the comment in assert_throw.h)
2013-03-18 15:12:16 -07:00
ottoni e2b5b1f6f4 Eliminate IncRef/DecRef pair when returning a local
In case a tracelet ends with CGetL + RetC, and IncRef/DecRef pair is
generated for the local being returned if it's ref-counted.  The
current ref-count optimization pass was unable to eliminate this, and
this diff tweaks the way HhbcTranslator generates the IR to enable the
optimization to kick in.

Here's the pattern generated without this diff:

CGetL 0
 t0 = LdLoc 0
 t1 = IncRef t0
RetC
 ExitWhenSurprised -> L
 DecRef t0
 RetVal t1
 ...

The source of t0 is not an IncRef, so the optimization doesn't apply.

With this diff, the IR is generated as:

CGetL 0
 t0 = LdLoc 0
 t1 = IncRef t0
RetC
 ExitWhenSurprised -> L
 DecRef t1
 RetVal t0
 ...

This enables the DecRef to be proved non-zero (becoming a DecRefNZ),
so it can be eliminated and the IncRef is sunk to the exit at L.
2013-03-18 15:12:16 -07:00
michalburger1 4858b29f95 Fix bzdecompress
Bad memory allocation, the buffer needs to be large enough to fit all
the data we've decompressed so far plus the extra storage we're
incrementally allocationg, not just the incremental part.
2013-03-18 15:12:16 -07:00
alia 59e537b127 Inlined the fast-path of FPushObjMethodD in the IR.
Inlined the fast-path of FPushObjMethodD in the IR from
MethodCache::lookup. This should reduce the number of times we call
the MethodCache::lookup helper by inlining the common case where the
object's class hits in the target cache.
2013-03-18 15:12:16 -07:00
hermanv 71ea0755d2 use s_self rather than a string literal
Use s_self, s_parent and s_static instead of "self", "parent" and "static" in f_defined.
2013-03-18 15:12:15 -07:00
Sara Golemon 0c912a4d7e Fix typo and timing of setting User-Agent header in http wrapper
$context['user_agent'] was only being respected if
other headers happened to be getting set as well.
Even then, the header being set was "User_Agent" rather than
the correct "User-Agent" version.
2013-03-18 15:12:15 -07:00
Sara Golemon 2027ae7e7e array_keys($arr) and array_keys($arr, NULL) should behave differently
In Zend, the latter form only returns keys which have a NULL
(or NULL-like if $strict==false) value.  The former returns all keys.
2013-03-18 15:12:15 -07:00
Owen Yamauchi f82de49886 Get rid of third-party XHP since it's actually part of the parser 2013-03-18 10:30:25 -07:00
jan 1ecf21f22b ListAssignment: define RHS kind explicitly for all expression types
It's easy to introduce bug by adding a new expression and not defining
its ListAssignment RHS kind. Add all expression types explicitly and
remove default case so that it becomes compile time error if the list is
not updated.
2013-03-15 09:07:36 -07:00
jan e7c6c0cf78 s/m_contTargets/m_controlTargets/ in emitter.{cpp,h}
contTargets name is misleading and suggests it has something to do with
continuations. Rename it to controlTargets.
2013-03-15 09:07:36 -07:00
bsimmers c7b5bbbb34 Fix the release build 2013-03-15 09:07:30 -07:00
bsimmers 0f9b92c2bb Implement known property offsets in VectorTranslator
This diff implements VectorTranslator::emitPropSpecialized and uses it
in three places: emitProp, emitSetProp, and emitCGetProp. The new test case in
test_code_run.cpp used to crash TranslatorX64; now it throws a fatal to keep
things simple. VectorTranslator has better control flow support at its disposal
and is able to get that case right.
2013-03-15 09:07:30 -07:00
bsimmers e580483214 Disable flaky tests in TestExtFile and TestExtImageSprite 2013-03-15 09:07:30 -07:00
smith 5dc84aac72 Remove ffi 2013-03-15 09:06:48 -07:00
kma 82326d7ec8 Access m_type via helpers.
We had the belief that m_type as an int32_t (and in at least one
place, an int64_t) burned in many places. This is going to make any kind of
re-encoding of TypedValues nearly impossible.

Redirect all such accesses via some helpers, so e.g.

        a.  cmpl(KindOfUninit, base[TVOFF(m_type)]);

becomes

       emitCmpTVType(a, KindOfUninit, base[TVOFF(m_type)]);

which may do byte or dword access, depending on m_type's actual size. While
this is motivated by 7pack, I'm planning to route it through trunk to
prevent any more of the old style accesses from cropping up.
2013-03-15 09:04:34 -07:00
mwilliams 6a867726b1 Don't use long double
Slots in the x87 stack get marked as occupied when you move
values into the corresponding mmx registers. If you try
to push a value onto the x87 stack, and the slot isnt empty,
it will fail, and give you a nan.

Generally, g++-x64 doesnt use the x87 instructions, but if
you do long double arithmetic, it does. f_pow was using
long doubles - but there was an alternate, much faster, asm
sequence which didnt use long double, and which just needed
to test the right define - so switch to that. Also grep
for long double to make sure we're not using it elsewhere.
2013-03-15 09:04:34 -07:00
bsimmers d25af371b9 Restore short aliases for DestType enum in nativecalls.cpp
The new names were causing a bunch of merge conflicts and
reduced the signal to noise ratio of the table. This is completely
contained within nativecalls.cpp; the new enum scope is preserved
everywhere else.
2013-03-15 09:04:34 -07:00
smith 693dc1e1be Add new DestType enum for helpers that return TypedValue.
This is necessary because without it, the only clue we have about
what return type a helper has, is the register assignments of the
destination SSATmp.  It is possible that even though the helper returns
a TypedValue, we might only have dest registers assigned for one part
or the other part.

Lastly, we could end up having helpers that return other two-register
results, which shouldn't be confused with TypedValue.

Also fixed cgFCallBuiltin() to use the correct size test
instruction when computing on types.  Types are currnetly 32bits
and the other bits can be garbage.

Renamed ArgGroup.valueType() to typedValue() for clarity.  It's only for
passing TypedValues by value; other register-packed structs would
need new helpers.

Added more asserts in cgCallHelper based on the return type.
assert if we assigned a register but DestType implies there's no
such value (e.g. assigning a void return to a register).
2013-03-14 14:27:22 -07:00
ottoni ba2cf21ec9 Properly patch exit traces ending with JmpZero and JmpNZero
The hoistConditionalJumps pass was not handling traces ending with
JmpZero and JmpNZero.  This was resulting in spurious jumps to
'astubs' instead of patching the jcc+jump pair in 'a'.
2013-03-14 14:27:22 -07:00
mwilliams f7b802c872 Use lookupUniqueClass
The translator does better in a number of places when it
knows an AttrUnqiue Class* at translation time - even if it
doesnt know for sure that it will be defined when we enter the
tracelet. Now that we autoload (nearly) everything, we enter
a lot of tracelets where an AttrUnique Class* has been seen
(during warmup) but is not yet defined (in this request).
I added lookupUniqueClass while working on the new autoloader
to find such Classes, and allow us to do a better translation,
but never got around to using it.
2013-03-14 14:27:22 -07:00
ptarjan bc49d78100 tell closures about scope clones
In HHBC mode, traits are flattened into their classes.
When that happens, closures need to know about all the
classes that contain them so that when we find a ##$this##
inside the closure, it can tell EVERY containing scope to
please propogate ##$this## down to me.
2013-03-14 14:27:22 -07:00
kma 35bd9acebb Minor assembler enhancements. 2013-03-14 14:27:22 -07:00
andrewparoski cc858b73db Collections updates
Replace "collection" with "collections" in various file names since
we typically use the plural form in conversation and documentation.

Add set() and removeAt() methods needed for collection interfaces. Also
add the KeyedIterable and KeyedIterator interfaces.

Add __construct() methods for collections
2013-03-14 14:27:16 -07:00
mwilliams 731a3fcd23 Fix emitInterceptProlog
When the compare was rewritten for the new assembler syntax
it was accidently changed from being a compare of the byte
pointed to by rax, to a compare of the low byte of rax.

I also noticed that by loading the Func* into rax, and doing
a compare against rax[Func::maybeInterceptedOff()] we can
skip a subsequent mov of the Func* into rax.

The code was only slightly broken because we set everything
to be interceptable up front, (if EnableRenameFunction is on)
because we had too many issues with the invalidation code. The
bug was that if the Func happened to be allocated at a multiple
of 256 bytes, it wasnt interceptable.

Also, the existing code looked silly,

  mov  $abcdef45, $eax
  cmp  0, $al

and the new code is smaller.
2013-03-14 11:41:16 -07:00
ottoni a7dc6b461c Reenable direct branch patching for ExitTraceCc
It looks like the pattern-matching performed in
hoistConditionalJumps() was not updated when control-flow support was
added, so the optimization was missing opportunities.
2013-03-14 11:41:16 -07:00
mwilliams b67c2239ed Simplify classof
We dont need to check whether the first Class* is
an interface or trait.

If the second class is an interface or trait, we
take the slow path. Otherwise, we take the fast path,
which will always return false if the first class is
an interface or trait (its m_classVec can only contain
interfaces or traits, while cls's m_classVec can only
contain non-interfaces and non-traits).

This saves doing the check, and avoids the slow path
in the case where the class being tested  is an interface
or trait.
2013-03-14 11:41:16 -07:00
mwilliams 97cf4e0e06 Limit the number of blocks handled by TraceBuilder::optimizeTrace
It appears to be O(N^3) in the number of blocks (a quick glance
at the code suggested N^2, but 1000 blocks took about .5s to process
while 2000 blocks took 4; 19000 blocks was nowhere near finished in
an hour). A better representation of the dominators would probably
solve this - but would also take *much* more space.
Having more than 1000 blocks appears to be extremely rare, so
this seems like a reasonable solution for now.
2013-03-14 11:41:16 -07:00
mwilliams 1678132143 Fix CodeGenerator::cgNInstanceOf
It assumed the result would be in rax, but it isnt always.
Use the correct register.
2013-03-13 09:56:35 -07:00
andrewparoski c1e4c29d0d Some ObjectData/Variant cleanup and dead code removal
This diff eliminates setOpEqual() and appendOpEqual() from Variant, and
it also removes several methods from ObjectData: o_assign_op(), o_argval(),
setDummy(), init(), cloneDynamic(), o_setPublicWithRef(), o_i_set(),
getRedeclaredParent(), and o_propForIteration().

This diff also makes several methods in ObjectData non-virtual: destruct(),
o_toIterArray(), and o_getDynamicProperties(). To achieve this, some of the
logic from Instance was moved to ObjectData.

Finally, this diff gets rid of "hhvm/externals_stubs.cpp" and
"runtime/eval/eval.cpp".
2013-03-13 09:56:28 -07:00
bertrand 97010deac1 Fixed ContNext by writing InitNull rather than Uninit.
Apparently, m_received needs to be InitNull, rather than
Uninit.
2013-03-13 09:53:58 -07:00
mwilliams 4514a79c60 Remove ReqSrc and ReqMod
They can no longer be generated. Also remove all the associated
code from the emitter.
2013-03-13 09:53:58 -07:00
Sara Golemon 6169f73d80 TCP ports should be unsigned 16 bit integers.
Summary:
Specifying Signed 16-bit Int in HDF parsing
prevents use of any port greater than 32767.

Test Plan: Run a server on port 40000

Reviewers: andrewparoski, jdelong, smith, kma, mwilliams

Reviewed By: jdelong

CC: hphp-diffs@lists, ps, ottoni, aalexandre

Differential Revision: https://phabricator.fb.com/D735202
2013-03-12 14:46:38 -07:00
hermanv 96350d1a66 add support for late bound constants to the defined function
The defined function did not have code to deal with "static::const" expressions. Added the necessary logic.
2013-03-12 14:22:14 -07:00
mwilliams f51b3c302b Remove some more dead code 2013-03-12 14:22:14 -07:00
bsimmers 6366959956 Implement VectorTranslator::emitSetNewElem and emit(Empty|Isset)Elem
Three more straightforward vector operations.
2013-03-12 14:22:14 -07:00
mwilliams a7a3c2e8cc Get rid of hphpc's switch helpers
hashForIntSwitch and hashForStringSwitch were used as part of
an efficient switch mechanism in hphpc, but are now dead.
2013-03-12 14:22:14 -07:00
andrewparoski 9df492da6a Update inconsistencies doc
Remove HPHPc-only inconsistencies from the inconsistencies doc. Also,
clarify the wording to make it clear we are comparing HipHop VM with the
Zend PHP engine.
2013-03-12 14:22:14 -07:00
ottoni 8b36e4b067 Enable branch fusion for [N]InstanceOfBitMask
This translates to a single 'testb' x86 instruction, so it's cheap
even if we end up redoing it.
2013-03-12 14:22:14 -07:00
bsimmers 518ae943da Enable VectorTranslator::emitRatchetRefs
The code was mostly already there, it was just waiting for
proper control flow support.
2013-03-12 14:22:14 -07:00
bsimmers f5b168643d Implement support for boxed bases in VectorTranslator
Nothing too fancy here. genLdLocAddr now takes an optional
exit trace to guard the inner type of the local.
2013-03-12 14:22:14 -07:00
bsimmers 4b075be2ee Add stronger assertions when killing IncRefs in dce
This diff changes DceFlags to be an opaque struct, and uses
the new decRefNZed flag to ensure that we don't kill any IncRefs
unless they're consumed by a DecRefNZ in at least one path. This
doesn't catch all cases of malformed IR, but it catches common
mistakes, including one in the vector translator that I just spent 2
days hunting down.

A couple things came out of this:
- dce now removes unreachable code before performing the real dead
  code analysis, since any unreachable IncRefs should be killed
  regardless of what consumes them.
- I found a bug in memelim where it wouldn't properly account for
  Uninit -> InitNull promotion when boxing a local. The fix for this
  was to never emit "Box Uninit".
2013-03-12 14:22:14 -07:00
bsimmers 51f986a0ae Implement VectorTranslator::emitElem
I'm going to pull my big vector translator diff apart into
more manageable chunks, both to keep things simpler and help me
debug. This is part 1.
2013-03-12 14:22:14 -07:00
jdelong e8d372f813 Fix gzinflate for strings larger than 128M
gzinflate tries to do some kind of exponential growth that
hits the max string limit immediately when you try to deflate a string
larger than 128 megs.  The logic is a little convoluted with a few
ways to bail, but rather than try to really fix it I just made it
behave close to the same on small strings, but use a smaller starting
factor on long ones and be willing to try to deflate it into a
max-sized string.
2013-03-12 14:22:13 -07:00
andrewparoski 6ddef58d56 Remove LVariableTable, RVariableTable, and getHphpBinaryType()
This diff removes LVariableTable, RVariableTable, and getHphpBinaryType().
It also consolidates some of the include logic that was spread across
multiple files.
2013-03-12 14:22:13 -07:00
smith 6434422e85 Encapsulate access to m_aux in TypedValueAux subclass.
Access to TypedValue.m_aux must now be via TypedValueAux.  For now,
TypedValueAux is an empty subclass with accessors to m_aux, which is
now private.  Once RefData.m_tv is moved out from under RefData._count,
we can move TypedValue.m_aux to TypedValueAux.

Removed unnecessary initialization of m_aux.u_hash from c_Vector.
2013-03-11 21:19:20 -07:00
Sara Golemon aa3124d64d Set/Unset DEBUG/NDEBUG as appropriate
For a debug build:
  cmake -DCMAKE_BUILD_TYPE=Debug .

For a release build:
  cmake -DCMAKE_BUILD_TYPE=Release .

If you never set CMAKE_BUILD_TYPE, the default will remain "Release"
2013-03-11 21:19:20 -07:00
smith b4085ff17b Fix missing zero-extend when passing bool as TypedValue
If the argument was in the expected register, we failed to do the
zero-extension.  This showed up as a heisenbug when experimenting
with different TypedValue layouts, but could be causing other
stability problems in HHIR as well.
2013-03-11 14:26:34 -07:00
ptarjan 1bcb5de881 assert that func's IDs are valid
I got bit by a really nasty bug where I cloned a ##Func## and didn't set the ID. Then the JIT happily used it and I got really weird segfaults.

Making the ##m_funcId## private turned out to be really hard (~30 callsites) so @andrewparoski said the ##translate()## and ##retranslate()## were the most important places. We just have to remember to do it. If there are other important places I'll just bite the bullet and make it private with an accessor.

This should save days of many future engineers.
2013-03-11 14:26:33 -07:00
smith b5bebbb8b7 Remove ENABLE_HPHP_ARRAY flag (HphpArray is always enabled) 2013-03-11 14:26:33 -07:00
smith 20ac715ec2 Remove dead MutableArrayIter code plus a few cleanups 2013-03-10 13:54:36 -07:00
Sara Golemon a95a84390e Update IDL generators for int64 and extprofiles changes 2013-03-10 13:12:43 -07:00
Sara Golemon e0d098ef70 Add http_response_code(), behavior matching Zend 2013-03-09 20:23:28 -08:00
Daniel Sloof e3c7403906 Support $classname parameter to simplexml_load_string/file
Argument was being ignored.  Allow specifying
custom children of SimpleXMLElement.
2013-03-09 16:41:07 -08:00
bsimmers dd83c93a8a Remove DecRef's source from the cse table
DecRef needs to be the last use of its source, since it might
destruct it. In the new test case, the second cast expression was
reusing the result of the first (through CSE) after it had been
DecReffed and destroyed.
2013-03-09 15:07:50 -08:00
mwilliams 9c470aa8ed Convert remaining instanceof(litStr) to instanceof(litCls) 2013-03-09 15:07:50 -08:00
smith 1569061e8c Rename TypedValue._count to m_aux; Variant extends TypedValue.
This diff removes initializing stores to TypedValue._count, renames
_count to m_aux, and makes m_aux a union with members typed
and named according to their specialized uses.   The few remaining
uses of that field for random tweaks are more obvious and easy to
grep for.

TypedValue no longer extends Value, (allowing m_data to move to a
different offset in the future), and Variant now extends TypedValue,
so we only have to maintain one definition.

HphpArray now explicitly uses TypedValue.m_pad instead of overlapping
TypedValue with an anonymous struct, again so we don't have to maintain
another structure to match TypedValue's layout.

The JIT's were using offsetof(TypedValue, _count) all over the place
for access to String/Array/Object/RefData::_count.  Instead, use
FAST_REFCOUNT_OFFSET.
2013-03-09 15:07:37 -08:00
mwilliams e10f38e7fa Dont burn Func*'s into the tc
If its unit gets edited, the Func* could be freed,
and the memory re-used. The name and cachehandle /are/ fixed,
however. Burn those in instead.
2013-03-09 14:45:16 -08:00
mwilliams ba0cc6be65 Better instanceof checks
o_instanceof was doing class lookups on statically known classes.
Use the statically known Class* instead.
2013-03-09 14:44:00 -08:00
bsimmers 79af6e51fa Eliminate jumps to the next instruction at codegen time
Blocks consisting of just a Jmp_ instruction could result in
emitting jmp instructions to the immediately following
instruction. This was fairly simple to avoid.
2013-03-09 14:44:00 -08:00
jan 5ba5cb3761 IsCppAbstract: mark classes that cannot be subclassed in PHP
Previous deff introduced mechanism to avoid calling constructor of abstract class. In some cases, subclassing an abstract class on the PHP side makes sense.

Let's remove this limitation by introducing IsCppAbstract flag, so that only constructor of classes that are abstract in the C++ sense is not called.
2013-03-09 14:21:19 -08:00
hermanv 089caca5ea Generate code for a call to tvCastToArrayInPlace, rather than punt.
Extend cgConv with support for converting to an array. Except for the trival cases of converting null to an empty array and converting arrays to arrays, which are handled in Simplifier, the conversion is delegated to a helper that calls tvCastToArrayInPlace on its input parameter and then returns the embedded array that results from the call. The helper also increases the ref count of operand to convert since tvCastToArrayInPlace assumes that updating the typed value passed to it will result in one fewer referenced to the argument.
2013-03-09 14:21:19 -08:00
ptarjan 23b681e872 allow closures to be cloned
In HPHPc it didn't allow closures to be cloned but in HHVM it did. When I migrated to a C++ closure then i left the HPHPc code. Zend 5.4 allows them to be cloned so lets go with this.
2013-03-09 14:04:11 -08:00
ptarjan f1a3410eb5 make isMethod check the cls() for closures
For closures, I'm going to clone the ##__invoke## method and set the runtime ##m_cls## to be whatever the containing class was (or nullptr if there isn't one). Instead of finding all the callsites that decRef the ##ActRec##'s ##m_this## based on ##isMethod##, I think it is clenaer to make ##isMethod## reflect the state of the ##Func*##
2013-03-09 13:26:27 -08:00
ptarjan 4a3a5ccc6a add ClosureExpression::hasStaticLocals
closures will need to know at emission time whether there is a

  static $foo;

statement inside them, because if there is, the closure has to stick around to hold the static locals.
2013-03-09 13:26:27 -08:00
bsimmers 2776ebd221 Disable the hhir vector translator unless tx64 is disabled
There are a few code quality issues that affect the IR in
general but are magnified in the vector translator. I'm going to work
on fixing those, but in the meantime we're faster with it disabled
(while punting to tx64).
2013-03-09 13:26:27 -08:00
mwilliams 21dab1f587 Need to call xmlInitParser early
Its required if you're going to be using simple xml
from multiple threads.
2013-03-09 13:26:15 -08:00
bsimmers a06a7e07af Don't spill SSATmps that came from the same stack location they're going to
This is a very simple optimization to avoid some unnecessary
stores. In codegen for SpillStack, if the value we're going to spill
comes from a LdStack instruction corresponding to the spill
destination, don't spill it.
2013-03-09 13:26:15 -08:00
ptarjan c1c68516c1 add zend_closure_020
A good unit test that I think we should have.
2013-03-09 13:26:15 -08:00
ptarjan 477f8330d4 pass 'this' through generators
I think this was just an oversight for generators. They should pass all the attributes inside.
2013-03-09 13:26:15 -08:00
ptarjan 71ee3ea273 get ref correct in closure parser 2013-03-09 13:26:15 -08:00
ptarjan 60c61ee3e1 capitalize Closure
PHP is case insensitive, but this leads to better debugging messages if the case matches the declaration.
2013-03-09 13:26:15 -08:00
ottoni f10ecaf20d Revert "make debug_backtrace go through ignored functions" 2013-03-09 13:26:15 -08:00
ptarjan ea782cbd3e handle create_function with a closure in it
This actually was pretty broken already. If you defined a new function in the ##create_function## string it would return that function but it wouldn't move it to the right unit so it can't execute. A big mess. For example:

    $ cat a.php
    <?php
    $a = create_function('', 'function b() { return 3; }');
    $a();
    var_dump(b());
    $ php a.php
    HipHop Fatal error: Undefined function: b in /data/users/ptarjan/hphp/hphp/a.php on line 4
    $ hhvm a.php
    int(3)
2013-03-09 13:26:15 -08:00
ptarjan 7fe1c94a7c increase readability of 0 -> KindOfUninit
I was perplexed by this. It makes more sense to me this way.
2013-03-09 13:26:15 -08:00
ptarjan 085040d70f fix bytecode spec 2013-03-09 13:25:52 -08:00
ptarjan 3ea0d8b8e0 provide better debugging information if source.size != dest.size 2013-03-09 13:25:52 -08:00
ptarjan fd2f07d1f1 Revert allowing $this in closures
I'm going to do a replacement diff anyways, so all this does is delays it a week.
2013-03-09 12:49:43 -08:00
aravind 3e8cbc356f Reset Xbox threads after each request
Xbox threads can now release memory after each request. Also
gives cleaner semantics as Xbox requests dodn't have to be careful
about not modifying global state.
2013-03-09 12:49:43 -08:00
mwilliams 10f9f6b239 const bool hhvm is dead 2013-03-09 12:49:37 -08:00
aravind a611ac930d Implement Switch in IR 2013-03-09 11:10:13 -08:00
jan 94f8158ca5 Expose reflection thru API
Expose the following data to the PHP:
- asio_get_current_context_idx(): get current context index
- asio_get_running_in_context(): get running wait handle in a given context
- asio_get_running(): get running wait handle in a current context (renamed asio_get_current())
- WaitableWaitHandle::getContextIdx(): get context the wait handle operates in
- WaitableWaitHandle::getCreator(): get continuation wait handle that constructed this wait handle
2013-03-09 10:50:49 -08:00
jan 3c20163337 Keep track of WaitableWaitHandle creators
Keep track of creator that constructed us.
2013-03-09 10:29:30 -08:00
jan a9926b46d2 Move enter/exit context responsibility from PHP to join(), try #2
Move the responsibility of entering/exiting contexts from PHP to the
implementation of $wait_handle->join().

This eliminates possibility of weird situations, like contexts without
any running wait handle. This guarantees that asio_get_current() returns
null only if called completely out of asio framework and simplifies some
logic, such as getCurrentWaitHandleDepth().
2013-03-09 10:29:30 -08:00
aalexandre 26178124a4 Eliminate int32, uint32, int16, uint16, int8, uint8.
This concludes the inttypes replacement.
These replacement have been mostly mechanical
with the use of cxx_replace.
2013-03-09 10:25:16 -08:00
bsimmers c7bb7d8eb6 Fix type mistake in cgOpSub
Sometimes src1 isn't an int. This was causing failed asserts
in debug perflab runs.
2013-03-09 10:25:15 -08:00
jan 05f5808d81 Revert "[ext_asio] Use guard to make sure state is restored correctly" 2013-03-09 10:25:15 -08:00
Sara Golemon 8e30d1c315 Update generated_files.sh to no longer build system/gen
Also split constants.h and class_map.cpp into separate generates.
2013-03-09 10:25:15 -08:00
Sara Golemon 3887bec93f Build hphp/system/class_map.cpp
And remove last of system/gen
2013-03-09 10:06:55 -08:00
bmaurer 2fb7b0e279 Avoid lookup during get_class_constants
Noticed this in perf, maybe I'm missing something obvious
but it seemed like there was a pretty easy way to avoid an extra
hashtable lookup during get_class_constants

This shows up because the Enum class call this method once per enum
the first time isValid is call. Might be worth doing something to
make this even more efficient, but seems like an easy win.
2013-03-08 19:13:06 -08:00
mwilliams fea70b0391 Kill more dead code
Kills
 - ClassPropTable
 - ObjectStaticCallbacks
 - MethodCallPackage
 - StaticStringProxy
 - VariantProxy
 - TheStaticStringSet
 - argvalAt
 - refvalAt

Also removes the more-or-less unused StringData in each
StaticString.
2013-03-08 19:13:05 -08:00
mwilliams a4c6fec8e9 Get rid of lots of non-hhvm code
Kill #ifdef HHVM
Kill lots of unused code
2013-03-08 18:44:01 -08:00
alia f6ac148c09 Removed some redundant code in HhbcTranslator::emitFPushClsMethodD.
Removed code in HhbcTranslator::emitFPushClsMethodD that was
duplicated in IRTranslator::irTranslateFPushClsMethodD.
2013-03-08 17:53:28 -08:00
jan 95fc3dc1c9 Use guard to make sure state is restored correctly
If an internal HPHP exception is thrown in a continuation executed by
ext_asio, m_current pointer was not reset and resources were not cleaned
up. This doesn't matter that much in prod, but when used in debug mode,
an assertion was hit.
2013-03-08 17:53:28 -08:00
jan 2ae5ebf3f5 Ignore exceptions generated by onFailed error handler
It's illegal for onFailed error handler to throw any exceptions. Ignore
them to avoid getting into inconsistent state.
2013-03-08 17:53:28 -08:00
jan c9f6d8aeb9 Remove abstract methods
Take advantage of previous diff that won't try to construct abstract classes.
Abstract methods now don't need to be implemented, so remove their
dummy implementation.
2013-03-08 17:53:28 -08:00
jan 6aa91b97c8 Do not generate new instance helper for abstract extension classes
Abstract classes can't be constructed. Don't generate helper for
constructing new instances of such classes. Set null to m_InstanceCtor
field of HhbcExtClassInfo that eventually gets passed to m_InstanceCtor
of Class. The Instance::newInstance() then ends up raising correct
exception.
2013-03-08 17:52:39 -08:00
ottoni 830c48eb8a Add null check in EmitterVisitor::requiresDeepInit 2013-03-08 17:52:39 -08:00
bsimmers e7a57f89c8 Remove HhbcTranslator::m_unboxPtrs and clean up emitCGetProp a little
m_unboxPtrs looks like a relic from the early days of the
ir. emitCGetProp has been cleaned up to never punt (it checks every
needed condition before deciding to not using the vector translator).
2013-03-08 17:52:39 -08:00
bsimmers e5469c9b19 Don't initialize MInstrState in some more common cases
This was causing the ir to generate much larger code than
tx64 for simple SetMs. tx64 does have a specialized helper for setting
array elements that we may want to replicate in the IR, but that can
come in a separate diff. The code generated by VectorTranslator is now
just a few instructions larger than tx64. Without the SpillStack it
would be 1 instruction smaller.
2013-03-08 17:52:39 -08:00
ottoni 96235149fb Don't insert translation counters by default 2013-03-08 17:52:39 -08:00
mwilliams c59f2ae71f Remove outputCPP support from hphp 2013-03-08 17:52:38 -08:00
mwilliams 4eaf40d7aa Generate g_class_map directly from the idl
This is the last step to being able to get rid of the c++ code
gen in hphp. "make -Chphp/system" is now a no-op.

I'll rip out the actual c++ generating code as a separate diff.
2013-03-08 17:52:31 -08:00
smith 73ebbc2160 Don't use m_mainReturn._count to hold the mergeOnly field in Unit[Emitter].
I found some byte-wide padding in Unit and UnitEmitter that we can
use to store the mergeOnly flag, instead of m_returnValue's unused
_count field.  This is one step towards eliminating TV._count.
2013-03-08 17:52:31 -08:00
alia 181f341d00 Minor code size improvements for HHIR.
Improved the size of the code emitted by HHIR. Checks for
this pointer should use a byte comparison. Added a linearscan
precoloring hint for global address helper. Modified argument
shuffling code to use xor rather than move of an immediate zero. For
StaticMethodCache access, moved the test next to the branch to make it
more x86 friendly.
2013-03-08 17:52:31 -08:00
andrewparoski b9e14c448c Support collection literals in initializers
This diff updates the parser and runtime to support using collection
literals in initializer expressions for instance properties, static
properties, parameters, and static locals.

The runtime as-is was able to correctly handle collection literals in
initializers for static properties, parameters, and static locals. However,
for instance properties I needed to way to make it so that each instance
got a fresh copy of the collection literal.

To achieve this, I added an attribute to indicate that a property requires
'deep' intiialization. When this attribute is set, the Class machinery
will not call setEvalScalar() on the initial value (the value produced by
86pinit), and it will make a deep copy of the initial value when a new
instance of the Class is allocated.
2013-03-08 17:52:31 -08:00
andrewparoski 2fe9a69916 Support == and != for collections
Support == and != operators for collections. Also fix some bugs the <, <=,
>, and >= operators when comparing two objects or when comparing an array
with an object.
2013-03-08 17:52:30 -08:00
andrewparoski 34ba5330d5 Fix bug involving autoload with interfaces and traits
This fixes an old bug with autoloading interfaces and traits where the
runtime erroneously continued to call autoload handlers even though the
requested interface/trait had already been loaded.

This also rips out some dead autoload helpers and removes the 'declared'
parameter from invokeHandler() since it is null for all callsites.
2013-03-08 17:52:30 -08:00
mwilliams 01b29a87df Re-enable static analysis for returns
The control flow issue was fixed a while back.
2013-03-08 17:52:30 -08:00
ottoni cf41a82f42 Fix bug looking up properties in a PreClass
A prior diff added property error-reporting code that was looking up the
property in the PreClass.  However, a PreClass doesn't contain the
inherited properties, so HHVM was crashing when trying to raise an
accessibility error on an inherited property.

This diff changes the code to lookup the property in the actual Class
instead.
2013-03-08 17:52:30 -08:00
smith 65119c99a0 Fix return type in collection fromArray/Vector/Iterable() methods
IDL says Object, but C++ code says Variant.  They always return Object,
but the ext_hhvm adapters don't crash because of the way Object and
Variant happen to be layed out.  When the layout changes, stuff breaks.
2013-03-08 17:52:30 -08:00
bertrand 10c79adeba Add symbols to disassembly
Adds debug symbols on calls into the runtime so we can better
understand/compare the helpers being called when we use DumpIR or
JitCompareHHIR.

I used the GNU backtrace_symbols() facility to do the translation of
address->symbol, since it seemed like the easiest route to this
functionality.
2013-03-08 17:52:30 -08:00
mwilliams 35e456c966 Put the compiler-id into a variable
So that we only have to recompile one file when it changes.
2013-03-08 17:52:20 -08:00
bertrand fd49414b4d Implement BaseG 2013-03-08 13:10:09 -08:00
mwilliams 6850f3fa89 Get rid of dynamic_table_constant.cpp
Moved last few uses into ClassInfo.
2013-03-08 12:23:12 -08:00
mwilliams 4286a730c5 Fix g++ 4.7.1 build
The variable declared in an if condition cant be redeclared in the
(outermost scope of the) else.

g++4.7.1 treats FOO as a literal suffix operator in "x"FOO, even if FOO
is a macro whose expansion wouldnt qualify (not sure if this is a bug
in g++4.7.1)
2013-03-08 08:51:38 -08:00
mwilliams 6c87ecb74e Remove dynamic_table_class.cpp
We only used it to get the values of certain class constants,
and to define the ObjectStaticCallbacks for every class.

We can put the class constants directly into the class_map
(we should have done that before for perf reasons), and then
the only remaining use of ObjectStaticCallbacks is to proxy
the Class* for each builtin class. So just use the Class*
directly.

Once this is in, Im just a small step away from eliminating
make -C hphp/system - so Im leaving a lot of dead code here.
Its going to be easier to delete it en masse, rather than
try to pick and chose now.
2013-03-08 08:50:45 -08:00
alia 7eeb594316 Completed implementing LateBoundCls in HHIR.
Completed implementing LateBoundCls in HHIR by handling the
case where we need to dynamically distinguish between a 'this' pointer
and a class in the ActRec. Introduced new instructions to extract
the context class from the m_cls/m_this field of the ActRec. Re-used
them for FPushClsMethodF.
2013-03-07 22:51:49 -08:00
ottoni ef70ffc4e0 Shrink Ret code sequence
Push return address directly from memory, saving one instruction and
two bytes per Ret* and NativeImpl.
2013-03-07 22:51:49 -08:00
ottoni 1811ef243f Add support for FPassV
However, it triggered a bug in memelim. When chasing the value of a
Ref, if it came from a load other than LdRef (eg LdLoc), the value
tracked was the Ref itself instead of the inner value. This diff
separates RefInfo and LocInfo, and it adds findRefValue() to get the
value of a Ref.
2013-03-07 22:51:49 -08:00
chip bdb5a88268 Expose facebook's libmysqlclient async extensions to hphp
This exposes the core async mysql async APIs we added to our
mysql client.

These APIs are not meant to really be directly used (though they can
be); instead they're the building block upon which higher level APIs can
be implemented.
2013-03-07 22:51:16 -08:00
bsimmers 8be4799db9 Add IR dumps to the output of EvalJitCompareHHIR
This turns the output into three columns: tx64 asm, hhir asm,
then pretty-printed hhir with asm inline. This should help us figure
out what the ir is doing wrong when it makes bigger code. I also
compacted the output of Trace::print a bit and changed it to print
unlikely blocks at the very end.
2013-03-07 22:27:19 -08:00
mwilliams 2f3f5f3c5a Get rid of FrameInjection 2013-03-07 22:04:08 -08:00
mwilliams 3b3f9aa449 Fix TestServer
TestServer finds a free port to use as the server, but it
used the standard admin and rpc ports. If you had a
webserver running, it would own the admin port, causing
TestServer's tests to time out (because it uses the admin
port to stop them). Similarly rpc tests would fail because
they would be talking to the wrong server.

Find free ports for the admin and rpc servers, and use them.
2013-03-07 21:29:34 -08:00
mwilliams 7e321f8d5a Fix uninitialized variable
chars_len holds the capacity of the buffer on input,
and is filled in with the number of chars written.

It was not being set, causing random behavior (including
potential buffer overrun). The testcase actually relied
on it being set to a too-small value.
2013-03-07 21:29:29 -08:00
mwilliams 951d7c0adf Fix various bugs with line numbers and classes
I found 4 separate problems, each of which broke this:
 - A hoistable class didnt generate bytecode, so the line number
   information was associated with whatever line the /next/
   bytecode corresponded to. Often there was no next bytecode,
   so we got the line number of the end of the file.
 - If there /was/ a bytecode for the defClass, the line number
   recorded for it was that of the pseudoMain, not the class
   itself; so again, it would be reported as the end of the file.
 - The parser records two sets of line numbers for a class; its
   start, and end. The end line gets associated with the bytecode.
 - There were optimized paths where we didnt setup an ActRec
   at all, resulting in either reporting the file/line of the
   require (or often a require much higher up the stack), or
   not reporting a file/line at all.

So now, we generate a nop if we would have skipped the defCls.
We override the normal line info, and set both the start and end
lines to the start. And we wrap all errors from defClass in a
temporary frame to ensure the line info is seen.

This changed the output for several of our tests. Spot checking
a couple showed they now report the same line number as zend.
2013-03-07 21:29:29 -08:00
mwilliams 7ff582616f Don't compile systemlib php files
We don't need them in g_class_map, beacuse hhvm processes
the php for itself.
2013-03-07 21:09:46 -08:00
mwilliams c4c4404aa9 Get rid of dynamic_table_func
Its no longer being used.
2013-03-07 21:09:03 -08:00
mwilliams a8e7668189 Get rid of lots of outputCPP code
Very little is actually used anymore
2013-03-07 20:44:34 -08:00
mwilliams 18a45ba0d0 Get rid of invoke_builtin
It was only used to fold SimpleFunctionCall nodes. Ive setup enough
of the runtime that we can call invoke (which goes through hhvm's
normal Func dispatch), and then removed it.
2013-03-07 20:19:00 -08:00
mwilliams a6104b9d6e Get rid of more of system/gen
This basically targetted symbols.php, and Globals, but ended up
killing a lot more. I could keep adding more and more, but
this seems like a good point to stop and continue with
another diff.
2013-03-07 16:19:03 -08:00
Sara Golemon e355d3de17 hphp/test should be using hphp/hhvm externals 2013-03-07 16:19:02 -08:00
jan 99bfd8e9ee Remove inline keywords from class method definitions
Removing redundant inline keywords per @mwilliam's feedback.
2013-03-07 12:12:15 -08:00
alia 30fcc6a0d1 HHIR: Plumbed more instructions from irtranslator to hhbctranslator.
There were a few bytecodes in irtranslator that were
HHIR_UNIMPLEMENTED. These are bytecodes that tx64 handles but the IR
does not. Changed these to use hhbctranslator emit routines and used
interponeOrPunt to implement them for now. This should increase IR's
coverage a little when IRPuntDontInterp is false.
2013-03-07 11:35:07 -08:00
aalexandre 61d3e28392 Add move constructor and move assignment to essential data structures.
This reduces CPU instruction count by about 0.2%, has negligible impact on other metrics. Implementation has been changed a but upon discussion with @mwilliams to account for circular destruction. The question remains open whether this should be in before or after rooting out hphpc, but on the other hand we gotta do what we gotta do to move forward.
2013-03-07 11:34:39 -08:00
smith 21c4fbdbf3 Remove ZendArray
SharedMap was the last dependency on ZendArray.  For its localCache,
use a TypedValue[] array indexed by SharedVariant.getIndex(), and
for escalate(mutableIteration), escalate to an HphpArray instead of
a ZendArray.
2013-03-07 11:34:24 -08:00
Sara Golemon 33e81ef7bb Ignore ext_closure during ext_injection run 2013-03-07 11:33:51 -08:00
Owen Yamauchi e518130c7b Generalize the sys/param.h check
I'm using OpenEmbedded for the ARMv8 build right now, and it seems to be
BSD-like, based on the preprocessor flags that are defined, including
__USE_BSD. OpenEmbedded has the same problem with the "isset" macro, and
this change includes it in the code that undefs isset.

I guess this problem is common to BSD-like systems (if you consider OS X
to be BSD-like for this purpose), but __USE_BSD by itself isn't enough;
OS X doesn't define it.
2013-03-06 15:14:35 -08:00
andrewparoski 5848c633c3 Stop generating C++ for system/classes, remove uses of MethodCallPackage
This diff suppresses the output of C++ for the "pure" classes defined in
system/classes, and it rips out all the uses of MethodCallPackage (except
for the i_* and ifa_* helpers, which we can go after separately).

Also cleans up a bunch of "if (hhvm)" and "#ifdef HHVM" checks in builtin_functions.cpp,
systemlib.cpp, object_data.cpp, and class_info.cpp (and the corresponding .h files).

Note that this does not completely remove the generated C++ files. We
still generate code for the PHP files in "system/globals" and we still
generate the g_class_map (because the VM needs g_class_map at startup
when it creates Class's for the extensions). We also still have the
dynamic_func_table/dynamic_class_table stuff, MethodCallPackage, and
the i_* and ifa_* helpers to support invoke_builtin() (which is still
used by the compiler).
2013-03-06 15:13:40 -08:00
andrewparoski 9be42ffc84 Fix weakRemove() to handle collections 2013-03-06 11:15:50 -08:00
ptarjan e150671d40 Move Closure from php to c++
This is in preparation for saving a Func* on the class to fix the perf.

It turns out Properties were never used on a single class in the IDL so HHVM never implemented them. Now it does.

This diff was a perfect exercise in "change very few lines but finding which lines to change takes hours".
2013-03-06 10:46:47 -08:00
aravind c9ae7340cf Implement BPassV
I forgot to add this with FCallBuiltin. BPassV is ~5% of the
punts on trunk.
2013-03-06 10:06:02 -08:00
bsimmers a7c629366f Update printing of StRaw
The extra offset is gone but we were still trying to print it.
2013-03-06 10:06:02 -08:00
Sara Golemon 45486a934f Nuke gen/ before generating system files so that we don't keep dead files 2013-03-05 23:00:14 -08:00
andrewparoski 92c74b141a Fix some places that use old VM-incompatible machinery
On the back burner I've been working on a diff to pull out of some of
the old VM-incompatible machinery for invoking functions/methods and for
creating object. Along the way I noticed some bugs, so I figured I'd fix
them first in a separate diff to make review easier.
2013-03-05 22:55:46 -08:00
smith 45a794d7dd Linear scan improvements
When allocating registers and inserting Reloads, be less pessimistic
about reusing earlier reloads.  Only "forget" reloads that don't
dominate current block.  e.g. right after an if/then/else block, it
will clear any reloads from if/else arms so they can't be used in
the join block.

Moved numberInstructions() to linearScan.cpp, and don't re-sort the
control flow graph every time; register allocation doesn't change
the CFG shape so its enough to just iterate the existing block list
each time.

Un-pessimize rematerialization by snapshotting state at branches,
merging state when necessary, then restoring state at block starts.
Here, "state" is the previously seen tmps for sp, fp, and each
local variable.

removeUnusedSpills() can just iterate over the spill slots, erasing
spills with no uses; we don't need to visit every instruction.
2013-03-05 22:28:42 -08:00
jan 883a11fbef Fix consistency issue with cross-context cycle exceptions
enterContext() throws an exception when cross-context cycle is found.
The problem is that it modifies state before the exception is thrown,
assuming that the call will succeed.

When an exception is thrown, a dependency is left in invalid state, with
parent being in more specific context. This breaks exitContext()
algorithm and results in either internal invariant violations as seen
in #2091939, or memory corruptions and crashes as seen in #2125762.

Let's fix it by modifying state after returning back from recursive call
instead of before doing such call. This was previously unsafe in case we
tried to import dependency loop. Once D720506 is committed, dependency
loops will not exist anymore.
2013-03-05 22:28:42 -08:00
jan c6475efbec Detect cycles online and fix part of #2125762
Currently, we detect dependency loops by waiting until there is nothing
else to execute. If the wait handle we are waiting for did not finish,
it means it is in a cycle. We find the cycle by simply following the
dependency chain. Once the cycle is found, one edge is eliminated and an
exception is injected.

There are multiple problems with this approach:

1. Unability to exit contet safely

We are unable to exit context safely. When a context is exited, all wait
handles in that context must be kicked out. But we maintain only
references to the SCHEDULED wait handles + BLOCKED wait handles that
recursively depend on them.

If we do not kick out all unfinished wait handles, we end up in
corrupted state.

2. Unability to break edge that caused the cycle

Once the cycle is detected, we don't know which edge caused the cycle to
be formed. We can only use heuristics to eliminate the edge that likely
formed the cycle, we cannot be sure. This may make it very hard to fix
the PHP code that caused the cycle.

Solution:

This diff implements online cycle detection with a naive approach of
visiting the dependency chain from child at a time new edge between
parent and child is being added. If a parent is visited, a cycle is
found. Otherwise we eventually reach non-BLOCKED wait handle as it is
guaranteed the rest of the graph is cycle-free.
2013-03-05 22:28:41 -08:00
jan a1baf2d540 Access context by index
Currently, wait handles store pointer to the context they are in. This
pointer is not protected with reference counting, as it is expected that
whenever a context is exited, references to it are cleaned thru
exitContext() mechanism.

If a bug is present that violates this assumption, it is impossible to
guard against invalid pointer access and a hard to debug memory
corruption occurs.

Since the structure of contexts is a simple stack, let's reference them
by index instead of by pointer.

As a bonus, one pointer worth of memory is saved for every non-trivial wait handle.

The actual bugs will be fixed by the next 2 diffs that do:
1. implement online cycle detection
2. do enterContext() atomically and properly handle failure
2013-03-05 22:28:41 -08:00
smith 0562656c5b Rename some tests to avoid collisions on case-insensitive filesystems.
Avoids headaches if you clone our repo or the OSS repo on a Mac.
2013-03-05 22:28:41 -08:00
Owen Yamauchi c1e71c1917 Conditionally compile assembly helpers
Just treating some more x64-specific assembly. The tx64 helpers are all
written to trap on ARM right now -- we're not going to be running the
jit for a little while, and we don't need real implementations till
then.

Fortunately, the system we're targeting has thread-local storage
support, and it's pretty easy to get at it, so I just did it.
2013-03-05 22:28:41 -08:00
aravind 668a9c1da2 FCallBuiltin for IR 2013-03-05 22:28:41 -08:00
alia f4551719a9 HHIR: Fixed uses of trace exits.
Fixed a few places where we were calling exitTrace when we
should have been calling exitSlowTrace in
hhbctranslator. ExitSlowTrace will exit and not return to the IR,
going to either code generated by tx64 or the interpreter (depending
on the IRPuntDontInterp runtime flag). ExitTrace will simply exit and
retranslate using the IR if possible. In some cases we were using
exitTrace for conditions that the IR could not handle, causing us to
just try the same doomed operation again in the IR.

Used control flow to implement IssetS/G and EmptyS/G instead of
exiting the trace on an undefined static property or global.

Implemented code gen for Unbox and cleaned up its
simplification.

Cleaned up some DefConsts in hhbctranslator.
2013-03-05 22:28:41 -08:00
ottoni 3f0a4f7ece Add support for noSurprise meta-data annotation
This was causing HHIR to emit surprise-flags checks when Tx64 was skipping it.
2013-03-05 22:27:43 -08:00
mwilliams ecdd06cebe Fix array_walk_recursive test
It wasnt testing what it was supposed to
2013-03-05 22:27:43 -08:00
Nick Harper 5744173e90 Fix array_walk_recursive() recursion check
We only have recursion if what we're currently looking at is the same as
one of its parents in the nested arrays. We don't need to keep track of
everything that's been seen, only the elements seen in a path down to that
element.
2013-03-05 22:27:43 -08:00
mwilliams 0f3ba86d84 Dont analyze every tracelet twice
Seems pointless (but maybe Im missing something). Long term its
not important - this only affects things when the ir is off, but
its going to give us a false baseline wrt startup translation
time of the ir.
2013-03-05 22:27:43 -08:00
smith 37d974ef83 Remove VectorArray (dead code)
Also cleaned up some if (hhvm) logic in the files I was touching anyway.
2013-03-05 22:27:42 -08:00
smith 7f43d78955 assert(isNative) in cgCallHelper, fix Native flags, enable MMX spills.
Now we can rely the Native flag to tell whether a call is going to
happen or not.  This should improve precoloring hints, and allows
re-enabling spilling to MMX registers.
2013-03-05 22:27:42 -08:00
smith 1f68fd307f Add DbgCheckTV opcode and use it in a couple places
Instead of custom asm we generate in a few places to generate asserts
that check a TypedValue, use an opcode instead.  This also moves more
of the assert-generation logic to a dedicated pass.

Moved the CSEHash for constants from TraceBuilder to IRFactory, to
simplify generating DefConst instructions later than the TraceBuilder
pass.  IRFactory now owns the constant table.

Cleaned up type names in ir.specification.  We always pretty-print
pointer types as PtrToWhatever, so do it that way in the spec too.
Added spec for Call.
2013-03-05 22:07:58 -08:00
smith 3e12490127 Enhance simplifier pass so it works with control flow.
Snapshot Tracebuilder state at branch points, and merge it at join points.
Remove the no-control-flow restriction from TraceBuilder::optimizeTrace,
since we can deal with control flow now.

In optimizeTrace, When we enter a block that has a snapshot state,
remove entries from the cse table that don't dominate the current block.
2013-03-05 22:07:58 -08:00
ottoni 334a83f7b6 Expand IncDecL support, use inc/dec x86 instructions, avoid useless moves
Add support for boxed ints, and boxed/unboxed doubles, and bools.

Emit inc/dec x86 instructions in some cases.

Got rid of some "mov rX, rX" found along the way.
2013-03-05 22:07:58 -08:00
mwilliams 8c2a7af8d4 Fix integer overflow in fb_serialized_size
We could overflow the size of an int, return a
"legitimate" looking value, and then crash in
fb_serialize_into_buffer when we go past the allocated
size.
2013-03-05 22:07:58 -08:00
mwilliams b40c724281 Fix bogus decRef of Null
If a PopR was marked as having a predicted type, and it was
not in the same tracelet as its producer, we would generate
code that didnt verify the predicted type. Note that normally
we would translate them together, unless we failed to get the
write lease. In that case, we could spend a long time inside
the call, and get the write lease by the time we return.
2013-03-05 22:07:58 -08:00
bertrand 157b59cdac Replace isStaticallyKnown with clearer names
There's widespread dislike of the isStaticallyKnown
predicate, and I think the main problem is the "statically" part in
the name.  Some of the basic types (str, null, array) are actually
unions of a static and counted type, so sometimes we don't precisely
know the type statically, but it doesn't matter.

To remedy the situation, I'm renaming isStaticallyKnown to be simply
"isKnown", which I think is a semantic improvement (@smith suggested
"hasKnownDataType" -- I figured that since the object is a type that
I'd go with something shorter). I'm also providing "needsReg", which
is now just the inverse of "isKnown", but having this available makes
the code clearer in places that care about the type only to figure out
whether to allocate storage for it.

There might be places where more precise tests could be used, but
they're not totally obvious to me.  So, I want to push out the simpler
naming scheme first.
2013-03-05 22:07:57 -08:00
smith 7969b8f2ee Add ifThen[Else] helpers in codegen.cpp; improve guard branching.
Got rid of lots of boilerplate by using ifThen helper.  In nearby
areas, updated asm generation code to use the new style.

Factored two-register-assignment out of cgCallHelper(), use it
in cgIncRef().

Generalized cgIncRefWork slightly (since it was cleaner this way)
so it handles the case of no-static-check but with a type check,
and use shuffle2() instead of more adhoc copy logic.

cgGuardRefs should generate fewer unnecessary jumps now, by crafting
the code we generate based on compile-time-known cases (fixes TODO).
2013-03-05 22:07:57 -08:00
smith addb01eea4 Fix local variable state-tracking for Iter[Next,Init][K]
tracebuilder and rematerialization both rely on tracking the contents
of local variables; these instructions were incomplete.
2013-03-05 22:07:57 -08:00
mwilliams 5eac64e8bd Remove GlobalArrayWrapper 2013-03-05 22:07:57 -08:00
andrewparoski 193ddf4a60 Fix unwinding for generator frames
The logic for unwinding generator frames was assuming that the previous
frame was always a VM frame. This used to be a correct assumption, but now
we have invokeContFunc which allows native code to call generator functions.

This diff fixes the unwinder to correctly computer the bottom of the eval
stack in the case where the previous frame is a native frame. It also
updates invokeContFunc to properly decref the return value.
2013-03-05 22:07:57 -08:00
alia 3f61cabef2 Implemented IterFree in HHIR.
Implemented IterFree in HHIR. This showed up in the list of
top reasons the HHIR punts.
2013-03-05 22:07:57 -08:00
Owen Yamauchi bffeb65b84 Delete NativeXHP flag
This flag isn't being used in any of our deployments. I sure hope not,
anyway, because if you turn it off, things are mega-busted; I can't even
run a sandbox without crashing pretty early on.

This breaks the OSS build's dependency on xhp. We're still depending on
it internally in a Facebook-specific extension (exposing the XHP
preprocessor to PHP code as ##xhp_preprocess_code()##). There might be
some way to replicate this functionality using HPHP's native XHP parser,
but that seems low-pri.
2013-03-05 22:07:57 -08:00
alia 6aa9f21425 Implemented globals in HHIR.
Implemented globals in HHIR (CGetG, SetG, VGetG, BindG,
IssetG, EmptyG). This version doesn't use the targetcache.
2013-03-05 22:07:57 -08:00
Owen Yamauchi de1249af6e Delete hphpc-only parts of Continuation
While I'm looking at this stuff during debugging, get rid of some of the
stuff that's only compiled for the now-nonexistent hphpc build.

I'm aiming for this change to result in identical code after
preprocessing. There is some other stuff in these files that could go
(any method with ##const_assert(!hhvm)##) but getting rid of those is a
bit hairier; I tried, and it resulted in some weird, hard-to-repro
instability, and it doesn't seem worth sinking much time into at the
moment.
2013-03-05 22:07:57 -08:00
mwilliams f5c0cd21ae Fix a maybe-used-uninitialized warning 2013-03-05 22:07:57 -08:00
ptarjan 9f21844eb5 handle reference closures
Handle a closure that returns by reference.
2013-03-05 22:07:56 -08:00
ptarjan 8c6d77deef Put the body of a closure on the class intead of in the __invoke of the closure
Instead of having the body of the closure be in the ##__invoke()## on the ##Closure## class, instead we make an anonymous function on the real class and put the body there. The signature for this function is:

  function methodForClosure$1234($arg1, $arg2, ..., $use1, $use2, ...)

and then ##__invoke## now just takes all the params that were passed to it, puts them as the first args to the anonymous function, then takes all the use variables it had saved up and passed them in as the next params.

I tried to not have an ##__invoke## at all, but I ended up basically doing the same parameter and use var repacking in iopFCall (and would have had to do it in x86 code too). I opted for doing the rejiggering in bytecode. If I did it in raw PHP I think it would have been much slower with many ##func_get_args()## and array operations.
2013-03-05 22:07:56 -08:00
ptarjan e5663bd9ec allow (new Foo)->bar() 2013-03-05 22:07:56 -08:00
ptarjan 7917779c18 make debug_backtrace go through ignored functions
We don't display the stack frame for ##isNoInjection()## functions, but the backtrace does set the previous call lines wrong.

This came up when I made the Closure::__invoke to be hidden, but the line numbers were wrong.
2013-03-05 22:07:56 -08:00
ptarjan a395e9e3dd script to import zend tests
I often want to make sure we are close to parity with zend so
importing their tests seems like a good idea. I used this for an
upcoming diff and it worked out well.

I just tried this on all the closure tests and it needs a bit
of hardening. It worked well though :)
2013-03-05 22:07:50 -08:00
ptarjan 27d247e976 Make hphp.y closer to zend
I'm going through the zend parser file and they are quite similar to ours:

https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y

It seems having our parser file being closer to theirs would help us keep parity. I also prefer less copy and pasting when possible.
2013-03-05 22:07:49 -08:00
smith af3c7ac8df Move assembly address info into AsmInfo
IRInstruction and Block have asmRange fields to record where
their assembly code got generated, but it's only used for
pretty-printing.  Do it with a side structure instead, indexed
by block (for block ranges) or instruction.

Gave each instruction its own range, to simplify pretty-printing.
Modified the pretty-printer to also print code following the last
instruction in a block but which is still in the block's range
(e.g. a jump to the next block)
2013-03-05 22:07:49 -08:00
bertrand 7c1503e778 Always generate Type::Arr instead of Type::StaticArr
Temporarily avoid generating static array to un-break PerfLab
2013-03-05 22:07:49 -08:00
dgomez ab71559f5a Reduce the number of copies of certain data
On the decompression+deserialization path one useless copy will be created in case the data is not compressed, but serialized. Uncompress always returns a platform native string, but if the data was serialized this platform string is not needed, since it will be unserialized into platform variant anyway.
This can be improved by unserializing the data directly from mc_msg_t in case it was not compressed.
2013-03-05 22:07:49 -08:00
hermanv aac3f2bfd5 Add constants asociated with idna functions. Port applicable tests from Zend.
The Zend versions of idn_to_ascii, idn_to_unicode and idn_to_utf8 take parameters whose valid values are defined by predefined constants and whose error codes correspond to
predefined constants. This change adds those predefined constants to hiphop. It also ports two of the applicable unit tests from the Zend code base to hiphop.
2013-03-05 22:07:37 -08:00
srenfro 296b2baede RuntimeOption to disable TLSv1.2 in HPHP runtime, not in OpenSSL
Introduces a new server runtime option TLSDisableTLS1_2,
which is off by default. When on, it disables TLSv1.2
in the two places we curl_init().
2013-03-05 21:17:51 -08:00
alia 2ef2187778 Fixed hphp/test/vm/static_sprop2.php test.
The test hphp/test/vm/static_sprop2.php needed a filter rule
file for a file path in its expected output. This was breaking tests.
2013-03-05 21:17:51 -08:00
alia e30755ddbe HHIR: Fixed potential problems with essential instructions
Fixed a few instructions in the HHIR instruction properties
table related to instructions that should not be moved or eliminated
by dead code elimination. Also made sure codegen can handle essential
instructions whose result are not used (i.e., instructions whose
destination registers are InvalidReg).
2013-03-05 21:17:51 -08:00
lovro bc085bbcf6 Use init_null_variant instead of null_variant
I'm experimenting with ArrayInit::add() and it behaves strange with null_variant
2013-03-05 21:17:40 -08:00
alia 09b97f8336 Fixed 2 HHIR bugs that were causing crashes.
Fixes HHIR bugs that were causing perflab crashes: guards on
class types and tvBox.

We were ignoring stack guards on class, which was causing the IR to
lose track of types for classes on the stack and causing assertion
failures. Fixed by making class stack type guards into stack type
asserts.

tvBox was not returning the right value, causing VGetS to crash in the
IR.

Changed 1 test and added another to cover VGetS in verify_quick_hhir.
2013-03-05 21:17:39 -08:00
bsimmers 991ca4e231 Add a top-level catch to RUN_TEST
A test was hanging on to the result of
std::string::c_str() past the lifetime of the string and then throwing
an uncaught exception.
This diff adds a top-level catch block to RUN_TEST to prevent things like
this from killing the test binary in the future.
2013-03-05 21:17:39 -08:00
smith 449ebdc43f Add a per-block likely/unlikely hint, use it for code placement.
Each Block has a new Likely/Unlikely/Neither hint that can be set
any time.  At codegen time, unlikely blocks are put in astubs.
Codegen takes care of inserting branches to/from them if necessary.

Updated the pretty-printing code to show AStubs code after each
block instead of after each trace.

Refactored the instructions that emit code into both a and astubs
so they work when a == astubs, by using a new unlikelyIfBlock
helper.
2013-03-05 19:52:43 -08:00
smith 6ab2ea2218 Track predecessors of "join" blocks so we can follow use->def chains
In order to find the srcs that reach a given DefLabel destination,
we need to know the Jmps that reach the label.  This diff tracks them
in a singly linked list which stays up-to-date when setTaken()
is called.

Just to exersize the ability, I changed the prettyprint output
to print "phi" pseudio-instructions.  These don't exist in the
actual IR but its helpful to see them in the dump output..
2013-03-05 19:52:43 -08:00
smith 0b27530c65 Make Block the main instruction container in HHIR
Instead of Traces holding a non-intrusive list of instructions,
have Blocks own instructions with an efficient intrusive list
so each instruction can only be in one block at a time.

Traces hold a list of blocks (which hold instructions); the overall
instruction order isn't changed.  However, use the Block api to
insert/remove instructions.

IRInstructions and Blocks point to their "parent" but the accessors
are named specifically (IRInstruction::getBlock and Block::getTrace).

Branches refer to a Block instead of a LabelInstruction.  Fields
of LabelInstruction were moved to Block, and LabelInstruction is
removed.  IRInstruction is now nonvirtual.

Several loops over trace->getInstructionList() were modified to
be nested loops over blocks, then instructions.

Removed the union of SSATmp[*|**] for destinations; instead, use
SSATmp* m_dst, which points to 0 or more destinations.  The
opcode still dictates whether the count must be 0, 1, or N.
Looping over multiple destinations now typically uses SSATmp&.
Renamed typedef SSARange to SrcRange and added DstRange.

Branch-patching state was moved out of LabelInstruction (or Block)
and is private to CodeGen now; each block has an associated patch
list.
2013-03-05 19:52:43 -08:00
Sara Golemon cd7b28ad6a Add folly experimental components 2013-03-05 19:52:43 -08:00
Scott MacVicar 943b945e1b Show message like the regular status messages
Make the CMake output consistent when doing a build.
2013-02-24 23:22:55 -08:00
Scott MacVicar ab6a6508fb Update README.md
Changed paths and added some extra libraries
2013-02-24 23:06:04 -08:00
ptarjan c1b7da6a4c Allow trailing comma in function calls
https://wiki.php.net/rfc/trailing-comma-function-args
2013-02-19 13:41:28 -08:00
bertrand 1d6df52d09 Introduce Counted type union.
This diff creates a Counted type union by splitting Arr into
CountedArr and StaticArr.  This cleans up the *Counted() predicates
and makes needsStaticBitCheck more precise for arrays.  Please check
me (esp on canRunDtor), because I am n00b with respect to PHP
semantics.
2013-02-19 13:41:27 -08:00
ptc 4507c61901 Include Local Var Info in DWARF Debug
Include locals information in gdb via the preexisting dwarf output.

As discussed I have a top level DIE for 'HPHP::TypedValue' with the same name
which gdb takes care of while doing the opaque type resolution.
2013-02-19 13:41:27 -08:00
mwilliams 7f6b1532dc Add smart allocated standard containers
And use them in AsioContext, which was doing a lot of memory
allocation via malloc/free, was itself allocated by malloc, and
needed to be sweepable to deal with the fact that it contained
standard containers.
2013-02-19 13:41:27 -08:00
bertrand 12471034e5 Implement BaseS in the vector translator 2013-02-19 13:41:27 -08:00
smith 28fc7a3a45 Fix result-copying in cgCallHelper
If the return value is a register pair (e.g. TypedValue by value),
and the register assignments required a swap or assigned rdx to
dest-register-0, then we'd clobber rdx before saving it.
2013-02-19 13:41:27 -08:00
bsimmers a9a021e739 Turn on HHIRDisableTx64 for IR automated tests 2013-02-19 13:41:27 -08:00
bsimmers 812070e82d Fix VectorEffects for bad array keys
Setting an array element with a key that's an array or object
raises a warning and evaluates to null. VectorEffects wasn't taking
this into account and was also getting a bunch of other things wrong,
so I rewrote it.
2013-02-19 13:41:27 -08:00
Owen Yamauchi 8d86116117 Conditionally compile cpuid stuff in GetCPUModel
Pretty self-explanatory. I took out the 32-bit compatibility stuff
because we're pretty far away from being able to support 32-bit
platforms (the open source build explicitly checks and fails on 32-bit).

On non-x64 platforms, we'll fall back to calling uname(). As far as I
can tell, ARM doesn't have a "processor name" facility like x86 does,
but if we find one, we can add support for it here.
2013-02-19 13:41:27 -08:00
Owen Yamauchi 520ef90a75 Conditionally compile memcpy-x64.cpp
Don't compile this on other platforms. (Really, this should be something
like HAVE_EMMINTRIN_H but we don't have that kind of infrastructure
right now.)
2013-02-19 13:41:27 -08:00
Owen Yamauchi c3cd188c6f Delete util/config.h
This is dead code. We're not using autotools at all, so let's not have
autotools artifacts sitting around.
2013-02-19 13:41:26 -08:00
Sara Golemon c1a8c937f1 Add support for user-defined streams wrappers 2013-02-19 13:41:26 -08:00
Sara Golemon 35842e9141 Clean up cruft in the CMakeLists 2013-02-19 13:41:26 -08:00
Sara Golemon fc5b95110f Remove support for buildling HPHPc
To get the non-hphpc portions of buliding for HPHPc,
perform an HHVM build and execute it with the --hphp flag

To checkout the commit immediately prior to this:
git checkout use-hphpc
2013-02-19 13:41:26 -08:00
hermanv 9cb2d7af85 Add support for UTS #46, along the lines of Zend, to idn_to_ascii.
Removes the output errorCode parameter (that is not currently used anywhere, except in testing code that gets but ignores it). Adds the options, variant and
idna_info parameters that are present in the Zend version of idn_to_ascii. Implement the new functionality required by these parameters by using the UTS #46 API, if
present.
2013-02-19 13:41:26 -08:00
ptarjan 6a311f2fab make test filters consistent 2013-02-19 13:41:08 -08:00
aalexandre b3b41e08bb Replaced NULL with nullptr 2013-02-19 06:57:54 -08:00
ptarjan 3e24e506f4 OBJMETHOD_BODY -> fPushObjMethodImpl
I was debugging this method and jumping into a macro that is 20 lines is much harder than a method. Shouldn't the compiler inline it if that is the right thing to do anyways?

There also was a hidden variable ##numArgs## which is what was messing me up.
2013-02-19 06:57:06 -08:00
alia ef1d4c9c1e Fixed HHIR bug: LdClsCached should be essential.
LdClsCached should be marked essential so that dead code elim
and code sinking don't touch it. This was causing a sandbox crash.
2013-02-19 06:57:06 -08:00
jan cee31f4412 RescheduleWaitHandle: management of execution priority
Abstract away execution priority management from ContinuationWaitHandle
and create RescheduleWaitHandle.
2013-02-19 06:53:40 -08:00
Owen Yamauchi 65d2487ab7 Increase -ftemplate-depth from 60 to 120 2013-02-14 09:09:34 -08:00
mwilliams 67013476b5 Fix TestExt to work under hhvm
and move it into the hhvm_tests target
2013-02-14 09:09:27 -08:00
bsimmers 2b3ae234fb Fix hphp
Util::s_pageSize wasn't being initialized early enough,
causing us to pass bogus values for stack sizes to pthread_create.
2013-02-14 06:48:37 -08:00
bsimmers 6fed85fbb4 Trace slow exits to tx64 in TRACE=punt:1
They're not dynamically important right now but we might as
well keep the instrumentation code.
2013-02-14 06:48:37 -08:00
andrewparoski bd2e014e8f Make String::operator+=() support StringSlice and MutableSlice
This diff adds support for StringSlice and MutableSlice to the
String::operator+=() method. It also uses operator+= to replace some
manual string manipulation in throwStrOOB inside ext_collection.cpp.
2013-02-14 06:48:37 -08:00
Owen Yamauchi c8cc07a61c Port ffs64 and fls64
These rely on the hilarious BSR and BSF instructions on x64. ARMv8 has
an instruction that does something similar: count leading zeros.
Unfortunately, their semantics differ in a few important ways:

- BSR and BSF, when given a zero input, set the zero flag and have
  undefined output. CLZ outputs 64.

- BSR and BSF return the index (starting from 0 at the LSB) of the most- or
  least-significant 1 bit. CLZ does what it says: count leading zeros.

Bottom line, there has to be some bit trickery somewhere to fit the two
instructions into the same interface. I kept the x64 implementations the
same and put all the nastiness in the ARM implementations to make them
match, since obviously the perf of the ARM implementations doesn't
matter yet.
2013-02-14 06:48:26 -08:00
Owen Yamauchi 26c4d57cfa Replace PAGE_SIZE with sysconf(_SC_PAGESIZE)
PAGE_SIZE isn't portable -- e.g. my ARMv8 sysroot doesn't define it. I'm
replacing it in the way the Linux manpage recommends. This should work
on a wide variety of platforms. For example, it works on OS X.
2013-02-14 06:47:38 -08:00
mwilliams f58323820c More customizable init/fini hooks
Allow extensions to hook into hphp_process_init and hphp_process_exit
in the same way they could already hook into thread_init/thread_fini.

Also fixed a bug where we didnt actually call the fini funcs (nobody
is using it though).
2013-02-14 06:47:38 -08:00
mwilliams 2f9f1a705b Fix QuickTests to work under hhvm 2013-02-13 06:44:30 -08:00
aravind 387a3555e2 Fix cgOpSub
Don't call cgNegateWork() for Type::Dbl operands.
2013-02-13 06:44:30 -08:00
ottoni 8a119496e1 fb_call_user_func_safe_return should try the autoloader
The interpreter apparently does so, but the JIT doesn't.
I suspect this is what is causing the problem reported in the
task. However, I can't reproduce (or properly test) it.

I believe we need a scenario with a least two requests. The first
request has seen the callee function by the time it translates
FPushCufSafe, so that it doesn't interpOne this instruction.  The
second request hasn't loaded the callee by the time it runs this
translation, so it misses in the TargetCache (at which point it should
try the autloader).
2013-02-13 06:44:30 -08:00
alia 5662a67f12 Cleaned up and added functionality to HHIR's handling of static properties and classes.
Broke LdClsPropAddr into 2 instructions by introducing a
ldClsPropAddrCached. LdClsPropAddrCached loads the static property via
the target cache so requires the class and property name to be
compile-time constants. LdClsPropAddr does not use the target cache
and works even if the property and class names are not constant.

Similarly broke LdCls into 2 by introducing LdClsCached. LdClsCached
uses the target cache to handle the case where the class name is a
compile time constant. Added code to detect cases where the class name
can be folded to a Class* constant.

Moved the code that decides between LdCls (LdClsPropAddr) and
LdClsCached (LdClsPropAddrCached) to the simplifier, allowing us to
optimize these instructions as optimization passes discover more
constants.

Changed HhbcTranslator code generation for AGet* and getClsPropAddr to
handle more cases using the above new instructions. Also improved
HhbcTranslator's translations for self and parent bytecodes.

Added a label to LdClsPropAddr to allow control flow when property is
not accessible. This enables implementation of IssetS (which was
incorrect before this diff) and EmptyS.

Implemented BindS, VGetS, EmptyS, and LateBoundCls.

Opportunitistically introduces calls to SSATmp::isA(...) to replace
explicit comparisons against Type::Tag values.

Moved AddElem punt from code generator to hhbctranslator so that we
can interpone.
2013-02-13 06:44:30 -08:00
mwilliams ac63ae02c6 Make TestServer work under hhvm 2013-02-13 06:44:30 -08:00
bsimmers f3a6aaee37 Fix TRACE=punt:1
One of the places that sets m_lastHHIRPunt was lost in
D705347. This will still capture punts that causes partial tracelet
interp because that translation ends up being a full-tracelet punt
when the IR tries to translate it again.
2013-02-13 06:44:20 -08:00
jdelong bbdf9729fb Fix another bug in exception handling
It's not ok for the unwinder to use a reference to elements
living in the m_faults array, since the unwinder can re-enter the VM
when calling destructors (or the FunctionExit hook).  If one of those
re-entries does exception handling, it can modify m_faults.
Additionally, gets rid of VMPrepareThrow and instead just throw Object
and use the same case as we do when exceptions came from an extension.
I had to fix an assembler test catch handler to actually catch to keep
the assertion about m_faults on re-entry correct.
2013-02-13 06:43:40 -08:00
bsimmers 09e01875a0 Table-drive register allocation and codegen for simple native call ops
This diff adds a table containing information about native
helpers called by translated code. It is used by LinearScan and
CodeGenerator to replace the manual and somewhat error-prone
precoloring hints and calls to cgCallHelper. I discovered in the
process that many of these helpers didn't have any precoloring hints,
so register allocation for some things should be improved slightly.
Code generation should be otherwise unchanged.
2013-02-13 06:43:40 -08:00
bsimmers 26a6669575 Implement more of HhbcTranslator::VectorTranslator
- Implement SetProp and SetElem
- SpillStack before each helper call since they can throw
- Stub out the remaining unimplemented vector operations for more
  fine-grained punt counts
- Kill TraceBuilder::gen* wrappers for vector stuff
- Rearrange some of the fake DataTypes to not confuse gdb. Values are
  unaffected.
2013-02-13 06:43:40 -08:00
bsimmers 162b46fb99 Refine some use of types in the IR
- LdLocAddr now returns a properly typed pointer
- Audit and clean up every use of Type::Null
- Add Type::debugString for use in gdb (calling Type::isString often
doesn't work)
- PtrToStr and PtrToNull are statically known
2013-02-13 06:43:40 -08:00
mwilliams f5188b8fe9 Fixes for turning off jemalloc
Some assumptions were made about low memory that broke under
libc malloc.
2013-02-13 06:43:40 -08:00
kma 0f9c93f9f9 Stop interp'ing at FCall.
When interp'ing an N-instruction tracelet, we ask the interpreter
to step through N instructions. The interpreter treats FCall as one of
those instructions, and happily starts interp'ing into the callee. This can
cause us to form weird tracelets in the callee that have no business
existing. Instead, break on any control-flow we encounter.
2013-02-13 06:43:40 -08:00
mwilliams 5ed74f1e03 Use Central repo for RepoAuthoritative repo generation
The central repo is always writable, so use that for writing,
and disable the local repo, so that hphp doesnt try to open
the default central repo, which can cause contention if there
are a lot of processes.
2013-02-13 06:43:40 -08:00
bsimmers d9943ae3c5 Fix bugs in cgGetCtxFwdCall
It was testing the low bit of the destination register before
moving the context to be tested into it, and if the low bit of that
register happened to be set already, nothing was ever put into the
destination reg. In certain situations this was causing fatals from a
null $this in instance methods.
2013-02-13 06:43:39 -08:00
mwilliams f109b02c7d Make stack based StringData safer
If you allocate a StringData on the stack, and it escapes,
you're in trouble. Make the destructor assert by default,
and add a StackStringData which does the appropriate
refCounting and checking.
2013-02-13 06:42:47 -08:00
mwilliams ac0ec5696a Fixup some array helpers
Some StringData* helpers were forwarding to CStrRef
methods - which now forward to StringData* methods. Just
call the StringData* methods directly

Other methods were using stack allocated StringData's.
Thats pointlessly risky for slow-path code. Use a String
instead.
2013-02-13 06:42:47 -08:00
mwilliams 64b6d99ef2 More gcc-4.7.1 compilation issues 2013-02-13 06:42:47 -08:00
mwilliams e300bc8cce Fix nemo warnings
Setup for parameters was skipped by some cleanup of the use of
the WholeProgram flag. Re-enable it.
2013-02-13 06:42:47 -08:00
andrewparoski bc6703d03f Improve the 'key not present' error message for collections 2013-02-13 06:42:47 -08:00
jan aee58ac19e Allow null dependency in tail call
If a continuation yields null in a tail call, we end up failing on
throw_null_pointer_exception. Fix it.
2013-02-13 06:42:47 -08:00
ottoni c375ba70b0 Enable arithmetic involving FP
Although support for FP arithmetic was added to HHIR codegen, it was
not plumbed through.  So it was still punting to tx64 or interpreting
FP Add, Sub, Mul.  This diff enables these instructions, which had to
be changed to have a TypeParam.

This diff also implements some checking for IR instructions' dest
operands in debug mode.

Finally, this diff fixes the 'reduce' script, which got broken when an
HHIR banner generated by DumpIR was changed.
2013-02-13 06:42:47 -08:00
kma 1643cb1d17 Capture the before-punt part of the trace in IR.
Try to scoop up some more instructions in the IR. In a
sequence like:

  BoringInstrA
  BoringInstrB
  PuntInstr
  BoringInstrC

we used to punt the entire tracelet to interp. Now we do:

hhir:
  BoringInstrA
  BoringInstrB

interp:
  PuntInstr
  BoringInstrC

Rescuing BoringInstrC from PuntInstr is future work.
2013-02-13 06:42:43 -08:00
jdelong 51f0a5bd3b Style change to the pretty-print format for IR extra data 2013-02-13 06:42:43 -08:00
bsimmers 8572bdeb7f Put predefined type bit patterns in an enum
This enables gdb to print something more useful than just the
raw integer when inspecting a Type. It also made the union macros
self-documenting and cleaned up the initialization in ir.cpp.
2013-02-13 06:42:43 -08:00
jdelong cf7133b406 Remove ConstInstruction and use a new extra data for DefConst 2013-02-13 06:42:43 -08:00
jdelong a44b190095 Remove LdHome from HHIR; use extra data for local ids
Removes all uses of Type::Home in the IR.  Rather than moving
the local ids into SSATmps via DefConst, beefs up IRExtraData (adding
support for CSE-able extra data and pretty printing them), so we can
use a new LocalId extra data type for all these instructions.  This
should save us a decent number of of ConstInstructions and reduce the
size of the IR, while also making accesses to local ids a little less
untyped.
2013-02-13 06:42:43 -08:00
jdelong e69e05711a Remove clearCountedMapNotIn since it seems impossible
The m_locs map is keyed on SSATmps that are Type::Home.  I
can't see any code path that can insert one of these into m_unescaped,
so remove it.
2013-02-13 06:42:43 -08:00
alia 3cf77e2df9 Implemented is[N]Type and JmpIs[N]Type in HHIR. 2013-02-13 06:42:43 -08:00
bsimmers 7fd841e6c1 Limit number of test jobs to 20 max 2013-02-13 06:42:43 -08:00
smith f3ddbe63f1 Remove the LdCls exception from IRInstruction::isEssential
LdCls is not used as a guard so that term should never be true.
2013-02-11 12:39:50 -08:00
bsimmers 1e4b0ed05b PtrTo* only needs one register 2013-02-11 12:39:50 -08:00
jdelong 2406e11d44 Fix a bug in FPushFuncD 2013-02-11 12:39:50 -08:00
mwilliams 1e54607680 Dont use free for low_malloc'd memory
In the case of a race to create a new class, we did
that, corrupting jemalloc's data structures in strange ways
(it didnt notice, even with a debug build, but bad things
happened later)
2013-02-11 12:04:10 -08:00
jan 28116234fb Use o_instanceof instead of dynamic_cast<>
Avoid dynamic_cast<> on fast paths, use o_instanceof(StaticString)
instead. Saves about ~0.2-0.3% of CPU time.

Once HPHPc is gone, we will convert these calls to HHVM-specific API.

Thanks @bmaurer for discovery and @mwilliams for suggestion how to fix
it.
2013-02-11 12:04:10 -08:00
Sara Golemon 337f15cc8d Sync system generated files 2013-02-11 11:45:25 -08:00
mwilliams a18dd73d06 Better initTrace
The old version read the first element of the array into $top,
checked some values on it, and then either shifted the first
element into $frame, or shifted it off and discarded it.

So its cheaper to just shift it directly into $top, and then
use $top rather than $frame.
2013-02-11 10:10:23 -08:00
jdelong 067e38c23d Fix exception safety for inline returns
If the profiler hook throws (and it used to not be able to),
we can decref a local twice.  The generic return case is safe, but the
inline return case wasn't zeroing the type.
2013-02-11 10:10:23 -08:00
mwilliams 2db86bd721 Remove pthread_setspecific calls
ThreadLocalSingleton had an s_key static property, and called
pthread_setspecific using it. In the USE_GCC_FAST_TLS case. Both
are unneeded, so remove them.
2013-02-11 10:09:31 -08:00
jan 527a155239 Export is{Finished,Succeeded,Failed} methods to PHP
In some cases, it may be useful to be able to check the current status
of wait handle. One particular use case is DynamicYield's get().
2013-02-11 08:55:54 -08:00
mwilliams 1bc06a26cf Fixes for gcc-4.7.1 compilation
g++-4.7.1 treats "FOO"bar as a c++-11 literal operator, even
if bar is a macro with an expansion such as "BAR" - so add a space
after the quote (this seems like a bug, and I fixed a bunch of these
a while ago, but we just added a slew of PRI*64 macros which break
under 4.7.1).

Also, it warned that "explicit by-copy capture of 'this' redundant"
for a lambda declared [=, this] - so I removed the this.

We also needed more than the 60 levels of template expansion that was
allowed by the makefile.
2013-02-11 08:55:54 -08:00
jdelong 76681bfc14 Print arena size after HHIR translations 2013-02-11 08:55:54 -08:00
jan 740868989c Make the individual bytes of o_subclassData easily accessible 2013-02-11 08:55:54 -08:00
jan 26c2654528 Less virtual calls, more predictive layout 2013-02-11 08:55:54 -08:00
jdelong bab632f35a Remove MarkerInstruction and use extra data for it 2013-02-11 08:13:21 -08:00
jdelong 51ffd22f03 Implement SSwitch; add support for instruction "extra data"
Implements the SSwitch opcode.

This involved adding an instruction that needed a whole switch table
of compile-time data, so rather than encode this in SSATmps or adding
a new internal type this adds support for every instruction to have an
associated C++ structure of extra data.  We should be able to move
Marker Label and ConstInstruction to use this, so this extra pointer
will be free since the vtable will be able to go away; we'll also be
able to save down this route by allocating fewer ConstInstructions for
compile-time data.
2013-02-11 08:13:21 -08:00
jan 03c8d47acb Unbox references in CWH::markCurrentAsSucceeded()
Seems that the calling convention allows values to be passed by
reference and it's up to the extension to unbox them.
2013-02-11 08:13:21 -08:00
Sara Golemon a4903eb14e Modify undefined property error to match Zend 2013-02-11 08:12:53 -08:00
Sara Golemon 9efb3c8e25 Expose driver-specific error code in PDOException
Match Zend behavior
2013-02-11 08:12:53 -08:00
mwilliams c21f2c3966 We dont need a boost::shared_ptr for m_bt in ExtendedException
Array is already a SmartPtr, wrapping it in another is pointless.
Except it turns out that there are include dependencies preventing
us from using Array here. Use boost::intrusive_ptr to wrap an
ArrayData instead.
2013-02-11 08:12:53 -08:00
jdelong 3a5087077f Fix release build wrt zend_html.cpp 2013-02-11 07:54:46 -08:00
jdelong dc8cc4656b Make the parser possible to test without compiling libhphp_runtime.a 2013-02-11 06:59:06 -08:00
jdelong 00b2101db0 Move zend_html to util so util/parser doesn't depend on the runtime 2013-02-11 06:59:06 -08:00
jdelong 3248a83461 Make ext_string not depend on zend_html, so it can be moved to util
The parser depends on zend_html, which means it's impossible
to write parser unit tests without compiling all of hphp.  This
separates the pieces that use runtime structures into ext_string, so
the rest can be moved to util/zend.  There was a raise_warning call
indirectly from string_html_decode (in determine_charset), but the
runtime use of string_html_decode already checks that it is a
supported charset and otherwise throws NotImplementedException, so I
removed this.  Another diff will do the actual move to util.
2013-02-11 06:59:06 -08:00
ptarjan 14c9e841c8 capital C in Closure
According to our PHP style guide http://www.phabricator.com/docs/phabricator/article/PHP_Coding_Standards.html classes start with capital letters
2013-02-11 06:59:06 -08:00
ptarjan 839bb3103e break out emitFPass 2013-02-11 06:59:06 -08:00
andrewparoski dec99505a6 Refactor iterator logic
This diff refactors some of the VM's logic for iterators (with a focus on
mutable iteration), delivering several improvements:
  1) MIterCtx was renamed to MArrayIter, and the m_key and m_val fields
     were eliminated.
  2) Eliminated the need for MArrayIter to dynamically allocate a
     MutableArrayIter object, and removed other layers of indirection as
     well.
  3) Reduced the size of HPHP::VM::Iter from 64 bytes down to 32 bytes.
  4) Removed the "if (siPastEnd())" check when adding a new element to an
     HphpArray or a ZendArray.
  5) Moved all of the iterator logic into a single .cpp file.

This diff reworks FullPos's to point to current element instead of pointing
to the next element. It also splits up the IterFree instruction into two
instructions (IterFree and MIterFree). These changes allowed various logic
to be simplified and data structures to be reduced in size. There is
definitely more opportunity for refactoring, but I know the JIT helpers for
iteration have been carefully tuned and so I'll leave further refactoring
for future diffs.

Finally, I spent a little time cleaning up the bytecode spec a bit, mostly
with respect to iteration.
2013-02-11 06:36:51 -08:00
ptarjan f3cf268bb1 create onClosureStart
For parity with onFunctionStart we should have an onClosureStart. It was really confusing to start with onFunctionStart and then end with onClosure.
2013-02-11 06:36:50 -08:00
ptarjan 5455370de0 add space to error message 2013-02-11 06:36:50 -08:00
ottoni 116bb2c662 Mark runtime helpers as hot, and get rid of some of them
This diff marks runtime helpers called from HHIR-generated code as hot.
In addition, it also eliminates some of the intermediate helpers.
2013-02-11 06:36:50 -08:00
jdelong cc5cc6d5cb Print IRInstruction iids instead of m_id in IRInstruction::print 2013-02-11 06:36:50 -08:00
bertrand cc863bf301 Implement AKExists in HHIR
Implements AKExists in HHIR.  I've added a new IR opcode for it which
basically generates a call to helper method (which is very similar to
the tx64 helper).  The major difference is putting the decrefs in the
IR rather than the helper.
2013-02-11 06:36:50 -08:00
bsimmers e09dbb6f89 Add Type::equals 2013-02-11 06:36:30 -08:00
mwilliams 5acac417e2 Fix issues when Exception::__init__() throws
We were calling Exception::__init__() from Instance's constructor.
If an exception is thrown (eg timeout), then we capture a backtrace
including $this pointers, unwind, and then pass the backtrace
to the error handler. But as c++ unwinds through Instance's
constructor, it calls ObjectData's destructor - so we end up
with a lame instance that doesnt work too well.

In addition, we were failing to correctly refCount the object
so we would leak its memory (and properties).
2013-02-11 06:36:29 -08:00
bsimmers b17ec4702a Kill Type::Tag and make Type an opaque class backed by a bitvector
Every non-union type has been assigned a bit between 0 and
47. This includes Boxed*, PtrTo*, and PtrToBoxed* for all PHP-visible
types. There are static const members of Type for all of these, along
with all the union types that used to be in Type::Tag (Cell, Gen,
Uncounted, etc...). Arbitrary union types can now be easily composed
using Type::operator|. Switching on types and comparing using any
operator other than == are no longer allowed. Also gone is
Type::isRefCounted (since the exact needs of code using it can be
unclear), replaced by maybeCounted and notCounted.

Type::Tag still exists as a typedef for Type itself; I'm going to fix
up all of the useage sites in a separate diff to keep this more
manageable. I'm also planning on introducing operator< and operator<=
on Type as synonyms for structSubtypeOf and subtypeOf,
respectively. That will happen after this diff goes in, ensuring that
all old-style uses of those comparisons are dead.
2013-02-11 06:36:22 -08:00
mwilliams f6efec4d7c Enable CodeError generation under hhvm
Just when running as hphp, so we can use the USE_HHVM version
of hphp to generate the reports
2013-02-11 06:32:54 -08:00
mwilliams 75948e48f7 Fix leaks/asserts in ext_curl
When a callback throws an exception, we catch it, and then handle
the exception after the libcurl function that invoked the callback
returns.

But we weren't checking the exception after some libcurl calls that
could invoke callbacks, which leaked the exception object in RELEASE
builds, and asserted in DEBUG builds.
2013-02-11 06:32:54 -08:00
bsimmers 3286e1d7c0 Check RuntimeOption::RepoCommit in Repo::commitUnit instead of callers 2013-02-11 06:32:54 -08:00
Sara Golemon d6be84e026 Sync system files 2013-02-11 06:31:00 -08:00
jan 0763e566f4 Instance::cloneSet: do not initialize dynamic properties if no properties to clone
Instance::cloneSet() unnecessarily creates HPHP array even if cloned
object has no dynamic properties. Don't do this.
2013-02-11 06:07:23 -08:00
smith 8c57d016d5 Move dead code elimination state out of IRInstruction
Introduced a state table for DCE, indexed by IId, instead
of using IRInstruction.id for the transient state of DCE
analysis.
2013-02-11 06:07:23 -08:00
ottoni 44dc3b58f4 Make memelim less conservative about locals
The memelim pass was being overly conservative by assuming that all
boxed locals can be modified by any instruction marked as
MayModifyRefs.  However, we know that this cannot happen for locals
that have not escaped.  This diff uses this fact to be less
conservative for functions other than pseudo-mains.
2013-02-11 06:07:23 -08:00
jdelong b24236e602 Re-enable InstanceOfD translation and fix NInstanceOf 2013-02-11 06:07:23 -08:00
mwilliams dbab820ff4 The fixup for a generator shouldnt include any locals
If a "surprise" happened during the prolog for a continuation,
the fixed-up $rbx was too low by the number of locals. This
resulted in the unwinder trying to unwind through garbage,
with unpredictable results
2013-02-11 06:07:23 -08:00
Owen Yamauchi 441fb578ec Delete pathtrack
This isn't being used right now.
2013-02-11 06:07:22 -08:00
aalexandre 755d38157f Fix serialization test failure introduced by inttypes
It seems serialization is sensitive to the alias name for int64.
2013-02-11 06:07:22 -08:00
andrewparoski 4196354f4f Fix parse issues with function types
Fix the parser to handle function types for functions that have no formal
parameters and for functions that take variable arguments.
2013-02-11 06:07:22 -08:00
andrewparoski f7dd399bd6 Fix handling of "$obj->{__FUNCTION__}" and "$obj->{__CLASS__}"
For "$obj->{__FUNCTION__}" and "$obj->{__CLASS__}", we currently don't
recognize __FUNCTION__ and __CLASS__ as "magic constants" and we just use
the literal strings "__FUNCTION__" and "__CLASS__" for the property names.
This is wrong. Same goes for object method calls (ex. "$obj->{..}(..)").

This diff fixes HipHop to recognize magic constants for properties names in
"$obj->{..}" expressions and method names in "$obj->{..}(..)" expressions.
2013-02-11 06:07:22 -08:00
mwilliams 0b586489c9 Remove a too aggressive assert
There was an assert that the statically inferred type was at least
as good as the runtime type. The new test case shows clearly why
that cannot be the case (and we were tripping over this assert
in production).
2013-02-11 06:07:21 -08:00
jdelong 31222e2c84 Fix another bug in "Fix a bug in exception handling"
When we skip EHEnts for catch blocks that we aren't going to
enter, we still need to count them in the handledCount so that we run
the appropriate fault funclet (see the unit test).  Before this
change, it would fail to account for the catch handler and end up
running the fault funclet twice, leading to an assertion about
IterFree trying to free an already-freed iterator.
2013-02-11 06:07:21 -08:00
smith d87811fd9b Support control flow in HHIR
Add support for in-trace control flow to HHIR.  To support
merging SSATmps, add support for 1+ sources to Jmp_ and
1+ destinations to DefLabel.  (One must use Jmp_ to pass
values to a label).

Every pass is affected by this.  The linearscan passes were
modified to visit blocks in reverse postorder (linear scan
should work even early blocks are not dominators of later
blocks).

Other passes had to be pessimized a bit because the dominator
assumption no longer holds.  Either they need to do full
dataflow analysis, be changed to do preorder traversals
down the dominator tree, changed to work only on a block
at a time, or fully disabled if control flow is detected.
2013-02-11 06:07:21 -08:00
smith 6492f650f5 Disable spilling to MMX registers in HHIR
... Until we have an assert(m_curInst->isNative()) in cgCallHelper
and fix our flags.  Without accurate flags, we can choose to spill
to an MMX register, then do a call anyway.
2013-02-11 06:07:21 -08:00
aalexandre d09fd3e421 inttypes conversion broken down by steps.
Per @mwilliams' suggestion, this is the first stage in a staggered approach to replacing int64 with int64_t. More precisely I inserted "typedef ::int64_t int64;" in util/base.h and dealt with the consequences.
2013-02-11 06:07:07 -08:00
jdelong 5baef2646d Disable InstanceOfD
This is breaking HHIR sandboxes and trunk should work.  I'm
not sure how long it will take me to debug so let's turn it off for
now.
2013-02-11 03:50:50 -08:00
alia 22541f491c Improved HHIR translation for AGetC.
Improved the way HHIR translates AGetC by generating a
defConst<Class> for the case where the loaded class is the same as or
a superclass of the context class. This eliminates an unnecessary
runtime class lookup (LdCls). Documented LdClsPropAddr.
2013-02-11 03:50:50 -08:00
smith a4b2eea173 Spill and Reload take any input type
were marked S(Gen) but can be anything, e.g. Gen*.  Also, Mov needed to be unrestricted.  Added an assert and todo in case Mov is used with types that use both registers.
2013-02-11 03:44:07 -08:00
ottoni e3d0c97679 Implement NullUninit 2013-02-11 03:44:07 -08:00
jdelong 795400d899 Table-drive type checking for IR opcodes
The way type.cpp was handling return types wasn't quite
sufficient for multiple destinations and unfortunately added a step
that's easy to forget when you add new opcodes with the HasDest flag.
Also, assertions about operand types are too distributed through the
code.  Pull everything into a central table, similar to hhbc.h.  This
still leaves several opcodes without type signatures, since figuring
it out got a bit tedious for now.  It did uncover a few documentation
bugs in ir.specification, though.
2013-02-11 03:44:07 -08:00
jdelong 5483751a25 Fix a bug when you print a DefConst of a NamedEntityPtr 2013-02-11 03:44:07 -08:00
jdelong 4797536f9d Fix a bug when throwing from nested FPI regions
Since we now use the original throw location to figure out
which EHEnt applies when propagating from a fault funclet, we need to
check whether we've already unwound the ActRec before doing it again.
Doing it again could cause issues with nested FPI regions (hitting an
assert in sandboxes).
2013-02-11 03:44:06 -08:00
mwilliams c67d35c50a The trouble with magic numbers...
... is that once you put them into the codebase, the odds of them
showing up where you dont want them go up dramatically.

With a gcc 4.7.1 -O0 build I hit a consistent crash in production
where debugBacktrace had stepped too far, thinking that the
first non-vm frame was in fact a vm frame. It did so because
it looked at the word above the frame, and saw that it contained
c_Continuation::kMagic.

It turns out that fixupWork's isVMFrame left kMagic in $rdx if the
frame really was a generator ($rdx was dead, but still). We then
return from the tc via a serviceReq that doesnt need $rdx (so doesnt
set it), and then (with a following wind, so that $rdx hasnt been
smashed yet) enterTCHelper stores $rdx in info.args[1].

By another staggering coincidence, info.args[1] is at exactly the
right address to make the call into enterTCHelper /look/ like a
a continuation (based on kMagic). So if we then have a catch
which re-enters the TC there's a good chance kMagic is still there
and the next debugBacktrace (or uncaught exception) will crash.

This diff rewrites everything in terms of the C++ stack; we
now say that its a VM frame if its not on the C++ stack.
2013-02-11 03:44:06 -08:00
mwilliams 453c9938c9 Dont leave 1.txt lying around 2013-02-11 03:44:06 -08:00
Owen Yamauchi 3e19c90b93 Macros for getting machine registers
This kind of business obviously doesn't work on non-x64 platforms, so
let's abstract it out into platform-specific macros. I've also changed
some of the associated variable names, to try to break people of the
habit of only thinking about x64.

There are a few instances of this trick remaining, referencing rbx and
r15. These are a little more of a pain to abstract out because their
roles are defined by our internal ABI rather than an architecture's ABI,
so their ARM equivalents will have to be tied to our ARM register
allocation convention. These will have to wait a bit.
2013-02-11 03:44:06 -08:00
bertrand bed8c0e6fe Don't allow nulls in regexes passed to preg_replace
Summary: If we allow null characters in a regex, then a user could construct a string that ends with "/e\0" and surreptitiously execute an arbitrary piece of code.  With this patch we fatal if a null is found anywhere before the end of the regex (determined by length()).
2013-02-11 03:44:06 -08:00
aravind 1b83a11ee8 Fix shuffleArgs
shuffleArgs() logic was broken if rScratch was used as part
of the suffle.
2013-02-11 03:44:06 -08:00
ottoni 94081c2cbc Get rid of "Ptr" from the name of internal types
shorter
more consistent with other types (e.g. Obj is a pointer too)
makes some of them more consistent, e.g. FuncClassPtr should
actually be FuncPtrClassPtr in the old scheme
2013-02-11 03:44:06 -08:00
mwilliams c7959bbe6a Fix some warnings at -O1
While tracking down gcc 4.7.1 issues I tried a -O1 build,
and got uninitialized variable warnings. None of them is
real, and at -O3 the compiler can figure out that the variables
are never actually used uninitialized.
2013-02-11 03:44:06 -08:00
alia 94aed72d26 Implemented Issets in HHIR.
Implemented Issets in HHIR. Added 2 new IR opcodes,
IsTypeMem<T> and IsNTypeMem<T>, that test the type of a given Cell* or
Gen*. We should be able to use them for IssetM as well. Fixed a bug in
simplifyIsType: We were not correctly folding the isType query when
the source was a static string. Removed a few unnecessary instructions
that cleared the top bits of a boolean register; booleans are
represented only in the lower byte of a register so its unnecessary to
clear the top bits.
2013-02-11 03:44:06 -08:00
aravind 6ac06a50eb Fix RetCtrl for Eval.HHIRGenerateAsserts=1 2013-02-11 03:44:05 -08:00
aravind 5e7c9d3457 Fix assert for LdRetAddr 2013-02-11 03:44:05 -08:00
aravind 1eeb100510 Delay pushing return address till RetCtrl
LdRetAddr used to modify rsp, which would break
any rsp relative Reload instructions before returning.
2013-02-11 03:44:05 -08:00
ottoni 6a4ec5ae0e Implement FPushClsMethodF in HHIR 2013-02-11 03:44:05 -08:00
mwilliams 52697c84a0 Fix profiling of continuations
In the interpreter, neither ContEnter nor ContExit checked the
surprise flags, resulting in the time being attributed to the
callers. In the jit, ContEnter checked the surprise flags, but
ContExit did not, resulting in what appeared to be highly
recursive profiles.
2013-02-11 03:44:05 -08:00
ottoni c4956fac10 Fix LdClsCns
The loaded value is guaranteed to be a Cell, so no exit label (and
check) is needed.
2013-02-11 03:44:05 -08:00
Sara Golemon ddd8720bf4 Update third_party/folly 2013-02-11 03:44:05 -08:00
vini 84d9aa7236 Update ext_icu_spoof test 2013-02-11 02:16:23 -08:00
Jordan Delong 363d1bb20f Code move src/ -> hphp/
This change is mostly for FB internal organizational reasons.
Building is not effected beyond the fact that the target now
lands in hphp/hhvm/hhvm rather than src/hhvm/hhvm.
2013-02-11 02:10:41 -08:00
34247 arquivos alterados com 1410806 adições e 1388121 exclusões
+45 -78
Ver Arquivo
@@ -8,102 +8,69 @@
.mkdir
hphp.log
/src/test/test
/src/test/test_fast.inc
/src/test/test_mysql_info.inc
/src/test/test_suite.inc
/src/test/real_mysql_info.inc
/src/test/*.tmp
/src/test/vm/*.out
/src/test/vm/*.diff
/src/test/vm/*.log
/src/test/vm/*.reduce_out
/src/test/vm/*.reduce_diff
/src/test/vm/*.reduce_exp
/src/test/vm/*.perf
/src/test/vm/perf/*.out
/src/test/vm/perf/*.diff
/src/test/vm/perf/*.perf
/src/runtime/ext_hhvm/xconstants.php
/src/runtime/ext_hhvm/ext_hhvm_infotabs.cpp
/src/runtime/ext_hhvm/ext_noinline.cpp
/src/compiler/analysis/code_error.inc
/hphp/test/test
/hphp/test/test_fast.inc
/hphp/test/test_mysql_info.inc
/hphp/test/test_suite.inc
/hphp/test/real_mysql_info.inc
/hphp/test/*.tmp
/hphp/test/vm/*.out
/hphp/test/vm/*.diff
/hphp/test/vm/*.log
/hphp/test/vm/*.reduce_out
/hphp/test/vm/*.reduce_diff
/hphp/test/vm/*.reduce_exp
/hphp/test/vm/*.perf
/hphp/test/vm/perf/*.out
/hphp/test/vm/perf/*.diff
/hphp/test/vm/perf/*.perf
/hphp/runtime/ext_hhvm/ext_noinline.cpp
/hphp/compiler/analysis/code_error.inc
/src/runtime/tmp/Test*
/src/runtime/tmp/run
/src/runtime/tmp/run.sh
/src/runtime/tmp/libtest.so
/src/runtime/vm/repo_schema.h
/src/runtime/base/compiler_id.h
/hphp/runtime/tmp/Test*
/hphp/runtime/tmp/run
/hphp/runtime/tmp/run.sh
/hphp/runtime/tmp/libtest.so
/hphp/hphp_build_info.cpp
/hphp/hphp_repo_schema.h
/src/hphpi/gen
/src/hphpi/hphpi
/hphp/hhvm/gen
/hphp/hhvm/hhvm
/src/hhvm/gen
/src/hhvm/hhvm
/src/hhvm/hphp
/hphp/runtime/ext/*.ext_hhvm.cpp
/hphp/runtime/ext/*.ext_hhvm.h
/hphp/runtime/ext/*/*.ext_hhvm.cpp
/hphp/runtime/ext/*/*.ext_hhvm.h
/hphp/runtime/base/builtin_functions.cpp.ext_hhvm.cpp
/hphp/runtime/base/builtin_functions.cpp.ext_hhvm.h
/hphp/runtime/ext_hhvm/ext_hhvm_infotabs.cpp
/hphp/runtime/ext_hhvm/ext_hhvm_infotabs.h
/src/tools/shmw/shmw
/hphp/tools/shmw/shmw
/src/ffi/java/classes
/src/ffi/java/hphp_ffi_java.h
/hphp/ffi/java/classes
/hphp/ffi/java/hphp_ffi_java.h
# Ignore all makefiles generated for fbcode's third-party repo
/bin/*.mk
!/bin/run.mk
/facebook/arcanist/.phutil_module_cache
/facebook/autoload_files
/facebook/hotcold.hdf
/facebook/benchmark/shootout/output_bench
/facebook/benchmark/shootout/output_bintree_new
/facebook/libcore_files
/facebook/output_*
/facebook/push/install
/facebook/stub_funcs.hdf
/facebook/volatile.hdf
/facebook/www.pid
/facebook/push/apc
/facebook/push/apclog
/facebook/push/autoload_files
/facebook/push/hotcold.hdf
/facebook/push/output_www
/facebook/push/system.tgz
/facebook/push/volatile.hdf
/facebook/push/stub_funcs.hdf
/facebook/push/output
/facebook/push/shared
/facebook/extensions/gen
/facebook/extensions/hphpi
/local/*.mk
CMakeFiles
CMakeCache.txt
cmake_install.cmake
install_manifest.txt
/output_gd/
/src/TAGS
# arcanist working-copy settings
.arc/
# fbcode output directory
/bin/_fbcode_bin/
/hphp/TAGS
# Generated makefiles
/src/third_party/lz4/Makefile
/src/third_party/double-conversion/Makefile
/src/third_party/folly/Makefile
/src/runtime/ext_hhvm/Makefile
/src/test/Makefile
/src/hphp/Makefile
/src/hhvm/Makefile
/src/compiler/Makefile
/src/Makefile
/hphp/runtime/ext_hhvm/Makefile
/hphp/test/Makefile
/hphp/hphp/Makefile
/hphp/hhvm/Makefile
/hphp/compiler/Makefile
/hphp/Makefile
/Makefile
# eclipse files
+13
Ver Arquivo
@@ -0,0 +1,13 @@
language: cpp
compiler:
- gcc
before_script:
- ./configure_ubuntu_12.04.sh
# for some tests
- sudo locale-gen de_DE && sudo locale-gen zh_CN.utf8 && sudo locale-gen fr_FR
- HPHP_HOME=`pwd` make -j 8
script: hphp/hhvm/hhvm hphp/test/run quick slow zend
notifications:
irc: "chat.freenode.net#hhvm"
+14
Ver Arquivo
@@ -56,6 +56,20 @@ if(ICU_INCLUDE_DIR AND ICU_LIBRARY)
set(ICU_I18N_FOUND 0)
set(ICU_I18N_LIBRARIES)
endif (ICU_I18N_LIBRARY)
# Look for the ICU data libraries
find_library(
ICU_DATA_LIBRARY
NAMES icudata cygicudata cygicudata32
DOC "Libraries to link against for ICU data")
mark_as_advanced(ICU_DATA_LIBRARY)
if (ICU_DATA_LIBRARY)
set(ICU_DATA_FOUND 1)
set(ICU_DATA_LIBRARIES ${ICU_DATA_LIBRARY})
else (ICU_DATA_LIBRARY)
set(ICU_DATA_FOUND 0)
set(ICU_DATA_LIBRARIES)
endif (ICU_DATA_LIBRARY)
else(ICU_INCLUDE_DIR AND ICU_LIBRARY)
set(ICU_FOUND 0)
set(ICU_I18N_FOUND 0)
+10 -1
Ver Arquivo
@@ -51,5 +51,14 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibElf DEFAULT_MSG
LIBELF_LIBRARIES
LIBELF_INCLUDE_DIRS)
SET(CMAKE_REQUIRED_LIBRARIES elf)
INCLUDE(CheckCXXSourceCompiles)
CHECK_CXX_SOURCE_COMPILES("#include <libelf.h>
int main() {
Elf *e = (Elf*)0;
size_t sz;
elf_getshdrstrndx(e, &sz);
return 0;
}" ELF_GETSHDRSTRNDX)
mark_as_advanced(LIBELF_INCLUDE_DIRS LIBELF_LIBRARIES)
mark_as_advanced(LIBELF_INCLUDE_DIRS LIBELF_LIBRARIES ELF_GETSHDRSTRNDX)
+1 -1
Ver Arquivo
@@ -29,7 +29,7 @@
#-------------- FIND MYSQL_INCLUDE_DIR ------------------
FIND_PATH(MYSQL_INCLUDE_DIR mysql/mysql.h
FIND_PATH(MYSQL_INCLUDE_DIR mysql.h
$ENV{MYSQL_INCLUDE_DIR}
$ENV{MYSQL_DIR}/include
/usr/include/mysql
+27
Ver Arquivo
@@ -0,0 +1,27 @@
# - Try to find libpthread
#
# Once done this will define
#
# LIBPTHREAD_FOUND - system has libpthread
# LIBPTHREAD_INCLUDE_DIRS - the libpthread include directory
# LIBPTHREAD_LIBRARIES - Link these to use libpthread
# LIBPTHREAD_DEFINITIONS - Compiler switches required for using libpthread
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
if (LIBPTHREAD_LIBRARIES AND LIBPTHREAD_INCLUDE_DIRS)
set (LIBPTHREAD_FIND_QUIETLY TRUE)
endif (LIBPTHREAD_LIBRARIES AND LIBPTHREAD_INCLUDE_DIRS)
find_path (LIBPTHREAD_INCLUDE_DIRS NAMES pthread.h)
find_library (LIBPTHREAD_LIBRARIES NAMES pthread)
include (FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBPTHREAD DEFAULT_MSG
LIBPTHREAD_LIBRARIES LIBPTHREAD_INCLUDE_DIRS)
mark_as_advanced(LIBPTHREAD_INCLUDE_DIRS LIBPTHREAD_LIBRARIES LIBPTHREAD_FOUND)
+40 -48
Ver Arquivo
@@ -18,13 +18,7 @@
include(CheckFunctionExists)
# boost checks
find_package(Boost 1.37.0 COMPONENTS system;program_options;filesystem REQUIRED)
if (BOOST_VERSION EQUAL 104200)
# Boost bug #3942 prevents us using 1.42
message(FATAL_ERROR "Boost 1.42 is not compatible with HipHop")
endif()
find_package(Boost 1.48.0 COMPONENTS system program_options filesystem regex REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
@@ -134,25 +128,15 @@ find_package(EXPAT REQUIRED)
include_directories(${EXPAT_INCLUDE_DIRS})
# SQLite3 + timelib are bundled in HPHP sources
include_directories("${HPHP_HOME}/src/third_party/libsqlite3")
include_directories("${HPHP_HOME}/src/third_party/timelib")
include_directories("${HPHP_HOME}/src/third_party/libafdt/src")
include_directories("${HPHP_HOME}/src/third_party/libmbfl")
include_directories("${HPHP_HOME}/src/third_party/libmbfl/mbfl")
include_directories("${HPHP_HOME}/src/third_party/libmbfl/filter")
include_directories("${HPHP_HOME}/src/third_party/lz4")
include_directories("${HPHP_HOME}/src/third_party/double-conversion/src")
include_directories("${HPHP_HOME}/src/third_party/folly")
FIND_LIBRARY(XHP_LIB xhp)
FIND_PATH(XHP_INCLUDE_DIR xhp_preprocess.hpp)
if (XHP_LIB AND XHP_INCLUDE_DIR)
include_directories(${XHP_INCLUDE_DIR})
set(SKIP_BUNDLED_XHP ON)
else()
include_directories("${HPHP_HOME}/src/third_party/xhp/xhp")
endif()
include_directories("${HPHP_HOME}/hphp/third_party/libsqlite3")
include_directories("${HPHP_HOME}/hphp/third_party/timelib")
include_directories("${HPHP_HOME}/hphp/third_party/libafdt/src")
include_directories("${HPHP_HOME}/hphp/third_party/libmbfl")
include_directories("${HPHP_HOME}/hphp/third_party/libmbfl/mbfl")
include_directories("${HPHP_HOME}/hphp/third_party/libmbfl/filter")
include_directories("${HPHP_HOME}/hphp/third_party/lz4")
include_directories("${HPHP_HOME}/hphp/third_party/double-conversion/src")
include_directories("${HPHP_HOME}/hphp/third_party/folly")
# ICU
find_package(ICU REQUIRED)
@@ -193,8 +177,7 @@ if (USE_GOOGLE_HEAP_PROFILER AND GOOGLE_PROFILER_LIB)
endif()
endif()
if (USE_JEMALLOC AND NOT GOOGLE_TCMALLOC_ENABLED
AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
if (USE_JEMALLOC AND NOT GOOGLE_TCMALLOC_ENABLED)
FIND_LIBRARY(JEMALLOC_LIB jemalloc)
if (JEMALLOC_LIB)
message(STATUS "Found jemalloc: ${JEMALLOC_LIB}")
@@ -202,8 +185,7 @@ if (USE_JEMALLOC AND NOT GOOGLE_TCMALLOC_ENABLED
endif()
endif()
if (USE_TCMALLOC AND NOT JEMALLOC_ENABLED AND NOT GOOGLE_TCMALLOC_ENABLED
AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
if (USE_TCMALLOC AND NOT JEMALLOC_ENABLED AND NOT GOOGLE_TCMALLOC_ENABLED)
FIND_LIBRARY(GOOGLE_TCMALLOC_MIN_LIB tcmalloc_minimal)
if (GOOGLE_TCMALLOC_MIN_LIB)
message(STATUS "Found minimal tcmalloc: ${GOOGLE_TCMALLOC_MIN_LIB}")
@@ -215,6 +197,9 @@ endif()
if (JEMALLOC_ENABLED)
add_definitions(-DUSE_JEMALLOC=1)
if (APPLE)
add_definitions(-DJEMALLOC_MANGLE=1 -DJEMALLOC_EXPERIMENTAL=1)
endif()
else()
add_definitions(-DNO_JEMALLOC=1)
endif()
@@ -270,6 +255,10 @@ include_directories(${LDAP_INCLUDE_DIR})
find_package(Ncurses REQUIRED)
include_directories(${NCURSES_INCLUDE_PATH})
# libpthreads
find_package(PThread REQUIRED)
include_directories(${LIBPTHREAD_INCLUDE_DIRS})
find_package(Readline REQUIRED)
include_directories(${READLINE_INCLUDE_DIR})
@@ -281,6 +270,9 @@ include_directories(${LIBDWARF_INCLUDE_DIRS})
find_package(LibElf REQUIRED)
include_directories(${LIBELF_INCLUDE_DIRS})
if (ELF_GETSHDRSTRNDX)
add_definitions("-DHAVE_ELF_GETSHDRSTRNDX")
endif()
CONTAINS_STRING("${CCLIENT_INCLUDE_PATH}/utf8.h" U8T_DECOMPOSE RECENT_CCLIENT)
if (NOT RECENT_CCLIENT)
@@ -305,12 +297,9 @@ if (NOT CCLIENT_HAS_SSL)
add_definitions(-DSKIP_IMAP_SSL=1)
endif()
FIND_LIBRARY(CRYPT_LIB NAMES xcrypt crypt crypto)
if (LINUX OR FREEBSD)
FIND_LIBRARY (CRYPT_LIB NAMES xcrypt crypt)
FIND_LIBRARY (RT_LIB rt)
elseif (APPLE)
FIND_LIBRARY (CRYPT_LIB crypto)
FIND_LIBRARY (ICONV_LIB iconv)
endif()
if (LINUX)
@@ -344,6 +333,11 @@ if (FREEBSD)
endif()
endif()
if (APPLE)
find_library(LIBINTL_LIBRARIES NAMES intl libintl)
find_library(KERBEROS_LIB NAMES gssapi_krb5)
endif()
#find_package(BISON REQUIRED)
#find_package(FLEX REQUIRED)
@@ -351,8 +345,8 @@ endif()
# message(FATAL_ERROR "Flex is too old, found ${FLEX_VERSION} and we need 2.5.33")
#endif()
include_directories(${HPHP_HOME}/src)
include_directories(${HPHP_HOME}/src/system/gen)
include_directories(${HPHP_HOME}/hphp)
include_directories(${HPHP_HOME}/hphp/system/gen)
macro(hphp_link target)
if (GOOGLE_HEAP_PROFILER_ENABLED OR GOOGLE_CPU_PROFILER_ENABLED)
@@ -373,7 +367,7 @@ macro(hphp_link target)
target_link_libraries(${target} ${LIBUNWIND_LIBRARY})
target_link_libraries(${target} ${MYSQL_CLIENT_LIBS})
target_link_libraries(${target} ${PCRE_LIBRARY})
target_link_libraries(${target} ${ICU_LIBRARIES} ${ICU_I18N_LIBRARIES})
target_link_libraries(${target} ${ICU_DATA_LIBRARIES} ${ICU_I18N_LIBRARIES} ${ICU_LIBRARIES})
target_link_libraries(${target} ${LIBEVENT_LIB})
target_link_libraries(${target} ${CURL_LIBRARIES})
target_link_libraries(${target} ${LIBGLOG_LIBRARY})
@@ -404,9 +398,16 @@ if (FREEBSD)
target_link_libraries(${target} ${EXECINFO_LIB})
endif()
if (APPLE)
target_link_libraries(${target} ${LIBINTL_LIBRARIES})
target_link_libraries(${target} ${KERBEROS_LIB})
endif()
target_link_libraries(${target} ${BFD_LIB})
target_link_libraries(${target} ${BINUTIL_LIB})
target_link_libraries(${target} pthread)
if (${LIBPTHREAD_LIBRARIES})
target_link_libraries(${target} ${LIBPTHREAD_LIBRARIES})
endif()
target_link_libraries(${target} ${TBB_LIBRARIES})
target_link_libraries(${target} ${OPENSSL_LIBRARIES})
target_link_libraries(${target} ${ZLIB_LIBRARIES})
@@ -423,12 +424,9 @@ endif()
target_link_libraries(${target} ${LIBMEMCACHED_LIBRARY})
target_link_libraries(${target} ${CRYPT_LIB})
if (LINUX OR FREEBSD)
target_link_libraries(${target} ${CRYPT_LIB})
target_link_libraries(${target} ${RT_LIB})
elseif (APPLE)
target_link_libraries(${target} ${CRYPTO_LIB})
target_link_libraries(${target} ${ICONV_LIB})
endif()
target_link_libraries(${target} timelib)
@@ -437,12 +435,6 @@ endif()
target_link_libraries(${target} double-conversion)
target_link_libraries(${target} folly)
if (SKIP_BUNDLED_XHP)
target_link_libraries(${target} ${XHP_LIB})
else()
target_link_libraries(${target} xhp)
endif()
target_link_libraries(${target} afdt)
target_link_libraries(${target} mbfl)
+35 -16
Ver Arquivo
@@ -11,13 +11,13 @@ endif()
if(CMAKE_COMPILER_IS_GNUCC)
INCLUDE(CheckCSourceCompiles)
CHECK_C_SOURCE_COMPILES("#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if GCC_VERSION < 40400
#error Need GCC 4.4.0+
#if GCC_VERSION < 40600
#error Need GCC 4.6.0+
#endif
int main() { return 0; }" HAVE_GCC_44)
int main() { return 0; }" HAVE_GCC_46)
if(NOT HAVE_GCC_44)
message(FATAL_ERROR "Need at least GCC 4.4")
if(NOT HAVE_GCC_46)
message(FATAL_ERROR "Need at least GCC 4.6")
endif()
endif()
@@ -45,11 +45,20 @@ endif()
include(HPHPFunctions)
include(HPHPFindLibs)
add_definitions(-D_GNU_SOURCE -D_REENTRANT=1 -D_PTHREADS=1)
add_definitions(-D_REENTRANT=1 -D_PTHREADS=1 -D__STDC_FORMAT_MACROS)
add_definitions(-DHHVM_LIB_PATH_DEFAULT="${HPHP_HOME}/bin")
if (LINUX)
add_definitions(-D_GNU_SOURCE)
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
add_definitions(-DRELEASE=1)
add_definitions(-DNDEBUG)
message("Generating Release build")
else()
add_definitions(-DDEBUG)
message("Generating DEBUG build")
endif()
if(INFINITE_LOOP_DETECTION)
@@ -100,22 +109,32 @@ if(APPLE OR FREEBSD)
add_definitions(-DSKIP_USER_CHANGE=1)
endif()
if(APPLE)
# We have to be a little more permissive in some cases.
add_definitions(-fpermissive)
# Skip deprecation warnings in OpenSSL.
add_definitions(-DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_6)
# Just assume we have sched.h
add_definitions(-DFOLLY_HAVE_SCHED_H=1)
# Enable weak linking
add_definitions(-DMACOSX_DEPLOYMENT_TARGET=10.6)
endif()
# enable the OSS options if we have any
add_definitions(-DHPHP_OSS=1)
execute_process(COMMAND git describe --all --long --abbrev=40 --always
OUTPUT_VARIABLE _COMPILER_ID OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
if (_COMPILER_ID)
add_definitions(-DCOMPILER_ID="${_COMPILER_ID}")
endif()
# later versions of binutils don't play well without automake
add_definitions(-DPACKAGE=hhvm -DPACKAGE_VERSION=Release)
IF($ENV{CXX} MATCHES "icpc")
set(CMAKE_C_FLAGS "-no-ipo -fp-model precise -wd584 -wd1418 -wd1918 -wd383 -wd869 -wd981 -wd424 -wd1419 -wd444 -wd271 -wd2259 -wd1572 -wd1599 -wd82 -wd177 -wd593 -w")
set(CMAKE_CXX_FLAGS "-no-ipo -fp-model precise -wd584 -wd1418 -wd1918 -wd383 -wd869 -wd981 -wd424 -wd1419 -wd444 -wd271 -wd2259 -wd1572 -wd1599 -wd82 -wd177 -wd593 -fno-omit-frame-pointer -ftemplate-depth-60 -Wall -Woverloaded-virtual -Wno-deprecated -w1 -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names")
set(CMAKE_CXX_FLAGS "-no-ipo -fp-model precise -wd584 -wd1418 -wd1918 -wd383 -wd869 -wd981 -wd424 -wd1419 -wd444 -wd271 -wd2259 -wd1572 -wd1599 -wd82 -wd177 -wd593 -fno-omit-frame-pointer -ftemplate-depth-120 -Wall -Woverloaded-virtual -Wno-deprecated -w1 -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names")
else()
set(CMAKE_C_FLAGS "-w")
set(CMAKE_CXX_FLAGS "-fno-gcse -fno-omit-frame-pointer -ftemplate-depth-60 -Wall -Woverloaded-virtual -Wno-deprecated -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names -Wno-error=array-bounds -Wno-error=switch -std=gnu++0x -Werror=format-security -Wno-unused-result -Wno-sign-compare")
set(CMAKE_CXX_FLAGS "-fno-gcse -fno-omit-frame-pointer -ftemplate-depth-120 -Wall -Woverloaded-virtual -Wno-deprecated -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names -Wno-error=array-bounds -Wno-error=switch -std=gnu++0x -Werror=format-security -Wno-unused-result -Wno-sign-compare")
endif()
IF(CMAKE_COMPILER_IS_GNUCC)
@@ -126,6 +145,6 @@ IF(CMAKE_COMPILER_IS_GNUCXX)
SET (CMAKE_CXX_FLAGS_RELEASE "-O3")
ENDIF()
include_directories(${HPHP_HOME}/src)
include_directories(${HPHP_HOME}/src/lib/system/gen)
include_directories(${HPHP_HOME}/hphp)
include_directories(${HPHP_HOME}/hphp/lib/system/gen)
include_directories(${HPHP_HOME})
+4 -4
Ver Arquivo
@@ -1,5 +1,5 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6.4 FATAL_ERROR)
PROJECT(hphp C CXX)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.5 FATAL_ERROR)
PROJECT(hphp C CXX ASM)
IF("$ENV{HPHP_HOME}" STREQUAL "")
message(FATAL_ERROR "You should set the HPHP_HOME environmental")
@@ -20,7 +20,7 @@ SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/HPHPFunctions.cmake")
include(CheckFunctionExists)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/hphp)
IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
message(FATAL_ERROR "32-bit support is currently unsupported, check back with a later version of HipHop")
@@ -30,5 +30,5 @@ if ("$ENV{USE_HHVM}" STREQUAL "1")
message("Building for HHVM")
endif()
if ("$ENV{USE_HPHPC}" STREQUAL "1")
message("Building for HPHPc")
message(FATAL_ERROR "Building HPHPc is no longer supported")
endif()
+18 -59
Ver Arquivo
@@ -1,74 +1,33 @@
# HipHop for PHP
# HipHop VM for PHP [![Build Status](https://travis-ci.org/facebook/hiphop-php.png?branch=master)](https://travis-ci.org/facebook/hiphop-php)
HipHop is a high performance PHP toolchain. Currently supported platforms are Linux and FreeBSD. There is no OS X support.
HipHop VM (HHVM) is a new open-source virtual machine designed for executing programs written in PHP. HHVM uses a just-in-time compilation approach to achieve superior performance while maintaining the flexibility that PHP developers are accustomed to. HipHop VM (and before it HPHPc) has realized > 5x increase in throughput for Facebook compared with Zend PHP 5.2.
* [Developer Mailing List](http://groups.google.com/group/hiphop-php-dev)
* [Wiki](http://wiki.github.com/facebook/hiphop-php)
* [Issue Tracker](http://github.com/facebook/hiphop-php/issues)
HipHop is most commonly run as a standalone server, replacing both Apache and modphp.
## Required Packages
## Installing
The latest information is available on the [wiki](http://wiki.github.com/facebook/hiphop-php/building-and-installing)
You can install a [prebuilt package](https://github.com/facebook/hiphop-php/wiki#installing-pre-built-packages-for-hhvm) or [compile from source](https://github.com/facebook/hiphop-php/wiki#building-hhvm).
* cmake *2.6 is the minimum version*
* g++/gcc *4.3 is the minimum version*
* Boost *1.37 is the minimum version*
* flex
* bison
* re2c
* libmysql
* libxml2
* libmcrypt
* libicu *4.2 is the minimum version*
* openssl
* binutils
* libcap
* gd
* zlib
* tbb *Intel's Thread Building Blocks*
* [Oniguruma](http://www.geocities.jp/kosako3/oniguruma/)
* libpcre
* libexpat
* libmemcached
* google-glog (http://code.google.com/p/google-glog/)
## Running
The following packages have had slight modifications added to them. Patches are provided and should be made against the current source copies.
You can run standalone programs just by passing them to hhvm: `hhvm my_script.php`.
* [libcurl](http://curl.haxx.se/download.html)
* src/third_party/libcurl.fb-changes.diff
* [libevent 1.4](http://www.monkey.org/~provos/libevent/)
* src/third_party/libevent-1.4.13.fb-changes.diff OR src/third_party/libevent-1.4.14.fb-changes.diff
HipHop bundles in a webserver. So if you want to run on port 80 in the current directory:
## Installation
```
sudo hhvm -m server
```
You may need to point CMake to the location of your custom libcurl and libevent, or to any other libraries which needed to be installed. The *CMAKE_PREFIX_PATH* variable is used to hint to the location.
For anything more complicated, you'll want to make a [config.hdf](https://github.com/facebook/hiphop-php/wiki/Runtime-options#server) and run `sudo hhvm -m server -c config.hdf`.
export CMAKE_PREFIX_PATH=/home/user
## Contributing
To build HipHop, use the following:
We'd love to have your help in making HipHop better. If you run into problems, please open an [issue](http://github.com/facebook/hiphop-php/issues), or better yet, fork us and send a pull request. Join us on [#hhvm on freenode](http://webchat.freenode.net/?channels=hhvm).
Linux:
If you want to help but don't know where to start, try fixing some of the [Zend tests that don't pass](hphp/test/zend/bad). You can run them with [hphp/test/run](hphp/test/run). When they work, move them to [zend/good](hphp/test/zend/good) and send a pull request.
cd /home/user/dev
git clone git://github.com/facebook/hiphop-php.git
cd hiphop-php
git submodule init
git submodule update
export HPHP_HOME=`pwd`
export HPHP_LIB=`pwd`/bin
cmake .
Before changes can be accepted a [Contributors Licensing Agreement](http://developers.facebook.com/opensource/cla) ([pdf](https://github.com/facebook/hiphop-php/raw/master/hphp/doc/FB_Individual_CLA.pdf) - print, sign, scan, link) must be signed.
If you are using FreeBSD instead use export - setenv
## Licence
Once this is done you can generate the build file. This will return you to the shell. Finally, to build, run `make`. If any errors occur, it may be required to remove the CMakeCache.txt directory in the checkout.
make
## Contributing to HipHop
HipHop is licensed under the PHP and Zend licenses except as otherwise noted.
Before changes can be accepted a [Contributors Licensing Agreement](http://developers.facebook.com/opensource/cla) must be signed and returned.
## Running HipHop
Please see [the wiki page](http://wiki.github.com/facebook/hiphop-php/running-hiphop)
HipHop VM is licensed under the PHP and Zend licenses except as otherwise noted.
-5592
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Arquivo executável
+71
Ver Arquivo
@@ -0,0 +1,71 @@
#########################################
#
# Install all the dependancies for HipHop
#
#########################################
SCRIPT_NAME='./configure_ubuntu_12.04.sh'
if [ "$0" != "$SCRIPT_NAME" ]; then
echo "Run the script from the hiphop-php directory like:"
echo " $SCRIPT_NAME"
exit 1
fi
export CMAKE_PREFIX_PATH=`/bin/pwd`/..
export HPHP_HOME=`/bin/pwd`
sudo apt-get install git-core cmake g++ libboost1.48-dev libmysqlclient-dev \
libxml2-dev libmcrypt-dev libicu-dev openssl build-essential binutils-dev \
libcap-dev libgd2-xpm-dev zlib1g-dev libtbb-dev libonig-dev libpcre3-dev \
autoconf libtool libcurl4-openssl-dev libboost-regex1.48-dev libboost-system1.48-dev \
libboost-program-options1.48-dev libboost-filesystem1.48-dev wget memcached \
libreadline-dev libncurses-dev libmemcached-dev libbz2-dev \
libc-client2007e-dev php5-mcrypt php5-imagick libgoogle-perftools-dev \
libcloog-ppl0 libelf-dev libdwarf-dev libunwind7-dev subversion
# libevent
git clone git://github.com/libevent/libevent.git
cd libevent
git checkout release-1.4.14b-stable
cat ../hphp/third_party/libevent-1.4.14.fb-changes.diff | patch -p1
./autogen.sh
./configure --prefix=$CMAKE_PREFIX_PATH
make
make install
cd ..
# curl
git clone git://github.com/bagder/curl.git
cd curl
./buildconf
./configure --prefix=$CMAKE_PREFIX_PATH
make
make install
cd ..
# glog
svn checkout http://google-glog.googlecode.com/svn/trunk/ google-glog
cd google-glog
./configure --prefix=$CMAKE_PREFIX_PATH
make
make install
cd ..
# jemaloc
wget http://www.canonware.com/download/jemalloc/jemalloc-3.0.0.tar.bz2
tar xjvf jemalloc-3.0.0.tar.bz2
cd jemalloc-3.0.0
./configure --prefix=$CMAKE_PREFIX_PATH
make
make install
cd ..
# cleanup
rm -rf libevent curl google-glog jemalloc-3.0.0.tar.bz2 jemalloc-3.0.0
# hphp
cmake .
echo "-------------------------------------------------------------------------"
echo "Done. Now run:"
echo " CMAKE_PREFIX_PATH=\`pwd\`/.. HPHP_HOME=\`pwd\` make"
+102
Ver Arquivo
@@ -0,0 +1,102 @@
#
# +----------------------------------------------------------------------+
# | HipHop for PHP |
# +----------------------------------------------------------------------+
# | Copyright (c) 2010 Facebook, Inc. (http://www.facebook.com) |
# | Copyright (c) 1997-2010 The PHP Group |
# +----------------------------------------------------------------------+
# | This source file is subject to version 3.01 of the PHP license, |
# | that is bundled with this package in the file LICENSE, and is |
# | available through the world-wide-web at the following url: |
# | http://www.php.net/license/3_01.txt |
# | If you did not receive a copy of the PHP license and are unable to |
# | obtain it through the world-wide-web, please send a note to |
# | license@php.net so we can mail you a copy immediately. |
# +----------------------------------------------------------------------+
#
include(HPHPSetup)
# HHVM Build
SET(USE_HHVM TRUE)
SET(ENV{HHVM} 1)
ADD_DEFINITIONS("-DHHVM -DHHVM_BINARY=1 -DHHVM_PATH=\\\"${HPHP_HOME}/hphp/hhvm/hhvm\\\"")
set(RECURSIVE_SOURCE_SUBDIRS runtime/base runtime/debugger runtime/eval runtime/ext runtime/vm util)
foreach (dir ${RECURSIVE_SOURCE_SUBDIRS})
auto_sources(files "*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
list(APPEND CXX_SOURCES ${files})
auto_sources(files "*.c" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
list(APPEND C_SOURCES ${files})
auto_sources(files "*.S" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
list(APPEND ASM_SOURCES ${files})
endforeach(dir ${RECURSIVE_SOURCE_SUBDIRS})
if(NOT LINUX)
add_definitions(-DNO_HARDWARE_COUNTERS)
list(REMOVE_ITEM CXX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/runtime/vm/debug/elfwriter.cpp)
endif()
# remove ext_hhvm, and anything in a test folder
foreach (file ${CXX_SOURCES})
if (${file} MATCHES "ext_hhvm")
list(REMOVE_ITEM CXX_SOURCES ${file})
endif()
if (${file} MATCHES "/test/")
list(REMOVE_ITEM CXX_SOURCES ${file})
endif()
endforeach(file ${CXX_SOURCES})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
add_subdirectory(third_party/libafdt)
add_subdirectory(third_party/libmbfl)
add_subdirectory(third_party/libsqlite3)
add_subdirectory(third_party/timelib)
add_subdirectory(third_party/lz4)
add_subdirectory(third_party/double-conversion)
add_subdirectory(third_party/folly)
foreach (CXX_FILE ${CXX_SOURCES})
if(${CXX_FILE} MATCHES ".no.cpp$")
SET_SOURCE_FILES_PROPERTIES(
${CXX_FILE}
PROPERTIES
COMPILE_FLAGS -O0
)
endif()
endforeach()
add_custom_command(
OUTPUT hphp_repo_schema.h hphp_build_info.cpp
COMMAND hphp/util/generate_buildinfo.sh
DEPENDS ${CXX_SOURCES} ${C_SOURCES}
WORKING_DIRECTORY ${HPHP_HOME}
COMMENT "Generating Repo Schema ID and Compiler ID"
VERBATIM)
ADD_LIBRARY(hphp_runtime_static STATIC
hphp_repo_schema.h hphp_build_info.cpp
${CXX_SOURCES} ${C_SOURCES} ${ASM_SOURCES})
SET_TARGET_PROPERTIES(hphp_runtime_static PROPERTIES OUTPUT_NAME "hphp_runtime")
SET_TARGET_PROPERTIES(hphp_runtime_static PROPERTIES PREFIX "lib")
SET_TARGET_PROPERTIES(hphp_runtime_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>")
hphp_link(hphp_runtime_static)
add_subdirectory("tools/bootstrap")
add_subdirectory(compiler)
add_subdirectory(runtime/ext_hhvm)
add_subdirectory(hhvm)
add_subdirectory(system)
if (NOT "$ENV{HPHP_NOTEST}" STREQUAL "1")
add_subdirectory(test)
endif ()
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,55 +14,61 @@
+----------------------------------------------------------------------+
*/
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/expression/expression.h>
#include <compiler/expression/assignment_expression.h>
#include <compiler/expression/array_element_expression.h>
#include <compiler/expression/list_assignment.h>
#include <compiler/expression/binary_op_expression.h>
#include <compiler/expression/unary_op_expression.h>
#include <compiler/expression/qop_expression.h>
#include <compiler/expression/simple_variable.h>
#include <compiler/expression/scalar_expression.h>
#include <compiler/expression/simple_function_call.h>
#include <compiler/expression/array_element_expression.h>
#include <compiler/expression/object_property_expression.h>
#include <compiler/expression/object_method_expression.h>
#include <compiler/expression/parameter_expression.h>
#include <compiler/expression/expression_list.h>
#include <compiler/expression/expression.h>
#include <compiler/expression/include_expression.h>
#include <compiler/expression/closure_expression.h>
#include <compiler/statement/statement.h>
#include <compiler/statement/statement_list.h>
#include <compiler/statement/catch_statement.h>
#include <compiler/statement/method_statement.h>
#include <compiler/statement/block_statement.h>
#include <compiler/statement/if_statement.h>
#include <compiler/statement/if_branch_statement.h>
#include <compiler/statement/break_statement.h>
#include <compiler/statement/return_statement.h>
#include <compiler/statement/loop_statement.h>
#include <compiler/statement/foreach_statement.h>
#include <compiler/statement/for_statement.h>
#include <compiler/statement/while_statement.h>
#include <compiler/statement/do_statement.h>
#include <compiler/statement/exp_statement.h>
#include <compiler/statement/echo_statement.h>
#include <compiler/statement/try_statement.h>
#include <compiler/analysis/alias_manager.h>
#include <compiler/analysis/control_flow.h>
#include <compiler/analysis/variable_table.h>
#include <compiler/analysis/data_flow.h>
#include <compiler/analysis/dictionary.h>
#include <compiler/analysis/expr_dict.h>
#include <compiler/analysis/live_dict.h>
#include <compiler/analysis/ref_dict.h>
#include "hphp/compiler/analysis/alias_manager.h"
#include <util/parser/hphp.tab.hpp>
#include <util/parser/location.h>
#include <util/util.h>
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/assignment_expression.h"
#include "hphp/compiler/expression/array_element_expression.h"
#include "hphp/compiler/expression/list_assignment.h"
#include "hphp/compiler/expression/binary_op_expression.h"
#include "hphp/compiler/expression/unary_op_expression.h"
#include "hphp/compiler/expression/qop_expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/expression/simple_function_call.h"
#include "hphp/compiler/expression/array_element_expression.h"
#include "hphp/compiler/expression/object_property_expression.h"
#include "hphp/compiler/expression/object_method_expression.h"
#include "hphp/compiler/expression/parameter_expression.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/include_expression.h"
#include "hphp/compiler/expression/closure_expression.h"
#include "hphp/compiler/statement/statement.h"
#include "hphp/compiler/statement/statement_list.h"
#include "hphp/compiler/statement/catch_statement.h"
#include "hphp/compiler/statement/method_statement.h"
#include "hphp/compiler/statement/block_statement.h"
#include "hphp/compiler/statement/if_statement.h"
#include "hphp/compiler/statement/if_branch_statement.h"
#include "hphp/compiler/statement/switch_statement.h"
#include "hphp/compiler/statement/break_statement.h"
#include "hphp/compiler/statement/return_statement.h"
#include "hphp/compiler/statement/loop_statement.h"
#include "hphp/compiler/statement/foreach_statement.h"
#include "hphp/compiler/statement/for_statement.h"
#include "hphp/compiler/statement/while_statement.h"
#include "hphp/compiler/statement/do_statement.h"
#include "hphp/compiler/statement/exp_statement.h"
#include "hphp/compiler/statement/echo_statement.h"
#include "hphp/compiler/statement/try_statement.h"
#include "hphp/compiler/statement/global_statement.h"
#include "hphp/compiler/statement/static_statement.h"
#include "hphp/compiler/analysis/control_flow.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/data_flow.h"
#include "hphp/compiler/analysis/dictionary.h"
#include "hphp/compiler/analysis/expr_dict.h"
#include "hphp/compiler/analysis/live_dict.h"
#include "hphp/compiler/analysis/ref_dict.h"
#include "hphp/runtime/base/builtin_functions.h"
#include "hphp/util/parser/hphp.tab.hpp"
#include "hphp/util/parser/location.h"
#include "hphp/util/util.h"
#define spc(T,p) boost::static_pointer_cast<T>(p)
#define dpc(T,p) boost::dynamic_pointer_cast<T>(p)
@@ -260,7 +266,7 @@ void AliasManager::beginScope() {
ExpressionPtr e(new ScalarExpression(BlockScopePtr(), LocationPtr(),
T_STRING, string("begin")));
m_accessList.add(e);
m_stack.push_back(m_accessList.size());
m_stack.push_back(CondStackElem(m_accessList.size()));
m_accessList.beginScope();
if (BucketMapEntry *tail = m_bucketList) {
BucketMapEntry *bm = tail;
@@ -532,11 +538,7 @@ int AliasManager::testAccesses(ExpressionPtr e1, ExpressionPtr e2,
goto def;
}
case Expression::KindOfIncludeExpression: {
IncludeExpressionPtr inc(spc(IncludeExpression, e2));
if (!inc->isPrivateScope()) {
return InterfAccess;
}
goto def;
return InterfAccess;
}
case Expression::KindOfStaticMemberExpression:
case Expression::KindOfObjectPropertyExpression:
@@ -602,10 +604,14 @@ void AliasManager::cleanRefs(ExpressionPtr e,
ExpressionPtrList::reverse_iterator it,
ExpressionPtrList::reverse_iterator &end,
int depth) {
if (e->is(Expression::KindOfUnaryOpExpression) &&
e->getLocalEffects() == Expression::UnknownEffect) {
return;
}
if (e->is(Expression::KindOfAssignmentExpression) ||
e->is(Expression::KindOfBinaryOpExpression) ||
e->is(Expression::KindOfUnaryOpExpression)) {
ExpressionPtr var = e->getNthExpr(0);
ExpressionPtr var = e->getStoreVariable();
if (var->is(Expression::KindOfSimpleVariable) &&
!(var->getContext() & Expression::RefAssignmentLHS)) {
SimpleVariablePtr sv(spc(SimpleVariable, var));
@@ -753,6 +759,7 @@ void AliasManager::killLocals() {
continue;
case Expression::KindOfUnaryOpExpression:
if (e->getLocalEffects() == Expression::UnknownEffect) goto kill_it;
cleanInterf(spc(UnaryOpExpression, e)->getExpression(),
++it, end, depth);
continue;
@@ -850,17 +857,33 @@ int AliasManager::checkInterf(ExpressionPtr rv, ExpressionPtr e,
}
case Expression::KindOfUnaryOpExpression:
isLoad = false;
return testAccesses(
spc(UnaryOpExpression,e)->getExpression(), rv, forLval);
case Expression::KindOfBinaryOpExpression:
isLoad = false;
return testAccesses(
spc(BinaryOpExpression,e)->getExp1(), rv, forLval);
if (e->getLocalEffects() == Expression::UnknownEffect) {
isLoad = false;
return InterfAccess;
}
// fall through
case Expression::KindOfAssignmentExpression:
case Expression::KindOfBinaryOpExpression: {
isLoad = false;
return testAccesses(
spc(AssignmentExpression,e)->getVariable(), rv, forLval);
ExpressionPtr var = e->getStoreVariable();
int access = testAccesses(var, rv, forLval);
if (access == SameAccess) {
// An assignment to something that might be visible from
// another scope, and that might contain an object, could
// end up with some other value (due to a destructor running)
// than the rhs.
if (var->getKindOf() != Expression::KindOfSimpleVariable) {
return InterfAccess;
}
SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(var);
if (sv->couldBeAliased() &&
(sv->isNeededValid() ? sv->isNeeded() :
!sv->getSymbol() || sv->getSymbol()->isNeeded())) {
return InterfAccess;
}
}
return access;
}
default:
not_reached();
@@ -887,11 +910,13 @@ int AliasManager::checkAnyInterf(ExpressionPtr e1, ExpressionPtr e2,
return DisjointAccess;
}
case Expression::KindOfAssignmentExpression:
e1 = spc(AssignmentExpression, e1)->getVariable();
break;
case Expression::KindOfUnaryOpExpression:
case Expression::KindOfBinaryOpExpression:
e1 = e1->getNthExpr(0);
case Expression::KindOfUnaryOpExpression:
if (e1->getLocalEffects() == Expression::UnknownEffect) {
isLoad = false;
return InterfAccess;
}
e1 = e1->getStoreVariable();
if (!e1 || !e1->hasContext(Expression::OprLValue)) return DisjointAccess;
break;
default:
@@ -1069,14 +1094,10 @@ void AliasManager::setCanonPtrForArrayCSE(
// need to switch on rep
ExpressionPtr rep0;
switch (rep->getKindOf()) {
case Expression::KindOfUnaryOpExpression:
rep0 = spc(UnaryOpExpression, rep)->getExpression();
break;
case Expression::KindOfBinaryOpExpression:
rep0 = spc(BinaryOpExpression, rep)->getExp1();
break;
case Expression::KindOfAssignmentExpression:
rep0 = spc(AssignmentExpression, rep)->getVariable();
case Expression::KindOfBinaryOpExpression:
case Expression::KindOfUnaryOpExpression:
rep0 = rep->getStoreVariable();
break;
case Expression::KindOfListAssignment:
// TODO: IMPLEMENT
@@ -1156,11 +1177,12 @@ ExpressionPtr AliasManager::canonicalizeNode(
return ExpressionPtr();
}
ExpressionPtr var;
switch (e->getKindOf()) {
case Expression::KindOfAssignmentExpression:
case Expression::KindOfAssignmentExpression: {
case Expression::KindOfBinaryOpExpression:
case Expression::KindOfUnaryOpExpression: {
ExpressionPtr var = e->getNthExpr(0);
case Expression::KindOfUnaryOpExpression:
ExpressionPtr var = e->getStoreVariable();
if (var && var->getContext() & (Expression::AssignmentLHS|
Expression::OprLValue)) {
processAccessChain(var);
@@ -1269,6 +1291,7 @@ ExpressionPtr AliasManager::canonicalizeNode(
}
case Expression::KindOfUnaryOpExpression: {
UnaryOpExpressionPtr u = spc(UnaryOpExpression, rep);
assert(u->getOp() == T_INC || u->getOp() == T_DEC);
if (Option::EliminateDeadCode) {
if (u->getActualType() && u->getActualType()->isInteger()) {
ExpressionPtr val = u->getExpression()->clone();
@@ -1387,7 +1410,7 @@ ExpressionPtr AliasManager::canonicalizeNode(
value = value->replaceValue(
canonicalizeRecurNonNull(
value->makeConstant(m_arp, "null")));
a->setNthKid(1, value);
a->setValue(value);
a->recomputeEffects();
setChanged();
} else {
@@ -1398,7 +1421,7 @@ ExpressionPtr AliasManager::canonicalizeNode(
a = spc(AssignmentExpression, a->clone());
el->addElement(a);
el->addElement(a->getValue());
a->setNthKid(1, value->makeConstant(m_arp, "null"));
a->setValue(value->makeConstant(m_arp, "null"));
rep->setReplacement(el);
m_replaced++;
}
@@ -1438,7 +1461,7 @@ ExpressionPtr AliasManager::canonicalizeNode(
Expression::UnsetContext)) {
ExpressionPtr rep;
int interf =
findInterf(e, true, rep, NULL, doArrayCSE);
findInterf(e, true, rep, nullptr, doArrayCSE);
add(m_accessList, e);
if (interf == SameAccess) {
if (e->getKindOf() == rep->getKindOf()) {
@@ -1498,12 +1521,13 @@ ExpressionPtr AliasManager::canonicalizeNode(
Expression::UnsetContext))) {
ExpressionPtr rep;
int interf =
findInterf(e, true, rep, NULL, doArrayCSE);
findInterf(e, true, rep, nullptr, doArrayCSE);
if (!m_inPseudoMain && interf == DisjointAccess && !m_cleared &&
e->is(Expression::KindOfSimpleVariable) &&
!e->isThis()) {
Symbol *s = spc(SimpleVariable, e)->getSymbol();
if (s && !s->isParameter() && !s->isClosureVar()) {
if (s && !s->isParameter() && !s->isGeneratorParameter() &&
!s->isClosureVar()) {
rep = e->makeConstant(m_arp, "null");
Compiler::Error(Compiler::UseUndeclaredVariable, e);
if (m_variables->getAttribute(VariableTable::ContainsCompact)) {
@@ -1562,17 +1586,17 @@ ExpressionPtr AliasManager::canonicalizeNode(
}
cur = next;
}
if ((!m_inCall || (!hhvm && !ae->getValue()->hasEffect())) &&
if (!m_inCall &&
!last->is(Expression::KindOfYieldExpression) &&
ae->isUnused() && m_accessList.isLast(ae) &&
!(hhvm && Option::OutputHHBC &&
e->hasAnyContext(Expression::AccessContext |
Expression::ObjectContext |
Expression::ExistContext |
Expression::UnsetContext))) {
!e->hasAnyContext(Expression::AccessContext |
Expression::ObjectContext |
Expression::ExistContext |
Expression::UnsetContext)) {
rep = ae->clone();
ae->setContext(Expression::DeadStore);
ae->setNthKid(1, ae->makeConstant(m_arp, "null"));
ae->setNthKid(0, ae->makeConstant(m_arp, "null"));
ae->setValue(ae->makeConstant(m_arp, "null"));
ae->setVariable(ae->makeConstant(m_arp, "null"));
e->recomputeEffects();
m_replaced++;
return e->replaceValue(canonicalizeRecurNonNull(rep));
@@ -1659,7 +1683,7 @@ ExpressionPtr AliasManager::canonicalizeNode(
while (v->getCanonPtr() && v->getCanonPtr() != op0) {
v = v->getCanonPtr();
}
ok = v->getCanonPtr();
ok = (v->getCanonPtr() != nullptr);
}
if (ok) {
b2->setContext(Expression::DeadStore);
@@ -1707,18 +1731,15 @@ ExpressionPtr AliasManager::canonicalizeNode(
if (interf == SameAccess) {
switch (alt->getKindOf()) {
case Expression::KindOfAssignmentExpression:
alt = spc(AssignmentExpression,alt)->getVariable();
break;
case Expression::KindOfBinaryOpExpression:
alt = spc(BinaryOpExpression,alt)->getExp1();
break;
case Expression::KindOfUnaryOpExpression:
alt = spc(UnaryOpExpression,alt)->getExpression();
alt = alt->getStoreVariable();
break;
default:
break;
}
always_assert(alt->getKindOf() == uop->getExpression()->getKindOf());
always_assert(alt->getKindOf() ==
uop->getExpression()->getKindOf());
uop->getExpression()->setCanonID(alt->getCanonID());
} else {
uop->getExpression()->setCanonID(m_nextID++);
@@ -1727,7 +1748,11 @@ ExpressionPtr AliasManager::canonicalizeNode(
add(m_accessList, e);
break;
default:
getCanonical(e);
if (uop->getLocalEffects() == Expression::UnknownEffect) {
add(m_accessList, e);
} else {
getCanonical(e);
}
break;
}
break;
@@ -1754,6 +1779,8 @@ ExpressionPtr AliasManager::canonicalizeNode(
}
void AliasManager::canonicalizeKid(ConstructPtr c, ExpressionPtr kid, int i) {
assert(c->getNthKid(i) == kid);
if (kid) {
StatementPtr sp(dpc(Statement, c));
if (sp) beginInExpression(sp, kid);
@@ -1773,6 +1800,8 @@ void AliasManager::canonicalizeKid(ConstructPtr c, ExpressionPtr kid, int i) {
}
int AliasManager::canonicalizeKid(ConstructPtr c, ConstructPtr kid, int i) {
assert(c->getNthKid(i) == kid);
int ret = FallThrough;
if (kid) {
ExpressionPtr e = dpc(Expression, kid);
@@ -1806,51 +1835,34 @@ ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
bool setInCall = true;
switch (e->getKindOf()) {
case Expression::KindOfQOpExpression:
canonicalizeKid(e, e->getNthExpr(0), 0);
case Expression::KindOfQOpExpression: {
QOpExpressionPtr qe(spc(QOpExpression, e));
canonicalizeKid(e, qe->getCondition(), 0);
beginScope();
if (ExpressionPtr e1 = e->getNthExpr(1)) {
if (ExpressionPtr e1 = qe->getYes()) {
canonicalizeKid(e, e1, 1);
resetScope();
}
canonicalizeKid(e, e->getNthExpr(2), 2);
canonicalizeKid(e, qe->getNo(), 2);
endScope();
return canonicalizeNode(e);
case Expression::KindOfBinaryOpExpression:
{
BinaryOpExpressionPtr binop(spc(BinaryOpExpression, e));
if (binop->isShortCircuitOperator()) {
canonicalizeKid(e, e->getNthExpr(0), 0);
beginScope();
canonicalizeKid(e, e->getNthExpr(1), 1);
endScope();
return canonicalizeNode(e);
}
}
case Expression::KindOfBinaryOpExpression: {
BinaryOpExpressionPtr binop(spc(BinaryOpExpression, e));
if (binop->isShortCircuitOperator()) {
canonicalizeKid(e, binop->getExp1(), 0);
beginScope();
canonicalizeKid(e, binop->getExp2(), 1);
endScope();
return canonicalizeNode(e);
}
break;
}
case Expression::KindOfExpressionList:
delayVars = false;
break;
case Expression::KindOfSimpleFunctionCall:
if (!hhvm || !Option::OutputHHBC) {
SimpleFunctionCallPtr f(spc(SimpleFunctionCall, e));
if (!f->getClass()) {
if (f->getClassName().empty()) {
if (f->getFuncScope() &&
!f->getFuncScope()->isVolatile()) {
setInCall = false;
}
} else if (ClassScopePtr cls = f->resolveClass()) {
if (!cls->isVolatile()) {
setInCall = false;
}
}
}
}
// fall through
case Expression::KindOfNewObjectExpression:
case Expression::KindOfDynamicFunctionCall:
inCall = setInCall;
@@ -1872,6 +1884,7 @@ ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
int n = e->getKidCount();
if (n < 2) delayVars = false;
if (e->is(Expression::KindOfAssignmentExpression)) delayVars = false;
m_inCall += inCall;
for (int j = delayVars ? 0 : 1; j < 2; j++) {
@@ -1941,42 +1954,42 @@ StatementPtr AliasManager::canonicalizeRecur(StatementPtr s, int &ret) {
// and fall through
break;
case Statement::KindOfIfStatement:
{
StatementPtr iflist = spc(Statement, s->getNthKid(0));
if (iflist) {
for (int i = 0, n = iflist->getKidCount(); i < n; i++) {
StatementPtr ifstmt = spc(Statement, iflist->getNthKid(i));
ExpressionPtr cond = spc(Expression, ifstmt->getNthKid(0));
canonicalizeKid(ifstmt, cond, 0);
if (!i) beginScope();
beginScope();
canonicalizeKid(ifstmt, ifstmt->getNthKid(1), 1);
endScope();
if (i+1 < n) resetScope();
}
case Statement::KindOfIfStatement: {
IfStatementPtr is = spc(IfStatement, s);
StatementListPtr iflist = is->getIfBranches();
if (iflist) {
for (int i = 0, n = iflist->getKidCount(); i < n; i++) {
IfBranchStatementPtr ifstmt = spc(IfBranchStatement, (*iflist)[i]);
canonicalizeKid(ifstmt, ifstmt->getCondition(), 0);
if (!i) beginScope();
beginScope();
canonicalizeKid(ifstmt, ifstmt->getStmt(), 1);
endScope();
if (i+1 < n) resetScope();
}
ret = FallThrough;
start = nkid;
endScope();
}
ret = FallThrough;
start = nkid;
break;
}
case Statement::KindOfIfBranchStatement:
always_assert(0);
break;
case Statement::KindOfForStatement:
canonicalizeKid(s, spc(Expression,s->getNthKid(0)), 0);
case Statement::KindOfForStatement: {
ForStatementPtr fs(spc(ForStatement, s));
canonicalizeKid(s, fs->getInitExp(), 0);
clear();
canonicalizeKid(s, spc(Expression,s->getNthKid(1)), 1);
canonicalizeKid(s, s->getNthKid(2), 2);
canonicalizeKid(s, fs->getCondExp(), 1);
canonicalizeKid(s, fs->getBody(), 2);
clear();
canonicalizeKid(s, spc(Expression,s->getNthKid(3)), 3);
canonicalizeKid(s, fs->getIncExp(), 3);
ret = Converge;
start = nkid;
break;
}
case Statement::KindOfWhileStatement:
case Statement::KindOfDoStatement:
case Statement::KindOfForEachStatement:
@@ -1984,27 +1997,27 @@ StatementPtr AliasManager::canonicalizeRecur(StatementPtr s, int &ret) {
ret = Converge;
break;
case Statement::KindOfSwitchStatement:
canonicalizeKid(s, spc(Expression,s->getNthKid(0)), 0);
case Statement::KindOfSwitchStatement: {
SwitchStatementPtr ss(spc(SwitchStatement, s));
canonicalizeKid(s, ss->getExp(), 0);
clear();
start = 1;
ret = Converge;
break;
}
case Statement::KindOfCaseStatement:
case Statement::KindOfLabelStatement:
clear();
break;
case Statement::KindOfReturnStatement:
{
canonicalizeKid(s, spc(Expression,s->getNthKid(0)), 0);
case Statement::KindOfReturnStatement: {
ReturnStatementPtr rs(spc(ReturnStatement, s));
canonicalizeKid(s, rs->getRetExp(), 0);
killLocals();
ret = FallThrough;
start = nkid;
break;
}
case Statement::KindOfBreakStatement:
case Statement::KindOfContinueStatement:
case Statement::KindOfGotoStatement:
@@ -2031,6 +2044,9 @@ StatementPtr AliasManager::canonicalizeRecur(StatementPtr s, int &ret) {
break;
}
case Statement::KindOfTypedefStatement:
break;
case Statement::KindOfCatchStatement:
clear();
ret = Converge;
@@ -2130,7 +2146,10 @@ int AliasManager::collectAliasInfoRecur(ConstructPtr cs, bool unused) {
case Statement::KindOfGlobalStatement:
case Statement::KindOfStaticStatement:
{
ExpressionListPtr vars = dpc(ExpressionList, s->getNthKid(0));
ExpressionListPtr vars = (skind == Statement::KindOfGlobalStatement)
? spc(GlobalStatement, s)->getVars()
: spc(StaticStatement, s)->getVars();
for (int i = 0, n = vars->getCount(); i < n; i++) {
ExpressionPtr e = (*vars)[i];
if (AssignmentExpressionPtr ae = dpc(AssignmentExpression, e)) {
@@ -2186,17 +2205,18 @@ int AliasManager::collectAliasInfoRecur(ConstructPtr cs, bool unused) {
}
break;
case Statement::KindOfForEachStatement: {
SimpleVariablePtr name =
dpc(SimpleVariable, s->getNthKid(ForEachStatement::NameExpr));
ForEachStatementPtr fs(static_pointer_cast<ForEachStatement>(s));
SimpleVariablePtr name = dpc(SimpleVariable, fs->getNameExp());
if (name) {
Symbol *sym = name->getSymbol();
sym->setNeeded();
if (Symbol *sym = name->getSymbol()) {
sym->setNeeded();
}
}
SimpleVariablePtr value =
dpc(SimpleVariable, s->getNthKid(ForEachStatement::ValueExpr));
SimpleVariablePtr value = dpc(SimpleVariable, fs->getValueExp());
if (value) {
Symbol *sym = value->getSymbol();
sym->setNeeded();
if (Symbol *sym = value->getSymbol()) {
sym->setNeeded();
}
}
break;
}
@@ -2311,9 +2331,7 @@ int AliasManager::collectAliasInfoRecur(ConstructPtr cs, bool unused) {
case Expression::KindOfIncludeExpression:
{
IncludeExpressionPtr inc(spc(IncludeExpression, e));
if (!inc->isPrivateScope()) {
m_variables->setAttribute(VariableTable::ContainsLDynamicVariable);
}
m_variables->setAttribute(VariableTable::ContainsLDynamicVariable);
}
break;
case Expression::KindOfArrayElementExpression:
@@ -2409,14 +2427,14 @@ int AliasManager::collectAliasInfoRecur(ConstructPtr cs, bool unused) {
}
break;
}
case Expression::KindOfQOpExpression:
case Expression::KindOfQOpExpression: {
QOpExpressionPtr q(spc(QOpExpression, e));
if (unused) {
if (ExpressionPtr t1 = e->getNthExpr(1)) t1->setUnused(true);
e->getNthExpr(2)->setUnused(true);
if (ExpressionPtr t1 = q->getYes()) t1->setUnused(true);
q->getNo()->setUnused(true);
}
break;
}
default:
break;
}
@@ -2511,7 +2529,7 @@ static void markAvailable(ExpressionRawPtr e) {
class TypeAssertionInserter {
public:
TypeAssertionInserter(AnalysisResultConstPtr ar) :
explicit TypeAssertionInserter(AnalysisResultConstPtr ar) :
m_ar(ar), m_changed(false) {
BuildAssertionMap();
}
@@ -2622,6 +2640,10 @@ private:
if (sv && se) {
const string &s = se->getLiteralString();
if (s.empty()) return ExpressionPtr();
if (interface_supports_array(s)) {
// This could be an array, so don't assert anything
return ExpressionPtr();
}
TypePtr o(Type::CreateObjectType(Util::toLower(s)));
// don't do specific type assertions for unknown classes
@@ -2955,15 +2977,6 @@ private:
}
}
break;
case Statement::KindOfBreakStatement:
{
BreakStatementPtr bs(spc(BreakStatement, stmt));
if (bs->getExp()) {
ExpressionPtr rep(
insertTypeAssertion(assertion, bs->getExp()));
replaceExpression(bs, rep, bs->getExp(), 0);
}
}
default:
// this is something like a continue statement,
// in which case we don't do anything
@@ -2975,8 +2988,9 @@ private:
if (!e) return ExpressionPtr();
if (FunctionWalker::SkipRecurse(e)) return ExpressionPtr();
int loopCondIdx = -1, loopBodyIdx = -1;
std::vector<int> needed;
ExpressionPtr loopCond;
StatementPtr loopBody;
std::vector<ExpressionPtr> needed;
switch (e->getKindOf()) {
case Statement::KindOfIfStatement:
{
@@ -3048,46 +3062,45 @@ private:
}
}
return ExpressionPtr();
case Statement::KindOfForStatement:
loopCondIdx = ForStatement::CondExpr;
loopBodyIdx = ForStatement::BodyStmt;
needed.push_back(ForStatement::InitExpr);
needed.push_back(ForStatement::IncExpr);
case Statement::KindOfForStatement: {
ForStatementPtr fs(static_pointer_cast<ForStatement>(e));
loopCond = fs->getCondExp();
loopBody = fs->getBody();
needed.push_back(fs->getInitExp());
needed.push_back(fs->getIncExp());
goto loop_stmt;
case Statement::KindOfWhileStatement:
loopCondIdx = WhileStatement::CondExpr;
loopBodyIdx = WhileStatement::BodyStmt;
}
case Statement::KindOfWhileStatement: {
WhileStatementPtr ws(static_pointer_cast<WhileStatement>(e));
loopCond = ws->getCondExp();
loopBody = ws->getBody();
goto loop_stmt;
case Statement::KindOfDoStatement:
loopCondIdx = DoStatement::CondExpr;
loopBodyIdx = DoStatement::BodyStmt;
}
case Statement::KindOfDoStatement: {
DoStatementPtr ds(static_pointer_cast<DoStatement>(e));
loopCond = ds->getCondExp();
loopBody = ds->getBody();
}
loop_stmt:
{
assert(loopCondIdx >= 0);
assert(loopBodyIdx >= 0);
if (e->getNthKid(loopCondIdx)) {
if (loopCond) {
bool passStmt;
bool negate;
ExpressionPtr after(createTypeAssertions(
spc(Expression, e->getNthKid(loopCondIdx)), passStmt, negate));
ExpressionPtr after(createTypeAssertions(loopCond, passStmt, negate));
if (after && !negate) {
insertTypeAssertion(
after, dpc(Statement, e->getNthKid(loopBodyIdx)));
insertTypeAssertion(after, loopBody);
}
}
for (std::vector<int>::const_iterator it = needed.begin();
it != needed.end();
++it) {
ExpressionPtr k(dpc(Expression, e->getNthKid(*it)));
for (auto it = needed.begin(); it != needed.end(); ++it) {
ExpressionPtr k(dpc(Expression, *it));
if (k) {
bool passStmt;
bool negate;
createTypeAssertions(k, passStmt, negate);
}
}
ConstructPtr body(e->getNthKid(loopBodyIdx));
createTypeAssertions(dpc(Statement, body));
createTypeAssertions(loopBody);
}
return ExpressionPtr();
case Statement::KindOfStatementList:
@@ -3324,7 +3337,7 @@ public:
b->setBit(DataFlow::PRefIn, it->second);
b->setBit(DataFlow::PInitIn, it->second);
}
updateParamInfo(m->getParams(), hhvm && Option::HardTypeHints);
updateParamInfo(m->getParams(), Option::HardTypeHints);
updateParamInfo(m->getFunctionScope()->getClosureVars(), false);
}
}
@@ -3338,6 +3351,9 @@ public:
std::map<std::string,int>::iterator it =
m_gidMap.find("v:" + p->getName());
if (it != m_gidMap.end() && it->second) {
// NB: this is unsound if the user error handler swallows a
// parameter typehint failure. It's opt-in via compiler
// options, though.
if (useDefaults && p->hasTypeHint() && !p->defaultValue()) {
b->setBit(DataFlow::AvailIn, it->second);
}
@@ -3669,7 +3685,7 @@ void AliasManager::doFinal(MethodStatementPtr m) {
}
void AliasManager::performReferencedAndNeededAnalysis(MethodStatementPtr m) {
always_assert(m_graph != NULL);
always_assert(m_graph != nullptr);
// bail out for pseudomain context
if (m->getScope()->inPseudoMain()) return;
@@ -3696,7 +3712,7 @@ void AliasManager::performReferencedAndNeededAnalysis(MethodStatementPtr m) {
}
int AliasManager::copyProp(MethodStatementPtr m) {
if (m_graph == NULL) createCFG(m);
if (m_graph == nullptr) createCFG(m);
performReferencedAndNeededAnalysis(m);
@@ -3719,13 +3735,13 @@ int AliasManager::copyProp(MethodStatementPtr m) {
}
void AliasManager::deleteCFG() {
assert(m_graph != NULL);
assert(m_graph != nullptr);
delete m_graph;
m_graph = NULL;
m_graph = nullptr;
}
void AliasManager::createCFG(MethodStatementPtr m) {
assert(m_graph == NULL);
assert(m_graph == nullptr);
m_graph = ControlFlowGraph::buildControlFlow(m);
}
@@ -3735,7 +3751,7 @@ void AliasManager::insertTypeAssertions(AnalysisResultConstPtr ar,
i.walk(m->getStmts());
if (Option::ControlFlow && Option::DumpAst) {
if (m_graph != NULL) deleteCFG();
if (m_graph != nullptr) deleteCFG();
createCFG(m);
printf("-------- BEGIN INSERTED -----------\n");
m_graph->dump(m_arp);
@@ -3750,7 +3766,7 @@ void AliasManager::removeTypeAssertions(AnalysisResultConstPtr ar,
r.walk(m->getStmts());
if (Option::ControlFlow && Option::DumpAst) {
if (m_graph != NULL) deleteCFG();
if (m_graph != nullptr) deleteCFG();
createCFG(m);
printf("-------- BEGIN REMOVED -----------\n");
m_graph->dump(m_arp);
@@ -3778,7 +3794,7 @@ int AliasManager::optimize(AnalysisResultConstPtr ar, MethodStatementPtr m) {
if (copyProp(m)) return 1;
}
if (m_graph != NULL) deleteCFG();
if (m_graph != nullptr) deleteCFG();
m_hasChainRoot = false;
@@ -3912,7 +3928,8 @@ void AliasManager::invalidateChainRoots(StatementPtr s) {
// otherwise we'd have to declare all CSE temps like:
// declare_temps;
// do { ... } while (cond);
disableCSE(s->getNthStmt(DoStatement::BodyStmt));
DoStatementPtr ds(static_pointer_cast<DoStatement>(s));
disableCSE(ds->getBody());
}
// fall through
default:
@@ -3923,47 +3940,56 @@ void AliasManager::invalidateChainRoots(StatementPtr s) {
}
}
void AliasManager::nullSafeDisableCSE(StatementPtr parent, int kid) {
void AliasManager::nullSafeDisableCSE(StatementPtr parent, ExpressionPtr kid) {
assert(parent);
ConstructPtr c(parent->getNthKid(kid));
if (!c) return;
ExpressionPtr e(dpc(Expression, c));
assert(e);
e->disableCSE();
if (!kid) return;
kid->disableCSE();
}
void AliasManager::disableCSE(StatementPtr s) {
if (!s) return;
switch (s->getKindOf()) {
case Statement::KindOfIfBranchStatement:
nullSafeDisableCSE(s, 0);
case Statement::KindOfIfBranchStatement: {
IfBranchStatementPtr is(static_pointer_cast<IfBranchStatement>(s));
nullSafeDisableCSE(s, is->getCondition());
break;
case Statement::KindOfSwitchStatement:
nullSafeDisableCSE(s, 0);
}
case Statement::KindOfSwitchStatement: {
SwitchStatementPtr ss(static_pointer_cast<SwitchStatement>(s));
nullSafeDisableCSE(s, ss->getExp());
break;
case Statement::KindOfForStatement:
nullSafeDisableCSE(s, ForStatement::InitExpr);
nullSafeDisableCSE(s, ForStatement::CondExpr);
nullSafeDisableCSE(s, ForStatement::IncExpr);
}
case Statement::KindOfForStatement: {
ForStatementPtr fs(static_pointer_cast<ForStatement>(s));
nullSafeDisableCSE(s, fs->getInitExp());
nullSafeDisableCSE(s, fs->getCondExp());
nullSafeDisableCSE(s, fs->getIncExp());
break;
case Statement::KindOfForEachStatement:
nullSafeDisableCSE(s, ForEachStatement::ArrayExpr);
nullSafeDisableCSE(s, ForEachStatement::NameExpr);
nullSafeDisableCSE(s, ForEachStatement::ValueExpr);
}
case Statement::KindOfForEachStatement: {
ForEachStatementPtr fs(static_pointer_cast<ForEachStatement>(s));
nullSafeDisableCSE(s, fs->getArrayExp());
nullSafeDisableCSE(s, fs->getNameExp());
nullSafeDisableCSE(s, fs->getValueExp());
break;
case Statement::KindOfWhileStatement:
nullSafeDisableCSE(s, WhileStatement::CondExpr);
}
case Statement::KindOfWhileStatement: {
WhileStatementPtr ws(static_pointer_cast<WhileStatement>(s));
nullSafeDisableCSE(s, ws->getCondExp());
break;
case Statement::KindOfDoStatement:
nullSafeDisableCSE(s, DoStatement::CondExpr);
}
case Statement::KindOfDoStatement: {
DoStatementPtr ds(static_pointer_cast<DoStatement>(s));
nullSafeDisableCSE(s, ds->getCondExp());
break;
}
default:
for (int i = s->getKidCount(); i--; ) {
ConstructPtr c(s->getNthKid(i));
if (StatementPtr skid = dpc(Statement, c)) {
disableCSE(skid);
} else {
nullSafeDisableCSE(s, i);
nullSafeDisableCSE(s, dpc(Expression, c));
}
}
break;
@@ -4107,38 +4133,42 @@ void AliasManager::stringOptsRecur(StatementPtr s) {
}
break;
case Statement::KindOfForStatement:
stringOptsRecur(spc(Expression,s->getNthKid(0)), true);
case Statement::KindOfForStatement: {
ForStatementPtr fs = spc(ForStatement, s);
stringOptsRecur(fs->getInitExp(), true);
pushStringScope(s);
stringOptsRecur(spc(Expression,s->getNthKid(1)), false);
stringOptsRecur(spc(Statement, s->getNthKid(2)));
stringOptsRecur(spc(Expression,s->getNthKid(3)), true);
stringOptsRecur(fs->getCondExp(), false);
stringOptsRecur(fs->getBody());
stringOptsRecur(fs->getIncExp(), true);
popStringScope(s);
return;
case Statement::KindOfWhileStatement:
}
case Statement::KindOfWhileStatement: {
WhileStatementPtr ws = spc(WhileStatement, s);
pushStringScope(s);
stringOptsRecur(spc(Expression,s->getNthKid(0)), false);
stringOptsRecur(spc(Statement, s->getNthKid(1)));
stringOptsRecur(ws->getCondExp(), false);
stringOptsRecur(ws->getBody());
popStringScope(s);
return;
case Statement::KindOfDoStatement:
}
case Statement::KindOfDoStatement: {
DoStatementPtr ds = spc(DoStatement, s);
pushStringScope(s);
stringOptsRecur(spc(Statement, s->getNthKid(0)));
stringOptsRecur(spc(Expression,s->getNthKid(1)), false);
stringOptsRecur(ds->getBody());
stringOptsRecur(ds->getCondExp(), false);
popStringScope(s);
return;
case Statement::KindOfForEachStatement:
stringOptsRecur(spc(Expression,s->getNthKid(0)), false);
stringOptsRecur(spc(Expression,s->getNthKid(1)), false);
stringOptsRecur(spc(Expression,s->getNthKid(2)), false);
}
case Statement::KindOfForEachStatement: {
ForEachStatementPtr fs = spc(ForEachStatement, s);
stringOptsRecur(fs->getArrayExp(), false);
stringOptsRecur(fs->getNameExp(), false);
stringOptsRecur(fs->getValueExp(), false);
pushStringScope(s);
stringOptsRecur(spc(Statement, s->getNthKid(3)));
stringOptsRecur(fs->getBody());
popStringScope(s);
return;
}
case Statement::KindOfExpStatement:
stringOptsRecur(spc(ExpStatement,s)->getExpression(), true);
return;
@@ -4146,9 +4176,9 @@ void AliasManager::stringOptsRecur(StatementPtr s) {
case Statement::KindOfBreakStatement:
{
BreakStatementPtr b = spc(BreakStatement, s);
int64 depth = b->getDepth();
int64_t depth = b->getDepth();
if (depth != 1) {
int64 s = m_loopInfo.size() - 1;
int64_t s = m_loopInfo.size() - 1;
if (s >= 0) {
if (!depth || depth > s) depth = s;
while (depth--) {
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __ALIAS_MANAGER_H__
#define __ALIAS_MANAGER_H__
#ifndef incl_HPHP_ALIAS_MANAGER_H_
#define incl_HPHP_ALIAS_MANAGER_H_
#include <compiler/expression/expression.h>
#include "hphp/compiler/expression/expression.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -88,7 +88,7 @@ class AliasManager {
enum { SameAccess, SameLValueAccess, InterfAccess,
DisjointAccess, NotAccess };
AliasManager(int opt);
explicit AliasManager(int opt);
~AliasManager();
void clear();
@@ -141,7 +141,7 @@ class AliasManager {
enum { FallThrough, CondBranch, Branch, Converge };
enum { NoCopyProp = 1, NoDeadStore = 2 };
struct CondStackElem {
CondStackElem(size_t s = 0) : m_size(s), m_exprs() {}
explicit CondStackElem(size_t s = 0) : m_size(s), m_exprs() {}
size_t m_size;
ExpressionPtrList m_exprs;
};
@@ -154,7 +154,7 @@ class AliasManager {
class LoopInfo {
public:
LoopInfo(StatementPtr s);
explicit LoopInfo(StatementPtr s);
StatementPtr m_stmt;
StatementPtrVec m_inner;
@@ -205,7 +205,7 @@ class AliasManager {
StatementPtr canonicalizeRecur(StatementPtr e, int &ret);
void invalidateChainRoots(StatementPtr s);
void nullSafeDisableCSE(StatementPtr parent, int kid);
void nullSafeDisableCSE(StatementPtr parent, ExpressionPtr kid);
void disableCSE(StatementPtr s);
void createCFG(MethodStatementPtr m);
void deleteCFG();
@@ -276,4 +276,4 @@ class AliasManager {
///////////////////////////////////////////////////////////////////////////////
}
#endif // __ALIAS_MANAGER_H__
#endif // incl_HPHP_ALIAS_MANAGER_H_
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+624
Ver Arquivo
@@ -0,0 +1,624 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_ANALYSIS_RESULT_H_
#define incl_HPHP_ANALYSIS_RESULT_H_
#include "hphp/compiler/code_generator.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/analysis/block_scope.h"
#include "hphp/compiler/analysis/symbol_table.h"
#include "hphp/compiler/analysis/function_container.h"
#include "hphp/compiler/package.h"
#include "hphp/util/string_bag.h"
#include "hphp/util/thread_local.h"
#include <boost/graph/adjacency_list.hpp>
#include "tbb/concurrent_hash_map.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(FileScope);
DECLARE_BOOST_TYPES(FunctionScope);
DECLARE_BOOST_TYPES(Location);
DECLARE_BOOST_TYPES(AnalysisResult);
DECLARE_BOOST_TYPES(ScalarExpression);
class AnalysisResult : public BlockScope, public FunctionContainer {
public:
/**
* There are multiple passes over our syntax trees. This lists all of them.
*/
enum Phase {
// parse
ParseAllFiles,
// analyzeProgram
AnalyzeAll,
AnalyzeFinal,
// pre-optimize
FirstPreOptimize,
// inferTypes
FirstInference,
// post-optimize
PostOptimize,
CodeGen,
};
enum FindClassBy {
ClassName,
MethodName,
PropertyName
};
enum GlobalSymbolType {
KindOfStaticGlobalVariable,
KindOfDynamicGlobalVariable,
KindOfMethodStaticVariable,
KindOfClassStaticVariable,
KindOfDynamicConstant,
KindOfPseudoMain,
KindOfRedeclaredFunction,
KindOfRedeclaredClass,
KindOfRedeclaredClassId,
KindOfVolatileClass,
KindOfLazyStaticInitializer,
GlobalSymbolTypeCount
};
class Locker {
public:
explicit Locker(const AnalysisResult *ar) :
m_ar(const_cast<AnalysisResult*>(ar)),
m_mutex(m_ar->getMutex()) {
m_mutex.lock();
}
explicit Locker(AnalysisResultConstPtr ar) :
m_ar(const_cast<AnalysisResult*>(ar.get())),
m_mutex(m_ar->getMutex()) {
m_mutex.lock();
}
Locker(const Locker &l) : m_ar(l.m_ar), m_mutex(l.m_mutex) {
const_cast<Locker&>(l).m_ar = 0;
}
~Locker() {
if (m_ar) m_mutex.unlock();
}
AnalysisResultPtr get() const {
return m_ar->shared_from_this();
}
AnalysisResult *operator->() const {
return m_ar;
}
private:
AnalysisResult *m_ar;
Mutex &m_mutex;
};
public:
AnalysisResult();
Locker lock() const { return Locker(this); }
void setPackage(Package *package) { m_package = package;}
void setParseOnDemand(bool v) { m_parseOnDemand = v;}
bool isParseOnDemand() const { return m_package && m_parseOnDemand;}
void setParseOnDemandDirs(const std::vector<std::string> &dirs) {
assert(m_package && !m_parseOnDemand);
m_parseOnDemandDirs = dirs;
}
/**
* create_function() generates extra PHP code that defines the lambda.
* Stores the code in a temporary string, so we can parse this as an
* extra file appended to parsed code.
*/
void appendExtraCode(const std::string &key, const std::string &code);
void appendExtraCode(const std::string &key, const std::string &code) const;
void parseExtraCode(const std::string &key);
Phase getPhase() const { return m_phase;}
void setPhase(Phase phase) { m_phase = phase;}
int getFunctionCount() const;
int getClassCount() const;
void countReturnTypes(std::map<std::string, int> &counts);
void addEntryPoint(const std::string &name);
void addEntryPoints(const std::vector<std::string> &names);
void addNSFallbackFunc(ConstructPtr c, FileScopePtr fs);
void loadBuiltins();
void analyzeProgram(bool system = false);
void analyzeIncludes();
void analyzeProgramFinal();
void analyzePerfectVirtuals();
void dump();
void docJson(const std::string &filename);
void visitFiles(void (*cb)(AnalysisResultPtr, StatementPtr, void*),
void *data);
void getScopesSet(BlockScopeRawPtrQueue &v);
void preOptimize();
void inferTypes();
void postOptimize();
/**
* Force all class variables to be variants, since l-val or reference
* of dynamic properties are used.
*/
void forceClassVariants(
ClassScopePtr curScope,
bool doStatic,
bool acquireLocks = false);
/**
* Force specified variable of all classes to be variants.
*/
void forceClassVariants(
const std::string &name,
ClassScopePtr curScope,
bool doStatic,
bool acquireLocks = false);
/**
* Code generation functions.
*/
bool outputAllPHP(CodeGenerator::Output output);
/**
* Parser creates a FileScope upon parsing a new file.
*/
void parseOnDemand(const std::string &name) const;
void parseOnDemandByClass(const std::string &name) const {
parseOnDemandBy(name, Option::AutoloadClassMap);
}
void parseOnDemandByFunction(const std::string &name) const {
parseOnDemandBy(name, Option::AutoloadFuncMap);
}
void parseOnDemandByConstant(const std::string &name) const {
parseOnDemandBy(name, Option::AutoloadConstMap);
}
void parseOnDemandBy(const std::string &name,
const std::map<std::string,std::string>& amap) const;
FileScopePtr findFileScope(const std::string &name) const;
const StringToFileScopePtrMap &getAllFiles() { return m_files;}
const std::vector<FileScopePtr> &getAllFilesVector() {
return m_fileScopes;
}
void addFileScope(FileScopePtr fileScope);
/**
* Declarations
*/
bool declareFunction(FunctionScopePtr funcScope) const;
bool declareClass(ClassScopePtr classScope) const;
void declareUnknownClass(const std::string &name);
bool declareConst(FileScopePtr fs, const std::string &name);
/**
* Dependencies
*/
void link(FileScopePtr user, FileScopePtr provider);
bool addClassDependency(FileScopePtr usingFile,
const std::string &className);
bool addFunctionDependency(FileScopePtr usingFile,
const std::string &functionName);
bool addIncludeDependency(FileScopePtr usingFile,
const std::string &includeFilename);
bool addConstantDependency(FileScopePtr usingFile,
const std::string &constantName);
ClassScopePtr findClass(const std::string &className) const;
ClassScopePtr findClass(const std::string &className,
FindClassBy by);
/**
* Find all the redeclared classes by the name, excluding system classes.
* Note that system classes cannot be redeclared.
*/
const ClassScopePtrVec &findRedeclaredClasses(
const std::string &className) const;
/**
* Find all the classes by the name, including system classes.
*/
ClassScopePtrVec findClasses(const std::string &className) const;
bool classMemberExists(const std::string &name, FindClassBy by) const;
ClassScopePtr findExactClass(ConstructPtr cs, const std::string &name) const;
bool checkClassPresent(ConstructPtr cs, const std::string &name) const;
FunctionScopePtr findFunction(const std::string &funcName) const ;
BlockScopeConstPtr findConstantDeclarer(const std::string &constName) const {
return const_cast<AnalysisResult*>(this)->findConstantDeclarer(constName);
}
BlockScopePtr findConstantDeclarer(const std::string &constName);
bool isConstantDeclared(const std::string &constName) const;
bool isConstantRedeclared(const std::string &constName) const;
bool isSystemConstant(const std::string &constName) const;
/**
* For function declaration parsing.
*/
static std::string prepareFile(const char *root, const std::string &fileName,
bool chop, bool stripPath = true);
void setOutputPath(const std::string &path) {
m_outputPath = path;
}
const std::string &getOutputPath() {
return m_outputPath;
}
/**
* Literal string to String precomputation
*/
std::string getLiteralStringName(int64_t hash, int index, bool iproxy = false);
std::string getLitVarStringName(int64_t hash, int index, bool iproxy = false);
int getLiteralStringId(const std::string &s, int &index);
/**
* Profiling runtime parameter type
*/
std::string getFuncId(ClassScopePtr cls, FunctionScopePtr func);
std::vector<const char *> &getFuncTableBucket(FunctionScopePtr func);
std::set<std::string> m_variableTableFunctions;
std::set<int> m_concatLengths;
int m_arrayLitstrKeyMaxSize;
int m_arrayIntegerKeyMaxSize;
std::string getHashedName(int64_t hash, int index, const char *prefix,
bool longName = false);
void addNamedLiteralVarString(const std::string &s);
void addNamedScalarVarArray(const std::string &s);
StringToClassScopePtrVecMap getExtensionClasses();
void addInteger(int64_t n);
private:
Package *m_package;
bool m_parseOnDemand;
std::vector<std::string> m_parseOnDemandDirs;
std::set<std::pair<ConstructPtr, FileScopePtr> > m_nsFallbackFuncs;
Phase m_phase;
StringToFileScopePtrMap m_files;
FileScopePtrVec m_fileScopes;
StringBag m_extraCodeFileNames;
std::map<std::string, std::string> m_extraCodes;
StringToClassScopePtrMap m_systemClasses;
StringToFunctionScopePtrMap m_functionDecs;
StringToFunctionScopePtrVecMap m_functionReDecs;
StringToClassScopePtrVecMap m_classDecs;
StringToClassScopePtrVecMap m_methodToClassDecs;
StringToFileScopePtrMap m_constDecs;
std::set<std::string> m_constRedeclared;
// Map names of class aliases to the class names they will alias.
// Only in WholeProgram mode. See markRedeclaringClasses.
std::multimap<std::string,std::string> m_classAliases;
// Names of type aliases.
std::set<std::string> m_typeAliasNames;
bool m_classForcedVariants[2];
StatementPtrVec m_stmts;
StatementPtr m_stmt;
std::string m_outputPath;
public:
AnalysisResultPtr shared_from_this() {
return boost::static_pointer_cast<AnalysisResult>
(BlockScope::shared_from_this());
}
AnalysisResultConstPtr shared_from_this() const {
return boost::static_pointer_cast<const AnalysisResult>
(BlockScope::shared_from_this());
}
private:
BlockScopePtrVec m_ignoredScopes;
typedef boost::adjacency_list<boost::setS, boost::vecS> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Graph>::adjacency_iterator adjacency_iterator;
Mutex m_depGraphMutex;
Graph m_depGraph;
typedef std::map<vertex_descriptor, FileScopePtr> VertexToFileScopePtrMap;
VertexToFileScopePtrMap m_fileVertMap;
/**
* Checks whether the file is in one of the on-demand parsing directories.
*/
bool inParseOnDemandDirs(const std::string &filename) const;
/*
* Find the names of all functions and classes in the program; mark
* functions with duplicate names as redeclaring, but duplicate
* classes aren't yet marked. See markRedeclaringClasses.
*/
void collectFunctionsAndClasses(FileScopePtr fs);
/**
* Making sure symbol orders are not different even with multithreading, so
* to make sure generated code are consistent every time.
*/
void canonicalizeSymbolOrder();
/*
* After all the class names have been collected and symbol order is
* canonicalized, this passes through and marks duplicate class
* names as redeclaring.
*/
void markRedeclaringClasses();
/**
* Checks circular class derivations that can cause stack overflows for
* subsequent analysis. Also checks to make sure no two redundant parents.
*/
void checkClassDerivations();
void resolveNSFallbackFuncs();
int getFileSize(FileScopePtr fs);
public:
static DECLARE_THREAD_LOCAL(BlockScopeRawPtr, s_currentScopeThreadLocal);
static DECLARE_THREAD_LOCAL(BlockScopeRawPtrFlagsHashMap,
s_changedScopesMapThreadLocal);
#ifdef HPHP_INSTRUMENT_PROCESS_PARALLEL
static int s_NumDoJobCalls;
static ConcurrentBlockScopeRawPtrIntHashMap s_DoJobUniqueScopes;
static int s_NumForceRerunGlobal;
static int s_NumReactivateGlobal;
static int s_NumForceRerunUseKinds;
static int s_NumReactivateUseKinds;
#endif /* HPHP_INSTRUMENT_PROCESS_PARALLEL */
private:
template <typename Visitor>
void processScopesParallel(const char *id, void *opaque = nullptr);
template <typename Visitor>
void preWaitCallback(bool first,
const BlockScopeRawPtrQueue &scopes,
void *opaque);
template <typename Visitor>
bool postWaitCallback(bool first,
bool again,
const BlockScopeRawPtrQueue &scopes,
void *opaque);
};
///////////////////////////////////////////////////////////////////////////////
// Type Inference
class RescheduleException : public Exception {
public:
explicit RescheduleException(BlockScopeRawPtr scope) :
Exception(), m_scope(scope) {}
BlockScopeRawPtr &getScope() { return m_scope; }
#ifdef HPHP_INSTRUMENT_TYPE_INF
static int s_NumReschedules;
static int s_NumForceRerunSelfCaller;
static int s_NumRetTypesChanged;
#endif /* HPHP_INSTRUMENT_TYPE_INF */
private:
BlockScopeRawPtr m_scope;
};
class SetCurrentScope {
public:
explicit SetCurrentScope(BlockScopeRawPtr scope) {
assert(!((*AnalysisResult::s_currentScopeThreadLocal).get()));
*AnalysisResult::s_currentScopeThreadLocal = scope;
scope->setInVisitScopes(true);
}
~SetCurrentScope() {
(*AnalysisResult::s_currentScopeThreadLocal)->setInVisitScopes(false);
AnalysisResult::s_currentScopeThreadLocal.destroy();
}
};
#define IMPLEMENT_INFER_AND_CHECK_ASSERT(scope) \
do { \
assert(AnalysisResult::s_currentScopeThreadLocal->get()); \
assert(AnalysisResult::s_currentScopeThreadLocal->get() == \
(scope).get()); \
(scope)->getInferTypesMutex().assertOwnedBySelf(); \
} while (0)
#ifdef HPHP_INSTRUMENT_TYPE_INF
typedef std::pair < const char *, int > LEntry;
struct LEntryHasher {
bool equal(const LEntry &l1, const LEntry &l2) const {
assert(l1.first);
assert(l2.first);
return l1.second == l2.second &&
strcmp(l1.first, l2.first) == 0;
}
size_t hash(const LEntry &l) const {
assert(l.first);
return hash_string(l.first) ^ l.second;
}
};
typedef tbb::concurrent_hash_map < LEntry, int, LEntryHasher >
LProfileMap;
#endif /* HPHP_INSTRUMENT_TYPE_INF */
class BaseTryLock {
friend class TryLock;
friend class ConditionalTryLock;
public:
#ifdef HPHP_INSTRUMENT_TYPE_INF
static LProfileMap s_LockProfileMap;
#endif /* HPHP_INSTRUMENT_TYPE_INF */
private:
inline bool acquireImpl(BlockScopeRawPtr scopeToLock) {
// A class scope can NEVER grab a lock on a function scope
BlockScopeRawPtr current ATTRIBUTE_UNUSED =
*(AnalysisResult::s_currentScopeThreadLocal.get());
assert(current);
assert(!current->is(BlockScope::ClassScope) ||
!scopeToLock->is(BlockScope::FunctionScope));
return m_mutex.tryLock();
}
#ifdef HPHP_INSTRUMENT_TYPE_INF
BaseTryLock(BlockScopeRawPtr scopeToLock,
const char * fromFunction,
int fromLine,
bool lockCondition = true,
bool profile = true)
: m_profiler(profile),
m_mutex(scopeToLock->getInferTypesMutex()),
m_acquired(false) {
if (LIKELY(lockCondition)) {
bool success = acquireImpl(scopeToLock);
if (UNLIKELY(!success)) {
// put entry in profiler
LProfileMap::accessor acc;
LEntry key(fromFunction, fromLine);
if (!s_LockProfileMap.insert(acc, key)) {
// pre-existing
acc->second++;
} else {
acc->second = 1;
}
// could not acquire lock, throw reschedule exception
throw RescheduleException(scopeToLock);
}
assert(success);
m_acquired = true;
m_mutex.assertOwnedBySelf();
}
}
#else
explicit BaseTryLock(BlockScopeRawPtr scopeToLock,
bool lockCondition = true,
bool profile = true)
: m_profiler(profile),
m_mutex(scopeToLock->getInferTypesMutex()),
m_acquired(false) {
if (LIKELY(lockCondition)) {
bool success = acquireImpl(scopeToLock);
if (UNLIKELY(!success)) {
// could not acquire lock, throw reschedule exception
throw RescheduleException(scopeToLock);
}
assert(success);
m_acquired = true;
m_mutex.assertOwnedBySelf();
}
}
#endif /* HPHP_INSTRUMENT_TYPE_INF */
~BaseTryLock() {
if (m_acquired) m_mutex.unlock();
}
LockProfiler m_profiler;
InferTypesMutex& m_mutex;
bool m_acquired;
};
class TryLock : public BaseTryLock {
public:
#ifdef HPHP_INSTRUMENT_TYPE_INF
TryLock(BlockScopeRawPtr scopeToLock,
const char * fromFunction,
int fromLine,
bool profile = true) :
BaseTryLock(scopeToLock, fromFunction, fromLine, true, profile) {}
#else
explicit TryLock(BlockScopeRawPtr scopeToLock,
bool profile = true) :
BaseTryLock(scopeToLock, true, profile) {}
#endif /* HPHP_INSTRUMENT_TYPE_INF */
};
class ConditionalTryLock : public BaseTryLock {
public:
#ifdef HPHP_INSTRUMENT_TYPE_INF
ConditionalTryLock(BlockScopeRawPtr scopeToLock,
const char * fromFunction,
int fromLine,
bool condition,
bool profile = true) :
BaseTryLock(scopeToLock, fromFunction, fromLine, condition, profile) {}
#else
ConditionalTryLock(BlockScopeRawPtr scopeToLock,
bool condition,
bool profile = true) :
BaseTryLock(scopeToLock, condition, profile) {}
#endif /* HPHP_INSTRUMENT_TYPE_INF */
};
#define GET_LOCK(scopeToLock) \
SimpleLock _lock((scopeToLock)->getInferTypesMutex())
#define COND_GET_LOCK(scopeToLock, condition) \
SimpleConditionalLock _clock((scopeToLock)->getInferTypesMutex(), \
(condition))
#define GET_LOCK_THIS() \
SimpleLock _lock(this->getInferTypesMutex())
#define COND_GET_LOCK_THIS(condition) \
SimpleConditionalLock _clock(this->getInferTypesMutex(), (condition))
#ifdef HPHP_INSTRUMENT_TYPE_INF
#define TRY_LOCK(scopeToLock) \
TryLock _tl((scopeToLock), __PRETTY_FUNCTION__, __LINE__)
#define COND_TRY_LOCK(scopeToLock, condition) \
ConditionalTryLock _ctl((scopeToLock), __PRETTY_FUNCTION__, \
__LINE__, condition)
#else
#define TRY_LOCK(scopeToLock) \
TryLock _tl((scopeToLock))
#define COND_TRY_LOCK(scopeToLock, condition) \
ConditionalTryLock _ctl((scopeToLock), (condition))
#endif /* HPHP_INSTRUMENT_TYPE_INF */
#define TRY_LOCK_THIS() \
TRY_LOCK(BlockScopeRawPtr(this))
#define COND_TRY_LOCK_THIS(condition) \
COND_TRY_LOCK(BlockScopeRawPtr(this), condition)
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_ANALYSIS_RESULT_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,8 +14,8 @@
+----------------------------------------------------------------------+
*/
#include <compiler/analysis/ast_walker.h>
#include <compiler/statement/statement.h>
#include "hphp/compiler/analysis/ast_walker.h"
#include "hphp/compiler/statement/statement.h"
using namespace HPHP;
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,11 +14,11 @@
+----------------------------------------------------------------------+
*/
#ifndef __AST_WALKER_H__
#define __AST_WALKER_H__
#ifndef incl_HPHP_AST_WALKER_H_
#define incl_HPHP_AST_WALKER_H_
#include <compiler/hphp.h>
#include <compiler/construct.h>
#include "hphp/compiler/hphp.h"
#include "hphp/compiler/construct.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -26,7 +26,7 @@ namespace HPHP {
class AstWalkerState {
public:
AstWalkerState() : index(0) {}
AstWalkerState(ConstructRawPtr c) : cp(c), index(0) {}
explicit AstWalkerState(ConstructRawPtr c) : cp(c), index(0) {}
friend bool operator==(const AstWalkerState &s1,
const AstWalkerState &s2) {
@@ -40,7 +40,7 @@ public:
class AstWalkerStateVec : public std::vector<AstWalkerState> {
public:
AstWalkerStateVec() {}
AstWalkerStateVec(ConstructRawPtr cp) {
explicit AstWalkerStateVec(ConstructRawPtr cp) {
push_back(AstWalkerState(cp));
}
};
@@ -116,13 +116,13 @@ public:
static bool SkipRecurse(ConstructRawPtr cp);
static bool SkipRecurse(StatementPtr s) {
return SkipRecurse(s ? s.get() : NULL);
return SkipRecurse(s ? s.get() : nullptr);
}
static bool SkipRecurse(StatementConstPtr s) {
return SkipRecurse(s ? s.get() : NULL);
return SkipRecurse(s ? s.get() : nullptr);
}
static bool SkipRecurse(StatementRawPtr s) {
return SkipRecurse(s ? s.get() : NULL);
return SkipRecurse(s ? s.get() : nullptr);
}
static bool SkipRecurse(const Statement *stmt);
@@ -132,4 +132,4 @@ public:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __AST_WALKER_H__
#endif // incl_HPHP_AST_WALKER_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -15,8 +15,8 @@
*/
#include <stdlib.h>
#include <compiler/analysis/bit_set_vec.h>
#include <compiler/analysis/data_flow.h>
#include "hphp/compiler/analysis/bit_set_vec.h"
#include "hphp/compiler/analysis/data_flow.h"
using namespace HPHP;
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -19,7 +19,7 @@
#include <limits.h>
#include <stddef.h>
#include "util/assertions.h"
#include "hphp/util/assertions.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,16 +14,16 @@
+----------------------------------------------------------------------+
*/
#include <compiler/expression/expression.h>
#include "hphp/compiler/expression/expression.h"
#include <compiler/analysis/block_scope.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/statement/statement_list.h>
#include <compiler/analysis/variable_table.h>
#include <compiler/analysis/constant_table.h>
#include <compiler/analysis/class_scope.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/analysis/file_scope.h>
#include "hphp/compiler/analysis/block_scope.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/statement/statement_list.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/constant_table.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/file_scope.h"
using namespace HPHP;
@@ -89,13 +89,29 @@ AnalysisResultRawPtr BlockScope::getContainingProgram() {
return AnalysisResultRawPtr((AnalysisResult*)bs);
}
ClassScopeRawPtr BlockScope::getContainingClass() {
FunctionScopeRawPtr BlockScope::getContainingNonClosureFunction() {
BlockScope *bs = this;
if (bs->is(BlockScope::FunctionScope)) {
// walk out through all the closures
while (bs && bs->is(BlockScope::FunctionScope)) {
HPHP::FunctionScope *fs = static_cast<HPHP::FunctionScope*>(bs);
if (!fs->isClosure() && !fs->isGeneratorFromClosure()) {
return FunctionScopeRawPtr(fs);
}
bs = bs->m_outerScope.get();
}
if (bs && !bs->is(BlockScope::ClassScope)) {
bs = 0;
return FunctionScopeRawPtr();
}
ClassScopeRawPtr BlockScope::getContainingClass() {
BlockScope *bs = getContainingNonClosureFunction().get();
if (!bs) {
bs = this;
}
if (bs && bs->is(BlockScope::FunctionScope)) {
bs = bs->m_outerScope.get();
}
if (!bs || !bs->is(BlockScope::ClassScope)) {
return ClassScopeRawPtr();
}
return ClassScopeRawPtr((HPHP::ClassScope*)bs);
}
@@ -225,11 +241,6 @@ void BlockScope::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_variables->outputPHP(cg, ar);
}
void BlockScope::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_constants->outputCPP(cg, ar);
m_variables->outputCPP(cg, ar);
}
int BlockScope::ScopeCompare::cmp(const BlockScopeRawPtr &p1,
const BlockScopeRawPtr &p2) const {
int d1 = p1->m_kind - p2->m_kind;
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,16 +14,16 @@
+----------------------------------------------------------------------+
*/
#ifndef __BLOCK_SCOPE_H__
#define __BLOCK_SCOPE_H__
#ifndef incl_HPHP_BLOCK_SCOPE_H_
#define incl_HPHP_BLOCK_SCOPE_H_
#include <compiler/hphp.h>
#include "hphp/compiler/hphp.h"
#include <util/bits.h>
#include <util/lock.h>
#include <runtime/base/macros.h>
#include "hphp/util/bits.h"
#include "hphp/util/lock.h"
#include "hphp/runtime/base/macros.h"
#include <tbb/concurrent_hash_map.h>
#include "tbb/concurrent_hash_map.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -178,6 +178,7 @@ public:
VariableTablePtr getVariables() { return m_variables;}
ConstantTablePtr getConstants() { return m_constants;}
ClassScopeRawPtr getContainingClass();
FunctionScopeRawPtr getContainingNonClosureFunction();
FunctionScopeRawPtr getContainingFunction() const {
return FunctionScopeRawPtr(is(FunctionScope) ?
(HPHP::FunctionScope*)this : 0);
@@ -218,9 +219,7 @@ public:
/**
* Code gen
*/
virtual void outputCPPDef(CodeGenerator &cg) {}
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual bool inPseudoMain() const {
return false;
@@ -367,4 +366,4 @@ public:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __BLOCK_SCOPE_H__
#endif // incl_HPHP_BLOCK_SCOPE_H_
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+490
Ver Arquivo
@@ -0,0 +1,490 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_CLASS_SCOPE_H_
#define incl_HPHP_CLASS_SCOPE_H_
#include "hphp/compiler/analysis/block_scope.h"
#include "hphp/compiler/analysis/function_container.h"
#include "hphp/compiler/statement/class_statement.h"
#include "hphp/compiler/statement/method_statement.h"
#include "hphp/compiler/statement/trait_prec_statement.h"
#include "hphp/compiler/statement/trait_alias_statement.h"
#include "hphp/compiler/expression/user_attribute.h"
#include "hphp/util/json.h"
#include "hphp/util/case_insensitive.h"
#include "hphp/compiler/option.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
DECLARE_BOOST_TYPES(StatementList);
DECLARE_BOOST_TYPES(FunctionScope);
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(FileScope);
class Symbol;
/**
* A class scope corresponds to a class declaration. We store all
* inferred types and analyzed results here, so not to pollute syntax trees.
*/
class ClassScope : public BlockScope, public FunctionContainer,
public JSON::CodeError::ISerializable,
public JSON::DocTarget::ISerializable {
public:
enum KindOf {
KindOfObjectClass,
KindOfAbstractClass,
KindOfFinalClass,
KindOfInterface,
KindOfTrait
};
#define DECLARE_MAGIC(prefix, prev) \
prefix ## UnknownPropGetter = prev << 1, /* __get */ \
prefix ## UnknownPropSetter = prev << 2, /* __set */ \
prefix ## UnknownPropTester = prev << 3, /* __isset */ \
prefix ## PropUnsetter = prev << 4, /* __unset */ \
prefix ## UnknownMethodHandler = prev << 5, /* __call */ \
prefix ## UnknownStaticMethodHandler = prev << 6, /* __callStatic */ \
prefix ## InvokeMethod = prev << 7, /* __invoke */ \
prefix ## ArrayAccess = prev << 8 /* Implements ArrayAccess */
enum Attribute {
System = 0x001,
Extension = 0x002,
/**
* set iff there is a __construct method. check ClassNameConstructor if
* you want to know whether there is a class-name constructor.
*/
HasConstructor = 0x0004,
ClassNameConstructor = 0x0008,
HasDestructor = 0x0010,
NotFinal = 0x0020,
UsesUnknownTrait = 0x0040,
DECLARE_MAGIC(Has, UsesUnknownTrait),
DECLARE_MAGIC(MayHave, HasArrayAccess),
DECLARE_MAGIC(Inherits, MayHaveArrayAccess)
};
enum Modifier {
Public = 1,
Protected = 2,
Private = 4,
Static = 8,
Abstract = 16,
Final = 32
};
enum Derivation {
FromNormal = 0,
DirectFromRedeclared,
IndirectFromRedeclared
};
enum JumpTableName {
JumpTableCallInfo
};
public:
ClassScope(KindOf kindOf, const std::string &name,
const std::string &parent,
const std::vector<std::string> &bases,
const std::string &docComment, StatementPtr stmt,
const std::vector<UserAttributePtr> &attrs);
/**
* Special constructor for extension classes.
*/
ClassScope(AnalysisResultPtr ar,
const std::string &name, const std::string &parent,
const std::vector<std::string> &bases,
const FunctionScopePtrVec &methods);
bool classNameCtor() const {
return getAttribute(ClassNameConstructor);
}
const std::string &getOriginalName() const;
std::string getDocName() const;
virtual std::string getId() const;
void checkDerivation(AnalysisResultPtr ar, hphp_string_iset &seen);
const std::string &getOriginalParent() const { return m_parent; }
/**
* Returns topmost parent class that has the method.
*/
ClassScopePtr getRootParent(AnalysisResultConstPtr ar,
const std::string &methodName = "");
void getRootParents(AnalysisResultConstPtr ar, const std::string &methodName,
ClassScopePtrVec &roots, ClassScopePtr curClass);
/**
* Whether this is a user-defined class.
*/
bool isUserClass() const { return !getAttribute(System);}
bool isExtensionClass() const { return getAttribute(Extension); }
bool isDynamic() const { return m_dynamic; }
bool isBaseClass() const { return m_bases.empty(); }
/**
* Whether this class name was declared twice or more.
*/
void setRedeclaring(AnalysisResultConstPtr ar, int redecId);
bool isRedeclaring() const { return m_redeclaring >= 0;}
int getRedeclaringId() { return m_redeclaring; }
void setStaticDynamic(AnalysisResultConstPtr ar);
void setDynamic(AnalysisResultConstPtr ar, const std::string &name);
void addReferer(BlockScopePtr ref, int useKinds);
/* For class_exists */
void setVolatile();
bool isVolatile() const { return m_volatile;}
bool isPersistent() const { return m_persistent; }
void setPersistent(bool p) { m_persistent = p; }
bool needLazyStaticInitializer();
Derivation derivesFromRedeclaring() const {
return m_derivesFromRedeclaring;
}
bool derivedByDynamic() const {
return m_derivedByDynamic;
}
/* Whether this class is brought in by a separable extension */
void setSepExtension() { m_sep = true;}
bool isSepExtension() const { return m_sep;}
/**
* Get/set attributes.
*/
void setSystem();
void setAttribute(Attribute attr) { m_attribute |= attr;}
void clearAttribute(Attribute attr) { m_attribute &= ~attr;}
bool getAttribute(Attribute attr) const {
return m_attribute & attr;
}
bool hasAttribute(Attribute attr, AnalysisResultConstPtr ar) const {
if (getAttribute(attr)) return true;
ClassScopePtr parent = getParentScope(ar);
return parent && !parent->isRedeclaring() && parent->hasAttribute(attr, ar);
}
void setKnownBase(int i) { assert(i < 32); m_knownBases |= 1u << i; }
bool hasUnknownBases() const {
int n = m_bases.size();
if (!n) return false;
if (n >= 32) n = 0;
return m_knownBases != (((1u << n) - 1) & 0xffffffff);
}
bool hasKnownBase(int i) const {
return m_knownBases & (1u << (i < 32 ? i : 31));
}
const FunctionScopePtrVec &getFunctionsVec() const {
return m_functionsVec;
}
/**
* Called by ClassScope to prepare name => method/property map.
*/
void collectMethods(AnalysisResultPtr ar,
StringToFunctionScopePtrMap &func,
bool collectPrivate = true,
bool forInvoke = false);
/**
* Whether or not we can directly call ObjectData::o_invoke() when lookup
* in this class fails. If false, we need to call parent::o_invoke(), which
* may be redeclared or may have private methods that need to check class
* context.
*/
bool needsInvokeParent(AnalysisResultConstPtr ar, bool considerSelf = true);
/*
void collectProperties(AnalysisResultPtr ar,
std::set<std::string> &names,
bool collectPrivate = true) const;
*/
/**
* Testing whether this class derives from another.
*/
bool derivesDirectlyFrom(const std::string &base) const;
bool derivesFrom(AnalysisResultConstPtr ar, const std::string &base,
bool strict, bool def) const;
/**
* Find a common parent of two classes; returns "" if there is no such.
*/
static ClassScopePtr FindCommonParent(AnalysisResultConstPtr ar,
const std::string &cn1,
const std::string &cn2);
/**
* Look up function by name.
*/
FunctionScopePtr findFunction(AnalysisResultConstPtr ar,
const std::string &name,
bool recursive,
bool exclIntfBase = false);
/**
* Look up constructor, both __construct and class-name constructor.
*/
FunctionScopePtr findConstructor(AnalysisResultConstPtr ar,
bool recursive);
Symbol *findProperty(ClassScopePtr &cls, const std::string &name,
AnalysisResultConstPtr ar);
/**
* Caller is assumed to hold a lock on this scope
*/
TypePtr checkProperty(BlockScopeRawPtr context,
Symbol *sym, TypePtr type,
bool coerce, AnalysisResultConstPtr ar);
/**
* Caller is *NOT* assumed to hold any locks. Context is
*/
TypePtr checkConst(BlockScopeRawPtr context,
const std::string &name, TypePtr type,
bool coerce, AnalysisResultConstPtr ar,
ConstructPtr construct,
const std::vector<std::string> &bases,
BlockScope *&defScope);
/**
* Collect parent class names.
*/
void getAllParents(AnalysisResultConstPtr ar,
std::vector<std::string> &names);
void getInterfaces(AnalysisResultConstPtr ar,
std::vector<std::string> &names,
bool recursive = true) const;
std::vector<std::string> &getBases() { return m_bases;}
typedef hphp_hash_map<std::string, ExpressionPtr, string_hashi,
string_eqstri> UserAttributeMap;
UserAttributeMap& userAttributes() { return m_userAttributes;}
ClassScopePtr getParentScope(AnalysisResultConstPtr ar) const;
void addUsedTrait(const std::string &s) {
if (!usesTrait(s)) {
m_usedTraitNames.push_back(s);
}
}
void addUsedTraits(const std::vector<std::string> &names) {
for (unsigned i = 0; i < names.size(); i++) {
if (!usesTrait(names[i])) {
m_usedTraitNames.push_back(names[i]);
}
}
}
const std::vector<std::string> &getUsedTraitNames() const {
return m_usedTraitNames;
}
const std::vector<std::pair<std::string, std::string> > &getTraitAliases()
const {
return m_traitAliases;
}
void addTraitAlias(TraitAliasStatementPtr aliasStmt);
void importUsedTraits(AnalysisResultPtr ar);
/**
* Serialize the iface, not everything.
*/
void serialize(JSON::CodeError::OutputStream &out) const;
void serialize(JSON::DocTarget::OutputStream &out) const;
bool isInterface() const { return m_kindOf == KindOfInterface; }
bool isFinal() const { return m_kindOf == KindOfFinalClass ||
m_kindOf == KindOfTrait; }
bool isAbstract() const { return m_kindOf == KindOfAbstractClass ||
m_kindOf == KindOfTrait; }
bool isTrait() const { return m_kindOf == KindOfTrait; }
bool hasProperty(const std::string &name) const;
bool hasConst(const std::string &name) const;
static bool NeedStaticArray(ClassScopePtr cls, FunctionScopePtr func);
void inheritedMagicMethods(ClassScopePtr super);
void derivedMagicMethods(ClassScopePtr super);
/* true if it might, false if it doesnt */
bool implementsArrayAccess();
/* true if it might, false if it doesnt */
bool implementsAccessor(int prop);
void outputForwardDeclaration(CodeGenerator &cg);
void clearBases() {
m_bases.clear();
m_parent = "";
}
/**
* Override function container
*/
bool addFunction(AnalysisResultConstPtr ar,
FunctionScopePtr funcScope);
void setNeedsCppCtor(bool needsCppCtor) {
m_needsCppCtor = needsCppCtor;
}
bool needsCppCtor() const {
return m_needsCppCtor;
}
void setNeedsInitMethod(bool needsInit) {
m_needsInit = needsInit;
}
bool needsInitMethod() const {
return m_needsInit;
}
bool canSkipCreateMethod(AnalysisResultConstPtr ar) const;
bool checkHasPropTable(AnalysisResultConstPtr ar);
private:
// need to maintain declaration order for ClassInfo map
FunctionScopePtrVec m_functionsVec;
std::string m_parent;
mutable std::vector<std::string> m_bases;
UserAttributeMap m_userAttributes;
std::vector<std::string> m_usedTraitNames;
// m_traitAliases is used to support ReflectionClass::getTraitAliases
std::vector<std::pair<std::string, std::string> > m_traitAliases;
struct TraitMethod {
const ClassScopePtr m_trait;
const MethodStatementPtr m_method;
const std::string m_originalName;
ModifierExpressionPtr m_modifiers;
const StatementPtr m_ruleStmt; // for methods imported via aliasing
TraitMethod(ClassScopePtr trait, MethodStatementPtr method,
ModifierExpressionPtr modifiers, StatementPtr ruleStmt) :
m_trait(trait), m_method(method),
m_originalName(method->getOriginalName()), m_modifiers(modifiers),
m_ruleStmt(ruleStmt) {
}
TraitMethod(ClassScopePtr trait, MethodStatementPtr method,
ModifierExpressionPtr modifiers, StatementPtr ruleStmt,
const std::string &originalName) :
m_trait(trait), m_method(method), m_originalName(originalName),
m_modifiers(modifiers), m_ruleStmt(ruleStmt) {
}
};
typedef std::list<TraitMethod> TraitMethodList;
typedef std::map<std::string, TraitMethodList> MethodToTraitListMap;
typedef std::map<std::string, std::string> GeneratorRenameMap;
MethodToTraitListMap m_importMethToTraitMap;
typedef std::map<std::string, MethodStatementPtr> ImportedMethodMap;
mutable int m_attribute;
int m_redeclaring; // multiple definition of the same class
KindOf m_kindOf;
Derivation m_derivesFromRedeclaring;
enum TraitStatus {
NOT_FLATTENED,
BEING_FLATTENED,
FLATTENED
} m_traitStatus;
unsigned m_dynamic:1;
unsigned m_volatile:1; // for class_exists
unsigned m_persistent:1;
unsigned m_derivedByDynamic:1;
unsigned m_sep:1;
unsigned m_needsCppCtor:1;
unsigned m_needsInit:1;
// m_knownBases has a bit for each base class saying whether
// its known to exist at the point of definition of this class.
// for classes with more than 31 bases, bit 31 is set iff
// bases 32 through n are all known.
unsigned m_knownBases;
void addImportTraitMethod(const TraitMethod &traitMethod,
const std::string &methName);
void informClosuresAboutScopeClone(ConstructPtr root,
FunctionScopePtr outerScope,
AnalysisResultPtr ar);
void setImportTraitMethodModifiers(const std::string &methName,
ClassScopePtr traitCls,
ModifierExpressionPtr modifiers);
MethodStatementPtr importTraitMethod(const TraitMethod& traitMethod,
AnalysisResultPtr ar,
std::string methName,
GeneratorRenameMap& genRenameMap,
const ImportedMethodMap &
importedTraitMethods);
void importTraitProperties(AnalysisResultPtr ar);
void relinkGeneratorMethods(AnalysisResultPtr ar,
ImportedMethodMap& importedMethods);
void findTraitMethodsToImport(AnalysisResultPtr ar, ClassScopePtr trait);
MethodStatementPtr findTraitMethod(AnalysisResultPtr ar,
ClassScopePtr trait,
const std::string &methodName,
std::set<ClassScopePtr> &visitedTraits);
void applyTraitRules(AnalysisResultPtr ar);
void applyTraitPrecRule(TraitPrecStatementPtr stmt);
void applyTraitAliasRule(AnalysisResultPtr ar, TraitAliasStatementPtr stmt);
ClassScopePtr findSingleTraitWithMethod(AnalysisResultPtr ar,
const std::string &methodName) const;
void removeSpareTraitAbstractMethods(AnalysisResultPtr ar);
bool usesTrait(const std::string &traitName) const;
bool hasMethod(const std::string &methodName) const;
const std::string& getNewGeneratorName(FunctionScopePtr genFuncScope,
GeneratorRenameMap& genRenameMap);
void renameCreateContinuationCalls(AnalysisResultPtr ar, ConstructPtr c,
ImportedMethodMap &importedMethods);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_CLASS_SCOPE_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,13 +14,13 @@
+----------------------------------------------------------------------+
*/
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/file_scope.h>
#include <compiler/parser/parser.h>
#include <compiler/construct.h>
#include <compiler/option.h>
#include <util/exception.h>
#include <util/lock.h>
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/parser/parser.h"
#include "hphp/compiler/construct.h"
#include "hphp/compiler/option.h"
#include "hphp/util/exception.h"
#include "hphp/util/lock.h"
using namespace HPHP::JSON;
@@ -79,7 +79,7 @@ std::vector<const char *> &CodeErrors::getErrorTexts() {
if (ErrorTexts.empty()) {
ErrorTexts.resize(ErrorCount);
#define CODE_ERROR_ENTRY(x) ErrorTexts[x] = #x;
#include "compiler/analysis/core_code_error.inc"
#include "hphp/compiler/analysis/core_code_error.inc"
#undef CODE_ERROR_ENTRY
}
return ErrorTexts;
@@ -178,7 +178,7 @@ void ClearErrors() {
}
void Error(ErrorType error, ConstructPtr construct) {
if (hhvm) return;
if (!Option::RecordErrors) return;
ErrorInfoPtr errorInfo(new ErrorInfo());
errorInfo->m_error = error;
errorInfo->m_construct1 = construct;
@@ -187,7 +187,7 @@ void Error(ErrorType error, ConstructPtr construct) {
}
void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
if (hhvm) return;
if (!Option::RecordErrors) return;
ErrorInfoPtr errorInfo(new ErrorInfo());
errorInfo->m_error = error;
errorInfo->m_construct1 = construct1;
@@ -197,7 +197,7 @@ void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
}
void Error(ErrorType error, ConstructPtr construct, const std::string &data) {
if (hhvm) return;
if (!Option::RecordErrors) return;
ErrorInfoPtr errorInfo(new ErrorInfo());
errorInfo->m_error = error;
errorInfo->m_construct1 = construct;
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,11 +14,11 @@
+----------------------------------------------------------------------+
*/
#ifndef __COMPILER_ERROR_H__
#define __COMPILER_ERROR_H__
#ifndef incl_HPHP_COMPILER_ERROR_H_
#define incl_HPHP_COMPILER_ERROR_H_
#include <compiler/analysis/type.h>
#include <util/json.h>
#include "hphp/compiler/analysis/type.h"
#include "hphp/util/json.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -31,7 +31,7 @@ namespace Compiler {
enum ErrorType {
#define CODE_ERROR_ENTRY(x) x,
#include "compiler/analysis/core_code_error.inc"
#include "hphp/compiler/analysis/core_code_error.inc"
#undef CODE_ERROR_ENTRY
ErrorCount,
NoError
@@ -79,4 +79,4 @@ bool HasError(); // any error
///////////////////////////////////////////////////////////////////////////////
}}
#endif // __COMPILER_ERROR_H__
#endif // incl_HPHP_COMPILER_ERROR_H_
+253
Ver Arquivo
@@ -0,0 +1,253 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/analysis/constant_table.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/type.h"
#include "hphp/compiler/code_generator.h"
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/option.h"
#include "hphp/util/util.h"
#include "hphp/util/hash.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/runtime/base/complex_types.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
ConstantTable::ConstantTable(BlockScope &blockScope)
: SymbolTable(blockScope, true),
m_hasDynamic(false) {
}
///////////////////////////////////////////////////////////////////////////////
TypePtr ConstantTable::add(const std::string &name, TypePtr type,
ExpressionPtr exp, AnalysisResultConstPtr ar,
ConstructPtr construct) {
if (name == "true" || name == "false") {
return Type::Boolean;
}
Symbol *sym = genSymbol(name, true);
if (!sym->declarationSet()) {
assert(!sym->valueSet());
setType(ar, sym, type, true);
sym->setDeclaration(construct);
sym->setValue(exp);
return type;
}
assert(sym->declarationSet() && sym->valueSet());
if (m_blockScope.isFirstPass()) {
if (construct) {
if (exp != sym->getValue()) {
Compiler::Error(Compiler::DeclaredConstantTwice, construct,
sym->getDeclaration());
if (!sym->isDynamic()) {
sym->setDynamic();
m_hasDynamic = true;
}
type = Type::Variant;
}
} else if (exp) {
sym->setValue(exp);
}
setType(ar, sym, type, true);
}
return type;
}
void ConstantTable::setDynamic(AnalysisResultConstPtr ar,
const std::string &name, bool forceVariant) {
Symbol *sym = genSymbol(name, true);
if (!sym->isDynamic()) {
Lock lock(BlockScope::s_constMutex);
sym->setDynamic();
if (sym->getDeclaration()) {
sym->getDeclaration()->getScope()->
addUpdates(BlockScope::UseKindConstRef);
}
m_hasDynamic = true;
if (forceVariant) {
setType(ar, sym, Type::Variant, true);
}
}
}
void ConstantTable::setValue(AnalysisResultConstPtr ar, const std::string &name,
ExpressionPtr value) {
Symbol *sym = getSymbol(name);
assert(sym && sym->isPresent());
sym->setValue(value);
}
bool ConstantTable::isRecursivelyDeclared(AnalysisResultConstPtr ar,
const std::string &name) const {
if (const Symbol *sym ATTRIBUTE_UNUSED = getSymbol(name)) {
assert(sym->isPresent() && sym->valueSet());
return true;
}
ClassScopePtr parent = findParent(ar, name);
if (parent) {
return parent->getConstants()->isRecursivelyDeclared(ar, name);
}
return false;
}
ConstructPtr ConstantTable::getValueRecur(AnalysisResultConstPtr ar,
const std::string &name,
ClassScopePtr &defClass) const {
if (const Symbol *sym = getSymbol(name)) {
assert(sym->isPresent() && sym->valueSet());
if (sym->getValue()) return sym->getValue();
}
ClassScopePtr parent = findParent(ar, name);
if (parent) {
defClass = parent;
return parent->getConstants()->getValueRecur(ar, name, defClass);
}
return ConstructPtr();
}
ConstructPtr ConstantTable::getDeclarationRecur(AnalysisResultConstPtr ar,
const std::string &name,
ClassScopePtr &defClass)
const {
if (const Symbol *sym = getSymbol(name)) {
assert(sym->isPresent() && sym->valueSet());
if (sym->getDeclaration()) return sym->getDeclaration();
}
ClassScopePtr parent = findParent(ar, name);
if (parent) {
defClass = parent;
return parent->getConstants()->getDeclarationRecur(ar, name, defClass);
}
return ConstructPtr();
}
void ConstantTable::cleanupForError(AnalysisResultConstPtr ar) {
AnalysisResult::Locker lock(ar);
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (!sym->isDynamic()) {
sym->setDynamic();
sym->setDeclaration(ConstructPtr());
sym->setValue(ConstructPtr());
}
}
}
TypePtr ConstantTable::check(BlockScopeRawPtr context,
const std::string &name, TypePtr type,
bool coerce, AnalysisResultConstPtr ar,
ConstructPtr construct,
const std::vector<std::string> &bases,
BlockScope *&defScope) {
assert(!m_blockScope.is(BlockScope::FunctionScope));
bool isClassScope = m_blockScope.is(BlockScope::ClassScope);
TypePtr actualType;
defScope = nullptr;
if (name == "true" || name == "false") {
actualType = Type::Boolean;
} else {
Symbol *sym = getSymbol(name);
if (!sym) {
if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
if (isClassScope) {
ClassScopeRawPtr parent = findBase(ar, name, bases);
if (parent) {
actualType = parent->getConstants()->check(
context, name, type, coerce, ar, construct, bases, defScope);
if (defScope) return actualType;
}
}
if (!isClassScope || !((ClassScope*)&m_blockScope)->isTrait()) {
Compiler::Error(Compiler::UseUndeclaredConstant, construct);
}
actualType = isClassScope || !Option::WholeProgram ?
Type::Variant : Type::String;
}
} else {
assert(sym->isPresent());
assert(sym->getType());
assert(sym->isConstant());
defScope = &m_blockScope;
if (isClassScope) {
// if the current scope is a function scope, grab the lock.
// otherwise if it's a class scope, then *try* to grab the lock.
if (context->is(BlockScope::FunctionScope)) {
GET_LOCK(BlockScopeRawPtr(&m_blockScope));
return setType(ar, sym, type, coerce);
} else {
TRY_LOCK(BlockScopeRawPtr(&m_blockScope));
return setType(ar, sym, type, coerce);
}
} else {
Lock lock(m_blockScope.getMutex());
return setType(ar, sym, type, coerce);
}
}
}
return actualType;
}
ClassScopePtr ConstantTable::findParent(AnalysisResultConstPtr ar,
const std::string &name) const {
for (ClassScopePtr parent = m_blockScope.getParentScope(ar);
parent && !parent->isRedeclaring();
parent = parent->getParentScope(ar)) {
if (parent->hasConst(name)) {
return parent;
}
}
return ClassScopePtr();
}
ClassScopeRawPtr ConstantTable::findBase(
AnalysisResultConstPtr ar, const std::string &name,
const std::vector<std::string> &bases) const {
for (int i = bases.size(); i--; ) {
ClassScopeRawPtr p = ar->findClass(bases[i]);
if (!p || p->isRedeclaring()) continue;
if (p->hasConst(name)) return p;
ConstantTablePtr constants = p->getConstants();
p = constants->findBase(ar, name, p->getBases());
if (p) return p;
}
return ClassScopeRawPtr();
}
///////////////////////////////////////////////////////////////////////////////
void ConstantTable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (Option::GenerateInferredTypes) {
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
Symbol *sym = m_symbolVec[i];
if (sym->isSystem()) continue;
cg_printf("// @const %s\t$%s\n",
sym->getFinalType()->toString().c_str(),
sym->getName().c_str());
}
}
}
+106
Ver Arquivo
@@ -0,0 +1,106 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_CONSTANT_TABLE_H_
#define incl_HPHP_CONSTANT_TABLE_H_
#include "hphp/compiler/analysis/symbol_table.h"
#include "hphp/compiler/analysis/block_scope.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
DECLARE_BOOST_TYPES(Expression);
DECLARE_BOOST_TYPES(CodeError);
DECLARE_BOOST_TYPES(ConstantTable);
DECLARE_BOOST_TYPES(ClassScope);
/**
* These are the only places that a new constant can be declared:
*
* const T_STRING = static_scalar
* class { const T_STRING = static_scalar,...}
* define('NAME', static_scalar)
*/
class ConstantTable : public SymbolTable {
public:
explicit ConstantTable(BlockScope &blockScope);
/**
* Whether defining something to be non-scalar value or redeclared, or
* marked up by "Dynamic" note.
*/
bool isDynamic(const std::string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isDynamic();
}
bool hasDynamic() const { return m_hasDynamic; }
/**
* Explicitly setting a constant to be dynamic, mainly for "Dynamic" note.
*/
void setDynamic(AnalysisResultConstPtr ar, const std::string &name,
bool forceVariant);
/**
* Called when a constant is declared (l-value).
*/
TypePtr add(const std::string &name, TypePtr type, ExpressionPtr exp,
AnalysisResultConstPtr ar, ConstructPtr construct);
/**
* Called after a constant is type-inferred
*/
void setValue(AnalysisResultConstPtr ar, const std::string &name,
ExpressionPtr value);
/**
* Called when a constant is used or being evaluated (r-value).
*/
TypePtr check(BlockScopeRawPtr context,
const std::string &name, TypePtr type, bool coerce,
AnalysisResultConstPtr ar, ConstructPtr construct,
const std::vector<std::string> &bases,
BlockScope *&defScope);
/**
* Generate all constant declarations for this symbol table.
*/
void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
bool isRecursivelyDeclared(AnalysisResultConstPtr ar,
const std::string &name) const;
ConstructPtr getValueRecur(AnalysisResultConstPtr ar, const std::string &name,
ClassScopePtr &defClass) const;
ConstructPtr getDeclarationRecur(AnalysisResultConstPtr ar,
const std::string &name,
ClassScopePtr &defClass) const;
void cleanupForError(AnalysisResultConstPtr ar);
private:
bool m_hasDynamic;
ClassScopePtr findParent(AnalysisResultConstPtr ar,
const std::string &name) const;
ClassScopeRawPtr findBase(AnalysisResultConstPtr ar,
const std::string &name,
const std::vector<std::string> &bases) const;
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_CONSTANT_TABLE_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -13,32 +13,32 @@
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "compiler/analysis/ast_walker.h"
#include "compiler/analysis/control_flow.h"
#include "compiler/analysis/data_flow.h"
#include "compiler/expression/expression.h"
#include "compiler/expression/binary_op_expression.h"
#include "compiler/expression/unary_op_expression.h"
#include "compiler/expression/qop_expression.h"
#include "compiler/statement/statement.h"
#include "compiler/statement/method_statement.h"
#include "compiler/statement/statement_list.h"
#include "compiler/statement/if_branch_statement.h"
#include "compiler/statement/for_statement.h"
#include "compiler/statement/while_statement.h"
#include "compiler/statement/do_statement.h"
#include "compiler/statement/foreach_statement.h"
#include "compiler/statement/switch_statement.h"
#include "compiler/statement/break_statement.h"
#include "compiler/statement/try_statement.h"
#include "compiler/statement/finally_statement.h"
#include "compiler/statement/label_statement.h"
#include "compiler/statement/goto_statement.h"
#include "compiler/statement/case_statement.h"
#include "hphp/compiler/analysis/control_flow.h"
#include <boost/graph/depth_first_search.hpp>
#include "hphp/compiler/analysis/ast_walker.h"
#include "hphp/compiler/analysis/data_flow.h"
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/binary_op_expression.h"
#include "hphp/compiler/expression/unary_op_expression.h"
#include "hphp/compiler/expression/qop_expression.h"
#include "hphp/compiler/statement/statement.h"
#include "hphp/compiler/statement/method_statement.h"
#include "hphp/compiler/statement/statement_list.h"
#include "hphp/compiler/statement/if_branch_statement.h"
#include "hphp/compiler/statement/for_statement.h"
#include "hphp/compiler/statement/while_statement.h"
#include "hphp/compiler/statement/do_statement.h"
#include "hphp/compiler/statement/foreach_statement.h"
#include "hphp/compiler/statement/switch_statement.h"
#include "hphp/compiler/statement/break_statement.h"
#include "hphp/compiler/statement/try_statement.h"
#include "hphp/compiler/statement/finally_statement.h"
#include "hphp/compiler/statement/label_statement.h"
#include "hphp/compiler/statement/goto_statement.h"
#include "hphp/compiler/statement/case_statement.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -128,7 +128,7 @@ private:
ControlFlowInfo *get(ConstructRawPtr cp) {
ConstructCFIMap::iterator it = m_ccfiMap.find(cp);
return it == m_ccfiMap.end() ? NULL : &it->second;
return it == m_ccfiMap.end() ? nullptr : &it->second;
}
ControlFlowInfo &cfi(ConstructRawPtr cp) {
@@ -182,7 +182,7 @@ public:
class dfs_dump : public boost::default_dfs_visitor {
public:
dfs_dump(AnalysisResultConstPtr ar) : m_ar(ar) {}
explicit dfs_dump(AnalysisResultConstPtr ar) : m_ar(ar) {}
void discover_vertex(ControlFlowGraph::vertex_descriptor u,
const ControlFlowGraph &g) {
@@ -329,9 +329,10 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
}
case Statement::KindOfForStatement: {
ConstructRawPtr cond(s->getNthKid(ForStatement::CondExpr));
ConstructRawPtr body(s->getNthKid(ForStatement::BodyStmt));
ConstructRawPtr incr(s->getNthKid(ForStatement::IncExpr));
ForStatementPtr fs(static_pointer_cast<ForStatement>(s));
ConstructRawPtr body(fs->getBody());
ConstructRawPtr cond(fs->getCondExp());
ConstructRawPtr incr(fs->getIncExp());
if (cond) addEdge(cond, AfterConstruct, s, AfterConstruct);
ConstructRawPtr end = incr ? incr : body ? body : cond;
ConstructRawPtr start = cond ? cond : body ? body : incr;
@@ -341,8 +342,9 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
}
case Statement::KindOfWhileStatement: {
ConstructRawPtr cond(s->getNthKid(WhileStatement::CondExpr));
ConstructRawPtr body(s->getNthKid(WhileStatement::BodyStmt));
WhileStatementPtr ws(static_pointer_cast<WhileStatement>(s));
ConstructRawPtr body(ws->getBody());
ConstructRawPtr cond(ws->getCondExp());
addEdge(cond, AfterConstruct, s, AfterConstruct);
addEdge(body ? body : cond, AfterConstruct, cond, BeforeConstruct);
noFallThrough(s);
@@ -350,15 +352,16 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
}
case Statement::KindOfDoStatement: {
ConstructRawPtr cond(s->getNthKid(DoStatement::CondExpr));
addEdge(cond, AfterConstruct, s, BeforeConstruct);
DoStatementPtr ds(static_pointer_cast<DoStatement>(s));
addEdge(ds->getCondExp(), AfterConstruct, s, BeforeConstruct);
break;
}
case Statement::KindOfForEachStatement: {
ConstructRawPtr body(s->getNthKid(ForEachStatement::BodyStmt));
ConstructRawPtr name(s->getNthKid(ForEachStatement::NameExpr));
ConstructRawPtr value(s->getNthKid(ForEachStatement::ValueExpr));
ForEachStatementPtr fs(static_pointer_cast<ForEachStatement>(s));
ConstructRawPtr body(fs->getBody());
ConstructRawPtr name(fs->getNameExp());
ConstructRawPtr value(fs->getValueExp());
ConstructRawPtr begin = name ? name : value;
ConstructRawPtr end = body ? body : value;
addEdge(end, AfterConstruct, begin, BeforeConstruct);
@@ -450,23 +453,31 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
} else {
ConstructRawPtr kid;
switch (l->getKindOf()) {
case Statement::KindOfForEachStatement:
kid = l->getNthKid(ForEachStatement::NameExpr);
case Statement::KindOfForEachStatement: {
ForEachStatementPtr fs(static_pointer_cast<ForEachStatement>(l));
kid = fs->getNameExp();
if (!kid) {
kid = l->getNthKid(ForEachStatement::ValueExpr);
kid = fs->getValueExp();
}
break;
case Statement::KindOfForStatement:
kid = l->getNthKid(ForStatement::IncExpr);
if (!kid) kid = l->getNthKid(ForStatement::CondExpr);
if (!kid) kid = l->getNthKid(ForStatement::BodyStmt);
}
case Statement::KindOfForStatement: {
ForStatementPtr fs(static_pointer_cast<ForStatement>(l));
kid = fs->getIncExp();
if (!kid) kid = fs->getCondExp();
if (!kid) kid = fs->getBody();
break;
case Statement::KindOfWhileStatement:
kid = l->getNthKid(WhileStatement::CondExpr);
}
case Statement::KindOfWhileStatement: {
WhileStatementPtr ws(static_pointer_cast<WhileStatement>(l));
kid = ws->getCondExp();
break;
case Statement::KindOfDoStatement:
kid = l->getNthKid(DoStatement::CondExpr);
}
case Statement::KindOfDoStatement: {
DoStatementPtr ds(static_pointer_cast<DoStatement>(l));
kid = ds->getCondExp();
break;
}
default:
always_assert(0);
}
@@ -487,6 +498,7 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
}
case Statement::KindOfEchoStatement:
case Statement::KindOfTypedefStatement:
break;
default:
@@ -495,36 +507,36 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
} else {
ExpressionPtr e(dynamic_pointer_cast<Expression>(cp));
switch (e->getKindOf()) {
case Expression::KindOfBinaryOpExpression:
{
BinaryOpExpressionPtr b(
static_pointer_cast<BinaryOpExpression>(e));
if (b->isShortCircuitOperator()) {
ConstructPtr trueBranch, falseBranch;
ConstructLocation tLoc, fLoc;
getTrueFalseBranches(0, trueBranch, tLoc, falseBranch, fLoc);
assert(trueBranch);
assert(falseBranch);
if (b->isLogicalOrOperator()) {
addEdge(e->getNthExpr(0), AfterConstruct, trueBranch, tLoc);
} else {
addEdge(e->getNthExpr(0), AfterConstruct, falseBranch, fLoc);
}
case Expression::KindOfBinaryOpExpression: {
BinaryOpExpressionPtr b(static_pointer_cast<BinaryOpExpression>(e));
if (b->isShortCircuitOperator()) {
ConstructPtr trueBranch, falseBranch;
ConstructLocation tLoc, fLoc;
getTrueFalseBranches(0, trueBranch, tLoc, falseBranch, fLoc);
assert(trueBranch);
assert(falseBranch);
if (b->isLogicalOrOperator()) {
addEdge(b->getExp1(), AfterConstruct, trueBranch, tLoc);
} else {
addEdge(b->getExp1(), AfterConstruct, falseBranch, fLoc);
}
}
break;
case Expression::KindOfQOpExpression:
if (ExpressionPtr e1 = e->getNthExpr(1)) {
addEdge(e->getNthExpr(0), AfterConstruct,
e->getNthExpr(2), BeforeConstruct);
}
case Expression::KindOfQOpExpression: {
QOpExpressionPtr q(static_pointer_cast<QOpExpression>(e));
if (ExpressionPtr e1 = q->getYes()) {
addEdge(q->getCondition(), AfterConstruct,
q->getNo(), BeforeConstruct);
addEdge(e1, AfterConstruct,
e->getNthExpr(2), AfterConstruct);
q->getNo(), AfterConstruct);
noFallThrough(e1);
} else {
addEdge(e->getNthExpr(0), AfterConstruct,
e->getNthExpr(2), AfterConstruct);
addEdge(q->getCondition(), AfterConstruct,
q->getNo(), AfterConstruct);
}
break;
}
default:
break;
}
@@ -586,32 +598,36 @@ void ControlFlowBuilder::getTrueFalseBranches(
ConstructPtr c(top(level));
if (StatementPtr s = dynamic_pointer_cast<Statement>(c)) {
int kidBodyIdx = -1;
StatementPtr kidBody;
switch (s->getKindOf()) {
case Statement::KindOfForStatement:
case Statement::KindOfForStatement: {
// examine which context we're in
{
ConstructPtr kid(top(level - 1));
if (kid == s->getNthKid(ForStatement::InitExpr)) {
; // just do the default case
} else if (kid == s->getNthKid(ForStatement::CondExpr)) {
kidBodyIdx = ForStatement::BodyStmt;
goto loop_stmt;
} else if (kid == s->getNthKid(ForStatement::IncExpr)) {
; // just do the default case
} else {
assert(false);
}
ForStatementPtr fs(static_pointer_cast<ForStatement>(s));
ConstructPtr kid(top(level - 1));
if (kid == fs->getInitExp()) {
; // just do the default case
} else if (kid == fs->getCondExp()) {
kidBody = fs->getBody();
goto loop_stmt;
} else if (kid == fs->getIncExp()) {
; // just do the default case
} else {
assert(false);
}
break;
case Statement::KindOfWhileStatement:
kidBodyIdx = WhileStatement::BodyStmt;
}
case Statement::KindOfWhileStatement: {
WhileStatementPtr ws(static_pointer_cast<WhileStatement>(s));
kidBody = ws->getBody();
goto loop_stmt;
case Statement::KindOfDoStatement:
kidBodyIdx = DoStatement::BodyStmt;
}
case Statement::KindOfDoStatement: {
DoStatementPtr ds(static_pointer_cast<DoStatement>(s));
kidBody = ds->getBody();
}
loop_stmt:
if (!trueBranch) {
trueBranch = s->getNthKid(kidBodyIdx);
trueBranch = kidBody;
tLoc = BeforeConstruct;
}
if (!falseBranch) {
@@ -852,7 +868,7 @@ ControlFlowGraph *ControlFlowGraph::buildControlFlow(MethodStatementPtr m) {
ControlFlowGraph *graph = new ControlFlowGraph;
graph->m_stmt = m;
ControlFlowBuilder cfb(graph, m->getOrigGeneratorFunc());
ControlFlowBuilder cfb(graph, !!m->getOrigGeneratorFunc());
cfb.run(m->getStmts());
graph->m_nextDfn = 1;
depth_first_visit(*graph, cfb.head(),
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,17 +14,17 @@
+----------------------------------------------------------------------+
*/
#ifndef __CONTROL_FLOW_H__
#define __CONTROL_FLOW_H__
#ifndef incl_HPHP_CONTROL_FLOW_H_
#define incl_HPHP_CONTROL_FLOW_H_
#include <boost/graph/properties.hpp>
#include <boost/graph/adjacency_iterator.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <compiler/hphp.h>
#include "hphp/compiler/hphp.h"
#include <compiler/analysis/ast_walker.h>
#include <compiler/analysis/bit_set_vec.h>
#include "hphp/compiler/analysis/ast_walker.h"
#include "hphp/compiler/analysis/bit_set_vec.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -65,6 +65,8 @@ struct graph_traits<HPHP::ControlFlowGraph> {
typedef int vertices_size_type;
typedef int edges_size_type;
typedef std::list<HPHP::ControlEdge*>::size_type degree_size_type;
static vertex_descriptor null_vertex() { return nullptr; }
};
template<>
@@ -309,7 +311,10 @@ inline void put(boost::vertex_color_t c,
class ControlFlowGraphWalker : public FunctionWalker {
public:
ControlFlowGraphWalker(ControlFlowGraph *g) : m_block(0), m_graph(*g) {}
explicit ControlFlowGraphWalker(ControlFlowGraph *g)
: m_block(0)
, m_graph(*g)
{}
template <class T>
void walk(T &t) {
std::pair<ControlFlowGraph::vertex_iterator,
@@ -333,4 +338,4 @@ protected:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __CONTROL_FLOW_H__
#endif // incl_HPHP_CONTROL_FLOW_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,12 +14,12 @@
+----------------------------------------------------------------------+
*/
#include "compiler/analysis/data_flow.h"
#include "hphp/compiler/analysis/data_flow.h"
#include "compiler/expression/expression.h"
#include "compiler/expression/simple_variable.h"
#include "compiler/expression/binary_op_expression.h"
#include "compiler/expression/list_assignment.h"
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/expression/binary_op_expression.h"
#include "hphp/compiler/expression/list_assignment.h"
using namespace HPHP;
using std::pair;
@@ -350,12 +350,13 @@ void DataFlowWalker::process(ExpressionPtr e, bool doAccessChains) {
case Expression::KindOfAssignmentExpression:
case Expression::KindOfBinaryOpExpression:
case Expression::KindOfUnaryOpExpression: {
ExpressionPtr var = e->getNthExpr(0);
ExpressionPtr var = e->getStoreVariable();
if (var && var->getContext() & (Expression::AssignmentLHS|
Expression::OprLValue)) {
processAccessChain(var);
processAccess(var);
}
// fall through
}
default:
processAccess(e);
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,11 +14,11 @@
+----------------------------------------------------------------------+
*/
#ifndef __DATA_FLOW_H__
#define __DATA_FLOW_H__
#ifndef incl_HPHP_DATA_FLOW_H_
#define incl_HPHP_DATA_FLOW_H_
#include <compiler/analysis/bit_set_vec.h>
#include <compiler/analysis/control_flow.h>
#include "hphp/compiler/analysis/bit_set_vec.h"
#include "hphp/compiler/analysis/control_flow.h"
namespace HPHP {
@@ -91,7 +91,7 @@ private:
class DataFlowWalker : public ControlFlowGraphWalker {
public:
DataFlowWalker(ControlFlowGraph *g) : ControlFlowGraphWalker(g) {}
explicit DataFlowWalker(ControlFlowGraph *g) : ControlFlowGraphWalker(g) {}
template<class T>
void walk(T &t) { ControlFlowGraphWalker::walk(t); }
@@ -107,4 +107,4 @@ public:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __DATA_FLOW_H__
#endif // incl_HPHP_DATA_FLOW_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,15 +14,15 @@
+----------------------------------------------------------------------+
*/
#ifndef __DEPTH_FIRST_VISITOR_H__
#define __DEPTH_FIRST_VISITOR_H__
#ifndef incl_HPHP_DEPTH_FIRST_VISITOR_H_
#define incl_HPHP_DEPTH_FIRST_VISITOR_H_
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/ast_walker.h>
#include <compiler/analysis/block_scope.h>
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/ast_walker.h"
#include "hphp/compiler/analysis/block_scope.h"
#include <compiler/expression/expression.h>
#include <compiler/statement/statement.h>
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/statement/statement.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -230,4 +230,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __DEPTH_FIRST_VISITOR_H__
#endif // incl_HPHP_DEPTH_FIRST_VISITOR_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,12 +14,12 @@
+----------------------------------------------------------------------+
*/
#include <compiler/analysis/alias_manager.h>
#include <compiler/analysis/dictionary.h>
#include <compiler/expression/expression.h>
#include <compiler/statement/statement.h>
#include <compiler/statement/method_statement.h>
#include <compiler/statement/statement_list.h>
#include "hphp/compiler/analysis/alias_manager.h"
#include "hphp/compiler/analysis/dictionary.h"
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/statement/statement.h"
#include "hphp/compiler/statement/method_statement.h"
#include "hphp/compiler/statement/statement_list.h"
using namespace HPHP;
using std::vector;
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,11 +14,11 @@
+----------------------------------------------------------------------+
*/
#ifndef __DICTIONARY_H__
#define __DICTIONARY_H__
#ifndef incl_HPHP_DICTIONARY_H_
#define incl_HPHP_DICTIONARY_H_
#include <compiler/hphp.h>
#include <compiler/analysis/data_flow.h>
#include "hphp/compiler/hphp.h"
#include "hphp/compiler/analysis/data_flow.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -32,7 +32,7 @@ class Dictionary {
public:
typedef std::vector<ExpressionPtr> IdMap;
Dictionary(AliasManager &am);
explicit Dictionary(AliasManager &am);
void build(MethodStatementPtr s);
void build(StatementPtr s);
void build(ExpressionPtr s);
@@ -78,4 +78,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __DICTIONARY_H__
#endif // incl_HPHP_DICTIONARY_H_
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,18 +14,19 @@
+----------------------------------------------------------------------+
*/
#ifndef __COMPILER_EMITTER_H__
#define __COMPILER_EMITTER_H__
#ifndef incl_HPHP_COMPILER_EMITTER_H_
#define incl_HPHP_COMPILER_EMITTER_H_
#include <compiler/expression/expression.h>
#include <compiler/statement/statement.h>
#include <compiler/statement/use_trait_statement.h>
#include <compiler/statement/trait_prec_statement.h>
#include <compiler/statement/trait_alias_statement.h>
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/statement/statement.h"
#include "hphp/compiler/statement/use_trait_statement.h"
#include "hphp/compiler/statement/trait_prec_statement.h"
#include "hphp/compiler/statement/trait_alias_statement.h"
#include "hphp/compiler/statement/typedef_statement.h"
#include <runtime/vm/func.h>
#include <runtime/vm/unit.h>
#include <util/hash.h>
#include "hphp/runtime/vm/func.h"
#include "hphp/runtime/vm/unit.h"
#include "hphp/util/hash.h"
namespace HPHP {
@@ -40,20 +41,12 @@ DECLARE_BOOST_TYPES(SimpleFunctionCall);
DECLARE_BOOST_TYPES(SwitchStatement);
DECLARE_BOOST_TYPES(ForEachStatement);
class StaticClassName;
class HhbcExtFuncInfo;
class HhbcExtClassInfo;
namespace Compiler {
///////////////////////////////////////////////////////////////////////////////
using VM::Offset;
using VM::Func;
using VM::Class;
using VM::Unit;
using VM::InvalidAbsoluteOffset;
using VM::Opcode;
using VM::Id;
using namespace VM;
// Forward declarations.
class Label;
class EmitterVisitor;
@@ -96,6 +89,12 @@ public:
Id str;
Label* dest;
};
struct IterPair {
IterPair(IterKind k, Id i) : kind(k), id(i) {}
IterKind kind;
Id id;
};
#define O(name, imm, pop, push, flags) \
void name(imm);
#define NA
@@ -110,10 +109,11 @@ public:
#define MA std::vector<uchar>
#define BLA std::vector<Label*>&
#define SLA std::vector<StrOff>&
#define IVA int32
#define HA int32
#define IA int32
#define I64A int64
#define ILA std::vector<IterPair>&
#define IVA int32_t
#define HA int32_t
#define IA int32_t
#define I64A int64_t
#define DA double
#define SA const StringData*
#define AA ArrayData*
@@ -129,6 +129,7 @@ public:
#undef MA
#undef BLA
#undef SLA
#undef ILA
#undef IVA
#undef HA
#undef IA
@@ -200,7 +201,7 @@ private:
DataType dt; // META_DATA_TYPE
} metaData;
const StringData* className;
int64 intval; // used for L and I symbolic flavors
int64_t intval; // used for L and I symbolic flavors
// If intval is an unnamed local temporary, this offset is the start
// of the region we are using it (which we will need to have a
@@ -237,7 +238,7 @@ public:
std::string pretty() const;
void push(char sym);
void setInt(int64 v);
void setInt(int64_t v);
void setString(const StringData* s);
void setKnownCls(const StringData* s, bool nonNull);
void setNotRef();
@@ -274,7 +275,7 @@ public:
ClassBaseType getClsBaseType(int index) const;
int getLoc(int index) const;
int64 getInt(int index) const;
int64_t getInt(int index) const;
Offset getUnnamedLocStart(int index) const;
void pushFDesc();
@@ -284,7 +285,7 @@ public:
class Label {
public:
Label() : m_off(InvalidAbsoluteOffset) {}
Label(Emitter& e) : m_off(InvalidAbsoluteOffset) {
explicit Label(Emitter& e) : m_off(InvalidAbsoluteOffset) {
set(e);
}
Offset getAbsoluteOffset() const { return m_off; }
@@ -323,7 +324,7 @@ public:
class EmitterVisitor {
friend class UnsetUnnamedLocalThunklet;
public:
EmitterVisitor(UnitEmitter& ue);
explicit EmitterVisitor(UnitEmitter& ue);
~EmitterVisitor();
bool visit(ConstructPtr c);
@@ -332,7 +333,7 @@ public:
void visit(FileScopePtr file);
void assignLocalVariableIds(FunctionScopePtr fs);
void fixReturnType(Emitter& e, FunctionCallPtr fn,
bool isBuiltinCall = false);
Func* builtinFunc = nullptr);
typedef std::vector<int> IndexChain;
void visitListAssignmentLHS(Emitter& e, ExpressionPtr exp,
IndexChain& indexChain,
@@ -347,9 +348,10 @@ public:
}
bool evalStackIsUnknown() { return m_evalStackIsUnknown; }
void popEvalStack(char symFlavor, int arg = -1, int pos = -1);
void popSymbolicLocal(Opcode opcode, int arg = -1, int pos = -1);
void popSymbolicLocal(Op opcode, int arg = -1, int pos = -1);
void popEvalStackLMany();
void popEvalStackMany(int len, char symFlavor);
void popEvalStackCVMany(int len);
void pushEvalStack(char symFlavor);
void peekEvalStack(char symFlavor, int depthActual);
void pokeEvalStack(char symFlavor, int depthActual);
@@ -359,9 +361,10 @@ public:
recordJumpTarget(target, m_evalStack);
}
void restoreJumpTargetEvalStack();
void recordCall();
bool isJumpTarget(Offset target);
void setPrevOpcode(Opcode op) { m_prevOpcode = op; }
Opcode getPrevOpcode() const { return m_prevOpcode; }
void setPrevOpcode(Op op) { m_prevOpcode = op; }
Op getPrevOpcode() const { return m_prevOpcode; }
bool currentPositionIsReachable() {
return (m_ue.bcPos() == m_curFunc->base()
|| isJumpTarget(m_ue.bcPos())
@@ -379,12 +382,19 @@ public:
EXCEPTION_COMMON_IMPL(IncludeTimeFatalException);
};
void pushIterId(Id id) { m_pendingIters.push_back(id); }
void popIterId() { m_pendingIters.pop_back(); }
void pushIterScope(Id id, IterKind kind) {
m_pendingIters.emplace_back(id, kind);
}
void popIterScope() { m_pendingIters.pop_back(); }
private:
typedef std::pair<StringData*, bool> ClosureUseVar; // (name, byRef)
typedef std::vector<ClosureUseVar> ClosureUseVarVec;
typedef std::vector<Id> IdVec;
typedef std::vector<std::pair<Id,IterKind> > PendingIterVec;
typedef std::pair<StringData*, ExpressionPtr> NonScalarPair;
typedef std::vector<NonScalarPair> NonScalarVec;
typedef std::pair<Id, int> StrCase;
class PostponedMeth {
public:
PostponedMeth(MethodStatementPtr m, FuncEmitter* fe, bool top,
@@ -395,6 +405,7 @@ private:
bool m_top;
ClosureUseVarVec* m_closureUseVars;
};
class PostponedCtor {
public:
PostponedCtor(InterfaceStatementPtr is, FuncEmitter* fe)
@@ -402,8 +413,7 @@ private:
InterfaceStatementPtr m_is;
FuncEmitter* m_fe;
};
typedef std::pair<StringData*, ExpressionPtr> NonScalarPair;
typedef std::vector<NonScalarPair> NonScalarVec;
class PostponedNonScalars {
public:
PostponedNonScalars(InterfaceStatementPtr is, FuncEmitter* fe,
@@ -416,6 +426,7 @@ private:
FuncEmitter* m_fe;
NonScalarVec* m_vec;
};
class PostponedClosureCtor {
public:
PostponedClosureCtor(ClosureUseVarVec& v, ClosureExpressionPtr e,
@@ -425,30 +436,32 @@ private:
ClosureExpressionPtr m_expr;
FuncEmitter* m_fe;
};
class ControlTargets {
public:
ControlTargets(Id itId, Label& brkTarg, Label& cntTarg, Label& brkHand,
Label& cntHand) : m_itId(itId), m_brkTarg(brkTarg), m_cntTarg(cntTarg),
m_brkHand(brkHand), m_cntHand(cntHand) {}
ControlTargets(Id itId, bool itRef, Label& brkTarg, Label& cntTarg)
: m_itId(itId), m_itRef(itRef), m_brkTarg(brkTarg), m_cntTarg(cntTarg)
{}
Id m_itId;
bool m_itRef;
Label& m_brkTarg; // Jump here for "break;" (after doing IterFree)
Label& m_cntTarg; // Jump here for "continue;"
Label& m_brkHand; // Push N and jump here for "break N;"
Label& m_cntHand; // Push N and jump here for "continue N;"
};
class ControlTargetPusher {
public:
ControlTargetPusher(EmitterVisitor* e, Id itId, Label& brkTarg,
Label& cntTarg, Label& brkHand, Label& cntHand) : m_e(e) {
e->m_contTargets.push_front(ControlTargets(itId, brkTarg, cntTarg,
brkHand, cntHand));
ControlTargetPusher(EmitterVisitor* e, Id itId, bool itRef, Label& brkTarg,
Label& cntTarg) : m_e(e) {
e->m_controlTargets.push_front(ControlTargets(itId, itRef, brkTarg,
cntTarg));
}
~ControlTargetPusher() {
m_e->m_contTargets.pop_front();
m_e->m_controlTargets.pop_front();
}
private:
EmitterVisitor* m_e;
};
class ExnHandlerRegion {
public:
ExnHandlerRegion(Offset start, Offset end) : m_start(start),
@@ -464,15 +477,23 @@ private:
std::set<StringData*, string_data_lt> m_names;
std::vector<std::pair<StringData*, Label*> > m_catchLabels;
};
class FaultRegion {
public:
FaultRegion(Offset start, Offset end, Id iterId)
: m_start(start), m_end(end), m_iterId(iterId) {}
FaultRegion(Offset start, Offset end, Id iterId, IterKind kind)
: m_start(start)
, m_end(end)
, m_iterId(iterId)
, m_iterKind(kind)
{}
Offset m_start;
Offset m_end;
Id m_iterId;
Label m_func;
IterKind m_iterKind;
Label m_func; // note: a pointer to this is handed out to the Funclet
};
class FPIRegion {
public:
FPIRegion(Offset start, Offset end, Offset fpOff)
@@ -481,10 +502,10 @@ private:
Offset m_end;
Offset m_fpOff;
};
typedef std::pair<Id, int> StrCase;
struct SwitchState : private boost::noncopyable {
SwitchState() : nonZeroI(-1), defI(-1) {}
std::map<int64, int> cases; // a map from int (or litstr id) to case index
std::map<int64_t, int> cases; // a map from int (or litstr id) to case index
std::vector<StrCase> caseOrder; // for string switches, a list of the
// <litstr id, case index> in the order
// they appear in the source
@@ -492,12 +513,16 @@ private:
int defI;
};
private:
void emitFatal(Emitter& e, const char* message);
private:
static const size_t kMinStringSwitchCases = 8;
UnitEmitter& m_ue;
FuncEmitter* m_curFunc;
FileScopePtr m_file;
Opcode m_prevOpcode;
Op m_prevOpcode;
std::deque<PostponedMeth> m_postponedMeths;
std::deque<PostponedCtor> m_postponedCtors;
@@ -505,16 +530,18 @@ private:
std::deque<PostponedNonScalars> m_postponedSinits;
std::deque<PostponedNonScalars> m_postponedCinits;
std::deque<PostponedClosureCtor> m_postponedClosureCtors;
IdVec m_pendingIters;
typedef std::map<const StringData*, Label*, string_data_lt> LabelMap;
LabelMap m_methLabels;
PendingIterVec m_pendingIters;
hphp_hash_set<std::string> m_generatorEmitted;
hphp_hash_set<std::string> m_topMethodEmitted;
SymbolicStack m_evalStack;
bool m_evalStackIsUnknown;
hphp_hash_map<Offset, SymbolicStack> m_jumpTargetEvalStacks;
int m_actualStackHighWater;
int m_fdescHighWater;
int m_closureCounter; // used to uniquify closures' mangled names
std::deque<ControlTargets> m_contTargets;
typedef tbb::concurrent_hash_map<const StringData*, int,
StringDataHashCompare> EmittedClosures;
static EmittedClosures s_emittedClosures;
std::deque<ControlTargets> m_controlTargets;
std::deque<Funclet> m_funclets;
std::deque<ExnHandlerRegion*> m_exnHandlers;
std::deque<FaultRegion*> m_faultRegions;
@@ -523,11 +550,9 @@ private:
std::set<std::string,stdltistr> m_hoistables;
LocationPtr m_tempLoc;
std::map<StringData*, Label, string_data_lt> m_gotoLabels;
std::vector<Label> m_yieldLabels;
MetaInfoBuilder m_metaInfo;
public:
Label& topBreakHandler() { return m_contTargets.front().m_brkHand; }
Label& topContHandler() { return m_contTargets.front().m_cntHand; }
bool checkIfStackEmpty(const char* forInstruction) const;
void unexpectedStackSym(char sym, const char* where) const;
@@ -535,6 +560,12 @@ public:
void buildVectorImm(std::vector<uchar>& vectorImm,
int iFirst, int iLast, bool allowW,
Emitter& e);
enum class PassByRefKind {
AllowCell,
WarnOnCell,
ErrorOnCell,
};
PassByRefKind getPassByRefKind(ExpressionPtr exp);
void emitAGet(Emitter& e);
void emitCGetL2(Emitter& e);
void emitCGetL3(Emitter& e);
@@ -549,7 +580,8 @@ public:
void emitIsDouble(Emitter& e);
void emitIsBool(Emitter& e);
void emitEmpty(Emitter& e);
void emitUnset(Emitter& e);
void emitUnset(Emitter& e, ExpressionPtr exp = ExpressionPtr());
void emitVisitAndUnset(Emitter& e, ExpressionPtr exp);
void emitSet(Emitter& e);
void emitSetOp(Emitter& e, int op);
void emitBind(Emitter& e);
@@ -561,12 +593,14 @@ public:
void emitConvertToCellOrLoc(Emitter& e);
void emitConvertSecondToCell(Emitter& e);
void emitConvertToVar(Emitter& e);
void emitFPass(Emitter& e, int paramID, PassByRefKind passByRefKind);
void emitVirtualLocal(int localId, DataType dt = KindOfUnknown);
template<class Expr> void emitVirtualClassBase(Emitter&, Expr* node);
void emitResolveClsBase(Emitter& e, int pos);
void emitClsIfSPropBase(Emitter& e);
Label* getContinuationGotoLabel(StatementPtr s);
void emitContinuationSwitch(Emitter& e, SwitchStatementPtr s);
Id emitVisitAndSetUnnamedL(Emitter& e, ExpressionPtr exp);
void emitPushAndFreeUnnamedL(Emitter& e, Id tempLocal, Offset start);
void emitContinuationSwitch(Emitter& e, int ncase);
DataType analyzeSwitch(SwitchStatementPtr s, SwitchState& state);
void emitIntegerSwitch(Emitter& e, SwitchStatementPtr s,
std::vector<Label>& caseLabels, Label& done,
@@ -574,6 +608,7 @@ public:
void emitStringSwitch(Emitter& e, SwitchStatementPtr s,
std::vector<Label>& caseLabels, Label& done,
const SwitchState& state);
void emitIterBreak(Emitter& e, uint64_t n, Label& targ);
void markElem(Emitter& e);
void markNewElem(Emitter& e);
@@ -587,7 +622,7 @@ public:
void emitAssignment(Emitter& e, ExpressionPtr c, int op, bool bind);
void emitListAssignment(Emitter& e, ListAssignmentPtr lst);
void postponeMeth(MethodStatementPtr m, FuncEmitter* fe, bool top,
ClosureUseVarVec* useVars = NULL);
ClosureUseVarVec* useVars = nullptr);
void postponeCtor(InterfaceStatementPtr m, FuncEmitter* fe);
void postponePinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
void postponeSinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
@@ -612,8 +647,7 @@ public:
};
bool emitCallUserFunc(Emitter& e, SimpleFunctionCallPtr node);
bool canEmitBuiltinCall(FunctionCallPtr fn, const std::string& name,
int numParams);
Func* canEmitBuiltinCall(const std::string& name, int numParams);
void emitFuncCall(Emitter& e, FunctionCallPtr node);
void emitFuncCallArg(Emitter& e, ExpressionPtr exp, int paramId);
void emitBuiltinCallArg(Emitter& e, ExpressionPtr exp, int paramId,
@@ -621,23 +655,29 @@ public:
void emitBuiltinDefaultArg(Emitter& e, Variant& v, DataType t, int paramId);
PreClass::Hoistable emitClass(Emitter& e, ClassScopePtr cNode,
bool topLevel);
void emitBreakHandler(Emitter& e, Label& brkTarg, Label& cntTarg,
Label& brkHand, Label& cntHand, Id iter = -1);
void emitTypedef(Emitter& e, TypedefStatementPtr);
void emitForeach(Emitter& e, ForEachStatementPtr fe);
void emitRestoreErrorReporting(Emitter& e, Id oldLevelLoc);
void emitMakeUnitFatal(Emitter& e, const std::string& message);
void addFunclet(Thunklet* body, Label* entry);
void emitFunclets(Emitter& e);
void newFaultRegion(Offset start, Offset end, Thunklet* t, Id iter = -1);
struct FaultIterInfo {
Id iterId;
IterKind kind;
};
void newFaultRegion(Offset start, Offset end, Thunklet* t,
FaultIterInfo = FaultIterInfo { -1, KindOfIter });
void newFPIRegion(Offset start, Offset end, Offset fpOff);
void copyOverExnHandlers(FuncEmitter* fe);
void copyOverFPIRegions(FuncEmitter* fe);
void saveMaxStackCells(FuncEmitter* fe);
void finishFunc(Emitter& e, FuncEmitter* fe);
StringData* newClosureName();
void initScalar(TypedValue& tvVal, ExpressionPtr val);
bool requiresDeepInit(ExpressionPtr initExpr) const;
void emitClassTraitPrecRule(PreClassEmitter* pce, TraitPrecStatementPtr rule);
void emitClassTraitAliasRule(PreClassEmitter* pce,
@@ -660,4 +700,4 @@ extern "C" {
}
}
#endif // __COMPILER_EMITTER_H__
#endif // incl_HPHP_COMPILER_EMITTER_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,14 +14,14 @@
+----------------------------------------------------------------------+
*/
#include <compiler/analysis/alias_manager.h>
#include <compiler/analysis/expr_dict.h>
#include "hphp/compiler/analysis/expr_dict.h"
#include "hphp/compiler/analysis/alias_manager.h"
#include <compiler/expression/expression.h>
#include <compiler/expression/assignment_expression.h>
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/assignment_expression.h"
#include <compiler/statement/statement.h>
#include <compiler/statement/method_statement.h>
#include "hphp/compiler/statement/statement.h"
#include "hphp/compiler/statement/method_statement.h"
using namespace HPHP;
using std::vector;
@@ -59,7 +59,7 @@ void ExprDict::getTypes(ExpressionPtr e, TypePtrIdxPairVec &types) {
class TypeFunc { public:
bool operator()(const TypePtrIdxPair& entry) const {
return entry.first;
return entry.first != nullptr;
}
};
static TypeFunc s_type_func;
@@ -313,7 +313,7 @@ void ExprDict::updateAccess(ExpressionPtr e) {
BitOps::set_bit(aid, m_altered, true);
}
if (!(cls & Expression::Store) ||
a != e->getNthExpr(0)) {
a != e->getStoreVariable()) {
a->clearAvailable();
m_avlAccess[i] = m_avlAccess[--n];
m_avlAccess.resize(n);
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __EXPR_DICT_H__
#define __EXPR_DICT_H__
#ifndef incl_HPHP_EXPR_DICT_H_
#define incl_HPHP_EXPR_DICT_H_
#include <compiler/analysis/dictionary.h>
#include "hphp/compiler/analysis/dictionary.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -27,7 +27,7 @@ typedef std::vector<TypePtrIdxPair> TypePtrIdxPairVec;
class ExprDict : public Dictionary {
public:
ExprDict(AliasManager &am);
explicit ExprDict(AliasManager &am);
/* Building the dictionary */
void build(MethodStatementPtr m);
void visit(ExpressionPtr e);
@@ -43,8 +43,8 @@ public:
TypePtr propagateType(ExpressionPtr e);
void getTypes(ExpressionPtr e, TypePtrIdxPairVec &types);
private:
private:
/**
* types is filled with (type assertion, canon id for that type assertion)
* tuples
@@ -94,4 +94,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __EXPR_DICT_H__
#endif // incl_HPHP_EXPR_DICT_H_
+495
Ver Arquivo
@@ -0,0 +1,495 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/statement/statement_list.h"
#include "hphp/compiler/statement/exp_statement.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/analysis/constant_table.h"
#include "hphp/compiler/analysis/function_scope.h"
#include <sys/stat.h>
#include "hphp/compiler/parser/parser.h"
#include "hphp/util/logger.h"
#include "hphp/util/util.h"
#include "hphp/util/base.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/statement/function_statement.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/expression/simple_function_call.h"
#include "hphp/compiler/expression/include_expression.h"
#include "hphp/compiler/expression/user_attribute.h"
#include "hphp/runtime/base/complex_types.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
FileScope::FileScope(const string &fileName, int fileSize, const MD5 &md5)
: BlockScope("", "", StatementPtr(), BlockScope::FileScope),
m_size(fileSize), m_md5(md5), m_module(false), m_privateInclude(false),
m_externInclude(false),
m_includeState(0), m_fileName(fileName), m_redeclaredFunctions(0) {
pushAttribute(); // for global scope
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
void FileScope::setFileLevel(StatementListPtr stmtList) {
for (int i = 0; i < stmtList->getCount(); i++) {
StatementPtr stmt = (*stmtList)[i];
stmt->setFileLevel();
if (stmt->is(Statement::KindOfExpStatement)) {
ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt);
ExpressionPtr exp = expStmt->getExpression();
exp->setFileLevel();
}
if (stmt->is(Statement::KindOfStatementList)) {
setFileLevel(dynamic_pointer_cast<StatementList>(stmt));
}
}
}
FunctionScopePtr FileScope::setTree(AnalysisResultConstPtr ar,
StatementListPtr tree) {
m_tree = tree;
setFileLevel(tree);
return createPseudoMain(ar);
}
void FileScope::cleanupForError(AnalysisResultConstPtr ar,
int line, const string &msg) {
for (StringToClassScopePtrVecMap::const_iterator iter = m_classes.begin();
iter != m_classes.end(); ++iter) {
BOOST_FOREACH(ClassScopePtr cls, iter->second) {
cls->getVariables()->cleanupForError(ar);
}
}
getConstants()->cleanupForError(ar);
StringToFunctionScopePtrMap().swap(m_functions);
delete m_redeclaredFunctions;
m_redeclaredFunctions = 0;
StringToClassScopePtrVecMap().swap(m_classes);
m_pseudoMain.reset();
m_tree.reset();
LocationPtr loc(new Location());
loc->file = m_fileName.c_str();
loc->first(line, 0);
loc->last(line, 0);
BlockScopePtr scope;
ExpressionListPtr args(new ExpressionList(scope, loc));
args->addElement(Expression::MakeScalarExpression(ar, scope, loc, msg));
SimpleFunctionCallPtr e(
new SimpleFunctionCall(scope, loc, "throw_fatal", false, args,
ExpressionPtr()));
e->setThrowFatal();
ExpStatementPtr exp(new ExpStatement(scope, loc, e));
StatementListPtr stmts(new StatementList(scope, loc));
stmts->addElement(exp);
FunctionScopePtr fs = setTree(ar, stmts);
fs->setOuterScope(shared_from_this());
fs->getStmt()->resetScope(fs);
fs->getStmt()->setLocation(loc);
setOuterScope(const_cast<AnalysisResult*>(ar.get())->shared_from_this());
}
bool FileScope::addFunction(AnalysisResultConstPtr ar,
FunctionScopePtr funcScope) {
if (ar->declareFunction(funcScope)) {
FunctionScopePtr &fs = m_functions[funcScope->getName()];
if (fs) {
if (!m_redeclaredFunctions) {
m_redeclaredFunctions = new StringToFunctionScopePtrVecMap;
}
FunctionScopePtrVec &funcVec =
(*m_redeclaredFunctions)[funcScope->getName()];
if (!funcVec.size()) {
fs->setLocalRedeclaring();
funcVec.push_back(fs);
}
funcScope->setLocalRedeclaring();
funcVec.push_back(funcScope);
} else {
fs = funcScope;
}
return true;
}
return false;
}
bool FileScope::addClass(AnalysisResultConstPtr ar, ClassScopePtr classScope) {
if (ar->declareClass(classScope)) {
m_classes[classScope->getName()].push_back(classScope);
return true;
}
return false;
}
ClassScopePtr FileScope::getClass(const char *name) {
StringToClassScopePtrVecMap::const_iterator iter = m_classes.find(name);
if (iter == m_classes.end()) return ClassScopePtr();
return iter->second.back();
}
int FileScope::getFunctionCount() const {
int total = FunctionContainer::getFunctionCount();
for (StringToClassScopePtrVecMap::const_iterator iter = m_classes.begin();
iter != m_classes.end(); ++iter) {
BOOST_FOREACH(ClassScopePtr cls, iter->second) {
total += cls->getFunctionCount();
}
}
return total;
}
void FileScope::countReturnTypes(std::map<std::string, int> &counts) {
FunctionContainer::countReturnTypes(counts, m_redeclaredFunctions);
for (StringToClassScopePtrVecMap::const_iterator iter = m_classes.begin();
iter != m_classes.end(); ++iter) {
BOOST_FOREACH(ClassScopePtr cls, iter->second) {
cls->countReturnTypes(counts, 0);
}
}
}
void FileScope::pushAttribute() {
m_attributes.push_back(0);
}
void FileScope::setAttribute(Attribute attr) {
assert(!m_attributes.empty());
m_attributes.back() |= attr;
}
int FileScope::popAttribute() {
assert(!m_attributes.empty());
int ret = m_attributes.back();
m_attributes.pop_back();
return ret;
}
int FileScope::getGlobalAttribute() const {
assert(m_attributes.size() == 1);
return m_attributes.back();
}
bool FileScope::needPseudoMainVariables() const {
VariableTablePtr variables = m_pseudoMain->getVariables();
return
variables->getAttribute(VariableTable::ContainsDynamicVariable) ||
variables->getSymbols().size() > 0;
}
///////////////////////////////////////////////////////////////////////////////
ExpressionPtr FileScope::getEffectiveImpl(AnalysisResultConstPtr ar) const {
if (m_tree) return m_tree->getEffectiveImpl(ar);
return ExpressionPtr();
}
///////////////////////////////////////////////////////////////////////////////
void FileScope::declareConstant(AnalysisResultPtr ar, const string &name) {
if (!ar->declareConst(shared_from_this(), name)) {
addConstantDependency(ar, name);
}
}
void FileScope::addConstant(const string &name, TypePtr type,
ExpressionPtr value,
AnalysisResultPtr ar, ConstructPtr con) {
BlockScopePtr f = ar->findConstantDeclarer(name);
f->getConstants()->add(name, type, value, ar, con);
}
void FileScope::addIncludeDependency(AnalysisResultPtr ar,
const string &file, bool byInlined) {
ar->addIncludeDependency(shared_from_this(), file);
}
void FileScope::addClassDependency(AnalysisResultPtr ar,
const string &classname) {
ar->addClassDependency(shared_from_this(), classname);
}
void FileScope::addFunctionDependency(AnalysisResultPtr ar,
const string &funcname, bool byInlined) {
ar->addFunctionDependency(shared_from_this(), funcname);
}
void FileScope::addConstantDependency(AnalysisResultPtr ar,
const string &decname) {
ar->addConstantDependency(shared_from_this(), decname);
}
void FileScope::analyzeProgram(AnalysisResultPtr ar) {
if (m_pseudoMain) {
m_pseudoMain->getStmt()->analyzeProgram(ar);
}
}
ClassScopeRawPtr FileScope::resolveClass(ClassScopeRawPtr cls) {
BlockScopeSet::iterator it = m_providedDefs.find(cls);
if (it != m_providedDefs.end()) {
return ClassScopeRawPtr(static_cast<HPHP::ClassScope*>(it->get()));
}
return ClassScopeRawPtr();
}
bool FileScope::checkClass(const string &cls) {
return m_redecBases.find(cls) != m_redecBases.end();
}
FunctionScopeRawPtr FileScope::resolveFunction(FunctionScopeRawPtr func) {
BlockScopeSet::iterator it = m_providedDefs.find(func);
if (it != m_providedDefs.end()) {
return FunctionScopeRawPtr(static_cast<HPHP::FunctionScope*>(it->get()));
}
return FunctionScopeRawPtr();
}
/*
* Insert the class, and its parents (recursively) into m_providedDefs,
* returning true if the class was already known to exist.
* If def is true, this is the actual definition for the class,
* so set the hasBase flags.
*/
bool FileScope::insertClassUtil(AnalysisResultPtr ar,
ClassScopeRawPtr cls, bool def) {
if (!m_providedDefs.insert(cls).second) return true;
const vector<string> &bases = cls->getBases();
bool topBasesKnown = def && bases.size() > 31;
for (unsigned i = 0; i < bases.size(); i++) {
const string &s = bases[i];
ClassScopeRawPtr c = ar->findClass(s);
if (c) {
if (c->isRedeclaring()) {
ClassScopeRawPtr cr = resolveClass(c);
if (!cr) {
if (i >= 31) topBasesKnown = false;
m_redecBases.insert(c->getName());
continue;
}
c = cr;
} else if (!c->isVolatile()) {
if (def && i < 31) cls->setKnownBase(i);
continue;
}
if (insertClassUtil(ar, c, false)) {
if (def && i < 31) cls->setKnownBase(i);
} else {
if (i >= 31) topBasesKnown = false;
}
}
}
if (topBasesKnown) cls->setKnownBase(31);
return false;
}
void FileScope::analyzeIncludesHelper(AnalysisResultPtr ar) {
m_includeState = 1;
if (m_pseudoMain) {
StatementList &stmts = *getStmt();
bool hoistOnly = false;
for (int i = 0, n = stmts.getCount(); i < n; i++) {
StatementPtr s = stmts[i];
if (!s) continue;
if (s->is(Statement::KindOfClassStatement) ||
s->is(Statement::KindOfInterfaceStatement)) {
ClassScopeRawPtr cls(
static_pointer_cast<InterfaceStatement>(s)->getClassScope());
if (hoistOnly) {
const string &parent = cls->getOriginalParent();
if (cls->getBases().size() > (parent.empty() ? 0 : 1)) {
continue;
}
if (!parent.empty()) {
ClassScopeRawPtr c = ar->findClass(parent);
if (!c || (c->isVolatile() &&
!resolveClass(c) && !checkClass(parent))) {
continue;
}
}
}
if (cls->isVolatile()) {
insertClassUtil(ar, cls, true);
}
continue;
}
if (s->is(Statement::KindOfFunctionStatement)) {
FunctionScopeRawPtr func(
static_pointer_cast<FunctionStatement>(s)->getFunctionScope());
if (func->isVolatile()) m_providedDefs.insert(func);
continue;
}
if (!hoistOnly && s->is(Statement::KindOfExpStatement)) {
ExpressionRawPtr exp(
static_pointer_cast<ExpStatement>(s)->getExpression());
if (exp && exp->is(Expression::KindOfIncludeExpression)) {
FileScopeRawPtr fs(
static_pointer_cast<IncludeExpression>(exp)->getIncludedFile(ar));
if (fs && fs->m_includeState != 1) {
if (!fs->m_includeState) {
if (m_module && fs->m_privateInclude) {
BOOST_FOREACH(BlockScopeRawPtr bs, m_providedDefs) {
fs->m_providedDefs.insert(bs);
}
}
fs->analyzeIncludesHelper(ar);
}
BOOST_FOREACH(BlockScopeRawPtr bs, fs->m_providedDefs) {
m_providedDefs.insert(bs);
}
continue;
}
}
}
hoistOnly = true;
}
}
m_includeState = 2;
}
void FileScope::analyzeIncludes(AnalysisResultPtr ar) {
if (!m_privateInclude && !m_includeState) {
analyzeIncludesHelper(ar);
}
}
void FileScope::visit(AnalysisResultPtr ar,
void (*cb)(AnalysisResultPtr, StatementPtr, void*),
void *data)
{
if (m_pseudoMain) {
cb(ar, m_pseudoMain->getStmt(), data);
}
}
const string &FileScope::pseudoMainName() {
if (m_pseudoMainName.empty()) {
m_pseudoMainName = Option::MangleFilename(m_fileName, true);
}
return m_pseudoMainName;
}
FunctionScopePtr FileScope::createPseudoMain(AnalysisResultConstPtr ar) {
StatementListPtr st = m_tree;
FunctionStatementPtr f
(new FunctionStatement(BlockScopePtr(), LocationPtr(),
ModifierExpressionPtr(),
false, pseudoMainName(),
ExpressionListPtr(), "", st, 0, "",
ExpressionListPtr()));
f->setFileLevel();
FunctionScopePtr pseudoMain(
new HPHP::FunctionScope(ar, true,
pseudoMainName().c_str(),
f, false, 0, 0,
ModifierExpressionPtr(),
m_attributes[0], "",
shared_from_this(),
vector<UserAttributePtr>(),
true));
f->setBlockScope(pseudoMain);
FunctionScopePtr &fs = m_functions[pseudoMainName()];
always_assert(!fs);
fs = pseudoMain;
m_pseudoMain = pseudoMain;
return pseudoMain;
}
string FileScope::outputFilebase() const {
string file = m_fileName;
string out;
if (file.size() > 4 && file.substr(file.length() - 4) == ".php") {
out = file.substr(0, file.length() - 4);
} else {
out = file + ".nophp";
}
return Option::MangleFilename(out, false);
}
static void getFuncScopesSet(BlockScopeRawPtrQueue &v,
const StringToFunctionScopePtrMap &funcMap) {
for (StringToFunctionScopePtrMap::const_iterator
iter = funcMap.begin(), end = funcMap.end();
iter != end; ++iter) {
FunctionScopePtr f = iter->second;
if (f->isUserFunction()) {
v.push_back(f);
}
}
}
void FileScope::getScopesSet(BlockScopeRawPtrQueue &v) {
const StringToClassScopePtrVecMap &classes = getClasses();
for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin(),
end = classes.end(); iter != end; ++iter) {
for (ClassScopePtrVec::const_iterator it = iter->second.begin(),
e = iter->second.end(); it != e; ++it) {
ClassScopePtr cls = *it;
if (cls->isUserClass()) {
v.push_back(cls);
getFuncScopesSet(v, cls->getFunctions());
}
}
}
getFuncScopesSet(v, getFunctions());
if (const StringToFunctionScopePtrVecMap *redec = m_redeclaredFunctions) {
for (StringToFunctionScopePtrVecMap::const_iterator iter = redec->begin(),
end = redec->end(); iter != end; ++iter) {
FunctionScopePtrVec::const_iterator i = iter->second.begin(),
e = iter->second.end();
v.insert(v.end(), ++i, e);
}
}
}
void FileScope::getClassesFlattened(ClassScopePtrVec &classes) const {
for (StringToClassScopePtrVecMap::const_iterator it = m_classes.begin();
it != m_classes.end(); ++it) {
BOOST_FOREACH(ClassScopePtr cls, it->second) {
classes.push_back(cls);
}
}
}
void FileScope::serialize(JSON::DocTarget::OutputStream &out) const {
JSON::DocTarget::MapStream ms(out);
ms.add("name", getName());
ClassScopePtrVec classes;
getClassesFlattened(classes);
ms.add("classes", classes);
FunctionScopePtrVec funcs;
getFunctionsFlattened(m_redeclaredFunctions, funcs, true);
ms.add("functions", funcs);
// TODO(stephentu): constants
ms.done();
}
+239
Ver Arquivo
@@ -0,0 +1,239 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_FILE_SCOPE_H_
#define incl_HPHP_FILE_SCOPE_H_
#include <map>
#include "hphp/compiler/analysis/block_scope.h"
#include "hphp/compiler/analysis/function_container.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/code_generator.h"
#include <boost/graph/adjacency_list.hpp>
#include "hphp/util/json.h"
#include "hphp/runtime/base/md5.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class CodeGenerator;
DECLARE_BOOST_TYPES(StatementList);
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(Location);
DECLARE_BOOST_TYPES(FileScope);
DECLARE_BOOST_TYPES(FunctionScope);
/**
* A FileScope stores what's parsed from one single source file. It's up to
* AnalysisResult objects to grab statements, functions and classes from
* FileScope objects to form execution paths.
*/
class FileScope : public BlockScope,
public FunctionContainer,
public JSON::DocTarget::ISerializable {
public:
enum Attribute {
ContainsDynamicVariable = 0x001,
ContainsLDynamicVariable = 0x002,
VariableArgument = 0x004,
ContainsExtract = 0x008, // contains call to extract()
ContainsCompact = 0x010, // contains call to compact()
ContainsReference = 0x020, // returns ref or has ref parameters
ReferenceVariableArgument = 0x040, // like sscanf or fscanf
ContainsUnset = 0x080, // need special handling
NoEffect = 0x100, // does not side effect
HelperFunction = 0x200, // runtime helper function
ContainsGetDefinedVars = 0x400, // need VariableTable with getDefinedVars
MixedVariableArgument = 0x800, // variable args, may or may not be ref'd
IsFoldable = 0x1000,// function can be constant folded
NeedsActRec = 0x2000,// builtin function needs ActRec
AllowOverride = 0x4000,// allow override of systemlib or builtin
};
typedef boost::adjacency_list<boost::setS, boost::vecS> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
public:
FileScope(const std::string &fileName, int fileSize, const MD5 &md5);
~FileScope() { delete m_redeclaredFunctions; }
int getSize() const { return m_size;}
// implementing FunctionContainer
virtual std::string getParentName() const { assert(false); return "";}
const std::string &getName() const { return m_fileName;}
const MD5& getMd5() const { return m_md5; }
StatementListPtr getStmt() const { return m_tree;}
const StringToClassScopePtrVecMap &getClasses() const {
return m_classes;
}
void getClassesFlattened(ClassScopePtrVec &classes) const;
ClassScopePtr getClass(const char *name);
void getScopesSet(BlockScopeRawPtrQueue &v);
int getFunctionCount() const;
void countReturnTypes(std::map<std::string, int> &counts);
int getClassCount() const { return m_classes.size();}
void pushAttribute();
void setAttribute(Attribute attr);
int getGlobalAttribute() const;
int popAttribute();
void serialize(JSON::DocTarget::OutputStream &out) const;
/**
* Whether this file has top level non-declaration statements that
* have CPP implementation.
*/
ExpressionPtr getEffectiveImpl(AnalysisResultConstPtr ar) const;
/**
* Parser functions. Parser only deals with a FileScope object, and these
* are the only functions a parser calls upon analysis results.
*/
FunctionScopePtr setTree(AnalysisResultConstPtr ar, StatementListPtr tree);
void cleanupForError(AnalysisResultConstPtr ar,
int line, const std::string &msg);
bool addFunction(AnalysisResultConstPtr ar, FunctionScopePtr funcScope);
bool addClass(AnalysisResultConstPtr ar, ClassScopePtr classScope);
const StringToFunctionScopePtrVecMap *getRedecFunctions() {
return m_redeclaredFunctions;
}
/**
* For separate compilation
* These add edges between filescopes in the other dep graph and
* save the symbols for our iface.
* This stuff only happens in the filechanged state.
*/
void addConstant(const std::string &name, TypePtr type, ExpressionPtr value,
AnalysisResultPtr ar, ConstructPtr con);
void declareConstant(AnalysisResultPtr ar, const std::string &name);
void getConstantNames(std::vector<std::string> &names);
TypePtr getConstantType(const std::string &name);
void addIncludeDependency(AnalysisResultPtr ar, const std::string &file,
bool byInlined);
void addClassDependency(AnalysisResultPtr ar,
const std::string &classname);
void addFunctionDependency(AnalysisResultPtr ar,
const std::string &funcname, bool byInlined);
void addConstantDependency(AnalysisResultPtr ar,
const std::string &decname);
void addClassAlias(const std::string& target, const std::string& alias) {
m_classAliasMap.insert(std::make_pair(target, alias));
}
std::multimap<std::string,std::string> const& getClassAliases() const {
return m_classAliasMap;
}
void addTypeAliasName(const std::string& name) {
m_typeAliasNames.insert(name);
}
std::set<std::string> const& getTypeAliasNames() const {
return m_typeAliasNames;
}
/**
* Called only by World
*/
vertex_descriptor vertex() { return m_vertex; }
void setVertex(vertex_descriptor vertex) {
m_vertex = vertex;
}
void setModule() { m_module = true; }
void setPrivateInclude() { m_privateInclude = true; }
bool isPrivateInclude() const { return m_privateInclude && !m_externInclude; }
void setExternInclude() { m_externInclude = true; }
void analyzeProgram(AnalysisResultPtr ar);
void analyzeIncludes(AnalysisResultPtr ar);
void analyzeIncludesHelper(AnalysisResultPtr ar);
bool insertClassUtil(AnalysisResultPtr ar, ClassScopeRawPtr cls, bool def);
bool checkClass(const std::string &cls);
ClassScopeRawPtr resolveClass(ClassScopeRawPtr cls);
FunctionScopeRawPtr resolveFunction(FunctionScopeRawPtr func);
void visit(AnalysisResultPtr ar,
void (*cb)(AnalysisResultPtr, StatementPtr, void*),
void *data);
const std::string &pseudoMainName();
void outputFileCPP(AnalysisResultPtr ar, CodeGenerator &cg);
bool load();
bool needPseudoMainVariables() const;
std::string outputFilebase() const;
void addPseudoMainVariable(const std::string &name) {
m_pseudoMainVariables.insert(name);
}
std::set<std::string> &getPseudoMainVariables() {
return m_pseudoMainVariables;
}
FunctionScopeRawPtr getPseudoMain() const {
return m_pseudoMain;
}
FileScopePtr shared_from_this() {
return boost::static_pointer_cast<FileScope>
(BlockScope::shared_from_this());
}
private:
int m_size;
MD5 m_md5;
unsigned m_module : 1;
unsigned m_privateInclude : 1;
unsigned m_externInclude : 1;
unsigned m_includeState : 2;
std::vector<int> m_attributes;
std::string m_fileName;
StatementListPtr m_tree;
StringToFunctionScopePtrVecMap *m_redeclaredFunctions;
StringToClassScopePtrVecMap m_classes; // name => class
FunctionScopeRawPtr m_pseudoMain;
vertex_descriptor m_vertex;
std::string m_pseudoMainName;
std::set<std::string> m_pseudoMainVariables;
BlockScopeSet m_providedDefs;
std::set<std::string> m_redecBases;
// Map from class alias names to the class they are aliased to.
// This is only needed in WholeProgram mode.
std::multimap<std::string,std::string> m_classAliasMap;
// Set of names that are on the left hand side of type alias
// declarations. We need this to make sure we don't mark classes
// with the same name Unique.
std::set<std::string> m_typeAliasNames;
FunctionScopePtr createPseudoMain(AnalysisResultConstPtr ar);
void setFileLevel(StatementListPtr stmt);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_FILE_SCOPE_H_
@@ -0,0 +1,80 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/analysis/function_container.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/statement/statement_list.h"
#include "hphp/compiler/option.h"
#include "hphp/util/util.h"
#include "hphp/util/hash.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
FunctionContainer::FunctionContainer() {
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
void FunctionContainer::countReturnTypes(
std::map<std::string, int> &counts,
const StringToFunctionScopePtrVecMap *redec) {
for (StringToFunctionScopePtrMap::const_iterator iter =
m_functions.begin(); iter != m_functions.end(); ++iter) {
FunctionScopePtr f = iter->second;
if (f->isLocalRedeclaring()) {
always_assert(redec);
BOOST_FOREACH(f, redec->find(iter->first)->second) {
TypePtr type = f->getReturnType();
if (type) {
type->count(counts);
}
}
} else {
TypePtr type = f->getReturnType();
if (type) {
type->count(counts);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void FunctionContainer::getFunctionsFlattened(
const StringToFunctionScopePtrVecMap *redec,
FunctionScopePtrVec &funcs,
bool excludePseudoMains /* = false */) const {
for (StringToFunctionScopePtrMap::const_iterator it = m_functions.begin();
it != m_functions.end(); ++it) {
FunctionScopePtr func = it->second;
if (!excludePseudoMains || !func->inPseudoMain()) {
if (func->isLocalRedeclaring()) {
const FunctionScopePtrVec &r = redec->find(it->first)->second;
funcs.insert(funcs.end(), r.begin(), r.end());
} else {
funcs.push_back(func);
}
}
}
}
+59
Ver Arquivo
@@ -0,0 +1,59 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_FUNCTION_CONTAINER_H_
#define incl_HPHP_FUNCTION_CONTAINER_H_
#include "hphp/compiler/hphp.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class CodeGenerator;
DECLARE_BOOST_TYPES(AnalysisResult);
DECLARE_BOOST_TYPES(FunctionScope);
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(FunctionContainer);
/**
* Base class of both FileScope and ClassScope that can contain functions.
*/
class FunctionContainer {
public:
FunctionContainer();
/**
* Functions this container has.
*/
int getFunctionCount() const { return m_functions.size(); }
void countReturnTypes(std::map<std::string, int> &counts,
const StringToFunctionScopePtrVecMap *redec);
const StringToFunctionScopePtrMap &getFunctions() const {
return m_functions;
}
void getFunctionsFlattened(const StringToFunctionScopePtrVecMap *redec,
FunctionScopePtrVec &funcs,
bool excludePseudoMains = false) const;
protected:
// name => functions. Order of declaration
StringToFunctionScopePtrMap m_functions;
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_FUNCTION_CONTAINER_H_
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+497
Ver Arquivo
@@ -0,0 +1,497 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_FUNCTION_SCOPE_H_
#define incl_HPHP_FUNCTION_SCOPE_H_
#include "hphp/compiler/expression/user_attribute.h"
#include "hphp/compiler/analysis/block_scope.h"
#include "hphp/compiler/option.h"
#include "hphp/util/json.h"
#include "hphp/util/parser/parser.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
DECLARE_BOOST_TYPES(Type);
DECLARE_BOOST_TYPES(Construct);
DECLARE_BOOST_TYPES(ExpressionList);
DECLARE_BOOST_TYPES(FileScope);
DECLARE_BOOST_TYPES(AnalysisResult);
DECLARE_BOOST_TYPES(FunctionScope);
DECLARE_BOOST_TYPES(Expression);
DECLARE_BOOST_TYPES(SimpleFunctionCall);
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(ParameterExpression);
DECLARE_BOOST_TYPES(MethodStatement);
class CodeGenerator;
typedef ExpressionPtr (*FunctionOptPtr)(CodeGenerator *cg,
AnalysisResultConstPtr ar,
SimpleFunctionCallPtr, int);
typedef std::pair< ParameterExpressionPtr, int >
ParameterExpressionPtrIdxPair;
typedef std::vector< ParameterExpressionPtrIdxPair >
ParameterExpressionPtrIdxPairVec;
/**
* A FunctionScope corresponds to a function declaration. We store all
* inferred types and analyzed results here, so not to pollute syntax trees.
*/
class FunctionScope : public BlockScope,
public JSON::CodeError::ISerializable,
public JSON::DocTarget::ISerializable {
public:
/**
* User defined functions.
*/
FunctionScope(AnalysisResultConstPtr ar, bool method,
const std::string &name, StatementPtr stmt,
bool reference, int minParam, int maxParam,
ModifierExpressionPtr modifiers, int attribute,
const std::string &docComment,
FileScopePtr file,
const std::vector<UserAttributePtr> &attrs,
bool inPseudoMain = false);
FunctionScope(FunctionScopePtr orig, AnalysisResultConstPtr ar,
const std::string &name, const std::string &originalName,
StatementPtr stmt, ModifierExpressionPtr modifiers);
/**
* System functions.
*/
FunctionScope(bool method, const std::string &name, bool reference);
void setParamCounts(AnalysisResultConstPtr ar, int minParam, int maxParam);
void setParamSpecs(AnalysisResultPtr ar);
void setParamName(int index, const std::string &name);
void setParamDefault(int index, const char* value, int64_t len,
const std::string &text);
CStrRef getParamDefault(int index);
void setRefParam(int index);
bool hasRefParam(int max) const;
void addModifier(int mod);
/**
* What kind of function this is.
*/
bool isUserFunction() const { return !m_system;}
bool isDynamic() const { return m_dynamic; }
bool isPublic() const;
bool isProtected() const;
bool isPrivate() const;
bool isStatic() const;
bool isAbstract() const;
bool isFinal() const;
bool isMagic() const;
bool isRefParam(int index) const;
bool isRefReturn() const { return m_refReturn;}
bool isDynamicInvoke() const { return m_dynamicInvoke; }
void setDynamicInvoke();
bool hasImpl() const;
void setDirectInvoke() { m_directInvoke = true; }
bool hasDirectInvoke() const { return m_directInvoke; }
bool mayContainThis();
bool isClosure() const;
bool isGenerator() const;
bool isGeneratorFromClosure() const;
int allocYieldLabel() { return ++m_yieldLabelCount; }
int getYieldLabelCount() const { return m_yieldLabelCount; }
bool hasGeneratorAsBody() const;
MethodStatementRawPtr getOrigGenStmt() const;
FunctionScopeRawPtr getOrigGenFS() const;
void setClosureGenerator() { m_closureGenerator = true; }
bool isClosureGenerator() const {
assert(!m_closureGenerator || isClosure());
return m_closureGenerator;
}
bool needsClassParam();
void setInlineSameContext(bool f) { m_inlineSameContext = f; }
bool getInlineSameContext() const { return m_inlineSameContext; }
void setContextSensitive(bool f) { m_contextSensitive = f; }
bool getContextSensitive() const { return m_contextSensitive; }
void setInlineAsExpr(bool f) { m_inlineAsExpr = f; }
bool getInlineAsExpr() const { return m_inlineAsExpr; }
int nextInlineIndex() { return ++m_inlineIndex; }
bool usesLSB() const { return !m_noLSB; }
void clearUsesLSB() { m_noLSB = true; }
bool nextLSB() const { return m_nextLSB; }
void setNextLSB(bool f) { m_nextLSB = f; }
void setHasGoto() { m_hasGoto = true; }
void setHasTry() { m_hasTry = true; }
bool hasGoto() const { return m_hasGoto; }
bool hasTry() const { return m_hasTry; }
unsigned getNewID() { return m_nextID++; }
bool needsLocalThis() const;
/**
* Either __construct or a class-name constructor.
*/
bool isConstructor(ClassScopePtr cls) const;
const std::string &getParamName(int index) const;
const std::string &name() const {
return getName();
}
virtual std::string getId() const;
std::string getInjectionId() const;
int getRedeclaringId() const {
return m_redeclaring;
}
void setDynamic() {
m_dynamic = true;
}
void setSystem() {
m_system = true;
m_volatile = false;
}
/**
* Tell this function about another outer scope that contains it.
*/
void addClonedTraitOuterScope(FunctionScopePtr scope) {
m_clonedTraitOuterScope.push_back(scope);
}
/**
* Get/set original name of the function, without case being lowered.
*/
const std::string &getOriginalName() const;
void setOriginalName(const std::string &name) { m_originalName = name; }
std::string getDocName() const;
std::string getDocFullName() const;
/**
* If class method, returns class::name, otherwise just name.
*/
std::string getFullName() const;
std::string getOriginalFullName() const;
/**
* Whether this function can take variable number of arguments.
*/
bool isVariableArgument() const;
bool isReferenceVariableArgument() const;
void setVariableArgument(int reference);
bool isMixedVariableArgument() const;
/**
* Whether this function has no side effects
*/
bool hasEffect() const;
void setNoEffect();
/**
* Whether this function can be constant folded
*/
bool isFoldable() const;
void setIsFoldable();
/*
* If this is a builtin function and does not need an ActRec
*/
bool needsActRec() const;
void setNeedsActRec();
/*
* If this is a builtin (C++ or PHP) and can be redefined
*/
bool allowOverride() const;
void setAllowOverride();
/**
* Whether this function is a runtime helper function
*/
void setHelperFunction();
/**
* Whether this function returns reference or has reference parameters.
*/
bool containsReference() const;
/**
* Whether this function contains a usage of $this
*/
bool containsThis() const { return m_containsThis;}
void setContainsThis(bool f = true);
bool containsBareThis() const { return m_containsBareThis; }
bool containsRefThis() const { return m_containsBareThis & 2; }
void setContainsBareThis(bool f, bool ref = false);
/**
* How many parameters a caller should provide.
*/
int getMinParamCount() const { return m_minParam;}
int getMaxParamCount() const { return m_maxParam;}
int getOptionalParamCount() const { return m_maxParam - m_minParam;}
/**
* What is the inferred type of this function's return.
*/
void pushReturnType();
void setReturnType(AnalysisResultConstPtr ar, TypePtr type);
TypePtr getReturnType() const {
return m_prevReturn ? m_prevReturn : m_returnType;
}
bool popReturnType();
void resetReturnType();
void addRetExprToFix(ExpressionPtr e);
void clearRetExprs();
void fixRetExprs();
void setOptFunction(FunctionOptPtr fn) { m_optFunction = fn; }
FunctionOptPtr getOptFunction() const { return m_optFunction; }
/**
* Whether this is a virtual function that needs to go through invoke().
* A perfect virtual will be generated as C++ virtual function without
* going through invoke(), but rather directly generated as obj->foo().
* "Overriding" is only being used by magic methods, enforcing parameter
* and return types.
*/
void setVirtual() { m_virtual = true;}
bool isVirtual() const { return m_virtual;}
void setHasOverride() { m_hasOverride = true; }
bool hasOverride() const { return m_hasOverride; }
void setPerfectVirtual();
bool isPerfectVirtual() const { return m_perfectVirtual;}
void setOverriding(TypePtr returnType, TypePtr param1 = TypePtr(),
TypePtr param2 = TypePtr());
bool isOverriding() const { return m_overriding;}
/**
* Whether same function name was declared twice or more.
*/
void setRedeclaring(int redecId) {
m_redeclaring = redecId;
setVolatile(); // redeclared function is also volatile
}
bool isRedeclaring() const { return m_redeclaring >= 0;}
void setLocalRedeclaring() { m_localRedeclaring = true; }
bool isLocalRedeclaring() const { return m_localRedeclaring; }
/* For function_exists */
void setVolatile() { m_volatile = true; }
bool isVolatile() const { return m_volatile; }
bool isPersistent() const { return m_persistent; }
void setPersistent(bool p) { m_persistent = p; }
bool isInlined() const { return m_inlineable; }
void disableInline() { m_inlineable = false; }
/* Whether this function is brought in by a separable extension */
void setSepExtension() { m_sep = true;}
bool isSepExtension() const { return m_sep;}
/* Whether we need to worry about the named return value optimization
for this function */
void setNRVOFix(bool flag) { m_nrvoFix = flag; }
bool getNRVOFix() const { return m_nrvoFix; }
/* Indicates if a function may need to use a VarEnv or varargs (aka
* extraArgs) at run time */
bool mayUseVV() const;
/**
* Whether this function matches the specified one with same number of
* parameters and types and defaults, so to qualify for perfect virtuals.
*/
bool matchParams(FunctionScopePtr func);
/**
* What is the inferred type of this function's parameter at specified
* index. Returns number of extra arguments to put into ArgumentArray.
*/
int inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp,
ExpressionListPtr params, bool &valid);
TypePtr setParamType(AnalysisResultConstPtr ar, int index, TypePtr type);
TypePtr getParamType(int index);
TypePtr getParamTypeSpec(int index) { return m_paramTypeSpecs[index]; }
typedef hphp_hash_map<std::string, ExpressionPtr, string_hashi,
string_eqstri> UserAttributeMap;
UserAttributeMap& userAttributes() { return m_userAttributes;}
/**
* Override BlockScope::outputPHP() to generate return type.
*/
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* Serialize the iface, not everything.
*/
void serialize(JSON::CodeError::OutputStream &out) const;
void serialize(JSON::DocTarget::OutputStream &out) const;
bool inPseudoMain() const {
return m_pseudoMain;
}
void setMagicMethod() {
m_magicMethod = true;
}
bool isMagicMethod() const {
return m_magicMethod;
}
void setStmtCloned(StatementPtr stmt) {
m_stmtCloned = stmt;
}
void setClosureVars(ExpressionListPtr closureVars) {
m_closureVars = closureVars;
}
ExpressionListPtr getClosureVars() const {
return m_closureVars;
}
void getClosureUseVars(ParameterExpressionPtrIdxPairVec &useVars,
bool filterUsed = true);
bool needsAnonClosureClass(ParameterExpressionPtrVec &useVars);
bool needsAnonClosureClass(ParameterExpressionPtrIdxPairVec &useVars);
void addCaller(BlockScopePtr caller, bool careAboutReturn = true);
void addNewObjCaller(BlockScopePtr caller);
ReadWriteMutex &getInlineMutex() { return m_inlineMutex; }
DECLARE_BOOST_TYPES(FunctionInfo);
static void RecordFunctionInfo(std::string fname, FunctionScopePtr func);
static FunctionInfoPtr GetFunctionInfo(std::string fname);
class FunctionInfo {
public:
explicit FunctionInfo(int rva = -1)
: m_maybeStatic(false)
, m_maybeRefReturn(false)
, m_refVarArg(rva)
{}
bool isRefParam(int p) const {
if (m_refVarArg >= 0 && p >= m_refVarArg) return true;
return (m_refParams.find(p) != m_refParams.end());
}
void setRefVarArg(int rva) {
if (rva > m_refVarArg) m_refVarArg = rva;
}
void setRefParam(int p) {
m_refParams.insert(p);
}
void setMaybeStatic() { m_maybeStatic = true; }
bool getMaybeStatic() { return m_maybeStatic; }
void setMaybeRefReturn() { m_maybeRefReturn = true; }
bool getMaybeRefReturn() { return m_maybeRefReturn; }
private:
bool m_maybeStatic; // this could be a static method
bool m_maybeRefReturn;
int m_refVarArg; // -1: no ref varargs;
// otherwise, any arg >= m_refVarArg is a reference
std::set<int> m_refParams; // set of ref arg positions
};
private:
void init(AnalysisResultConstPtr ar);
static StringToFunctionInfoPtrMap s_refParamInfo;
int m_minParam;
int m_maxParam;
int m_attribute;
std::vector<std::string> m_paramNames;
TypePtrVec m_paramTypes;
TypePtrVec m_paramTypeSpecs;
std::vector<String> m_paramDefaults;
std::vector<std::string> m_paramDefaultTexts;
std::vector<bool> m_refs;
TypePtr m_returnType;
TypePtr m_prevReturn;
ModifierExpressionPtr m_modifiers;
UserAttributeMap m_userAttributes;
unsigned m_hasVoid : 1;
unsigned m_method : 1;
unsigned m_refReturn : 1; // whether it's "function &get_reference()"
unsigned m_virtual : 1;
unsigned m_hasOverride : 1;
unsigned m_perfectVirtual : 1;
unsigned m_dynamic : 1;
unsigned m_dynamicInvoke : 1;
unsigned m_overriding : 1; // overriding a virtual function
unsigned m_volatile : 1; // for function_exists
unsigned m_persistent : 1;
unsigned m_pseudoMain : 1;
unsigned m_magicMethod : 1;
unsigned m_system : 1;
unsigned m_inlineable : 1;
unsigned m_sep : 1;
unsigned m_containsThis : 1; // contains a usage of $this?
unsigned m_containsBareThis : 2; // $this outside object-context,
// 2 if in reference context
unsigned m_nrvoFix : 1;
unsigned m_inlineAsExpr : 1;
unsigned m_inlineSameContext : 1;
unsigned m_contextSensitive : 1;
unsigned m_directInvoke : 1;
unsigned m_closureGenerator : 1;
unsigned m_noLSB : 1;
unsigned m_nextLSB : 1;
unsigned m_hasTry : 1;
unsigned m_hasGoto : 1;
unsigned m_localRedeclaring : 1;
int m_redeclaring; // multiple definition of the same function
StatementPtr m_stmtCloned; // cloned method body stmt
int m_inlineIndex;
FunctionOptPtr m_optFunction;
ExpressionPtrVec m_retExprsToFix;
ExpressionListPtr m_closureVars;
ExpressionListPtr m_closureValues;
ReadWriteMutex m_inlineMutex;
unsigned m_nextID; // used when cloning generators for traits
int m_yieldLabelCount; // number of allocated yield labels
std::list<FunctionScopeRawPtr> m_clonedTraitOuterScope;
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_FUNCTION_SCOPE_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,20 +14,20 @@
+----------------------------------------------------------------------+
*/
#include <compiler/analysis/alias_manager.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/analysis/live_dict.h>
#include <compiler/analysis/variable_table.h>
#include "hphp/compiler/analysis/alias_manager.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/live_dict.h"
#include "hphp/compiler/analysis/variable_table.h"
#include <compiler/expression/expression.h>
#include <compiler/expression/assignment_expression.h>
#include <compiler/expression/simple_variable.h>
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/assignment_expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include <compiler/statement/statement.h>
#include <compiler/statement/block_statement.h>
#include <compiler/statement/exp_statement.h>
#include <compiler/statement/method_statement.h>
#include <compiler/statement/statement_list.h>
#include "hphp/compiler/statement/statement.h"
#include "hphp/compiler/statement/block_statement.h"
#include "hphp/compiler/statement/exp_statement.h"
#include "hphp/compiler/statement/method_statement.h"
#include "hphp/compiler/statement/statement_list.h"
using namespace HPHP;
using std::vector;
@@ -326,10 +326,10 @@ void LiveDict::updateAccess(ExpressionPtr e) {
}
struct Colorizer {
Colorizer(int w) : toNode(w) {}
explicit Colorizer(int w) : toNode(w) {}
struct NodeInfo {
NodeInfo(int index) : originalIndex(index), size(0), color(-1) {}
explicit NodeInfo(int index) : originalIndex(index), size(0), color(-1) {}
int originalIndex;
int size;
int color;
@@ -359,7 +359,7 @@ struct Colorizer {
class NodeCmp {
public:
NodeCmp(const Colorizer *c) : m_c(c) {}
explicit NodeCmp(const Colorizer *c) : m_c(c) {}
bool operator()(int a, int b) {
const NodeInfo &n1 = m_c->nodes[a];
const NodeInfo &n2 = m_c->nodes[b];
@@ -461,25 +461,11 @@ bool LiveDict::color(TypePtr type) {
if (Type::SameType(type, e->getCPPType())) {
SimpleVariablePtr sv(
static_pointer_cast<SimpleVariable>(e));
bool isGenParam = false;
if (sv->getFunctionScope()->isGenerator()) {
// do not allow coalescing of symbols which are parameters/use vars
// in the generator (sym->isParameter() will be false b/c we are in
// the scope of the generator function)
FunctionScopeRawPtr origScope(sv->getFunctionScope()->getOrigGenFS());
assert(origScope);
Symbol *origSym =
origScope->getVariables()->getSymbol(sv->getName());
if (origSym &&
(origSym->isParameter() || origSym->isClosureVar())) {
isGenParam = true;
}
}
Symbol *sym = sv->getSymbol();
if (sym &&
!sym->isGlobal() &&
!sym->isParameter() &&
!isGenParam &&
!sym->isGeneratorParameter() &&
!sym->isClosureVar() &&
!sym->isStatic() &&
!e->isThis()) {
@@ -623,9 +609,8 @@ public:
always_assert(e && e->is(Expression::KindOfSimpleVariable));
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
Symbol *sym = sv->getSymbol();
bool inGen = sv->getFunctionScope()->isGenerator();
if (!sym || sym->isGlobal() || sym->isStatic() || sym->isParameter() ||
sym->isClosureVar() || sv->isThis() || inGen) {
sym->isGeneratorParameter() || sym->isClosureVar() || sv->isThis()) {
continue;
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __LIVE_DICT_H__
#define __LIVE_DICT_H__
#ifndef incl_HPHP_LIVE_DICT_H_
#define incl_HPHP_LIVE_DICT_H_
#include <compiler/analysis/dictionary.h>
#include "hphp/compiler/analysis/dictionary.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -26,7 +26,7 @@ namespace HPHP {
class LiveDict : public Dictionary {
public:
LiveDict(AliasManager &am) : Dictionary(am) {}
explicit LiveDict(AliasManager &am) : Dictionary(am) {}
/* Building the dictionary */
void build(MethodStatementPtr m);
void visit(ExpressionPtr e);
@@ -53,4 +53,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __LIVE_DICT_H__
#endif // incl_HPHP_LIVE_DICT_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,18 +14,16 @@
+----------------------------------------------------------------------+
*/
#include "compiler/analysis/peephole.h"
#include "compiler/analysis/emitter.h"
#include "hphp/compiler/analysis/peephole.h"
#include "hphp/compiler/analysis/emitter.h"
#include "hphp/runtime/vm/preclass-emit.h"
namespace HPHP { namespace Compiler {
using VM::FuncEmitter;
using VM::UnitEmitter;
using VM::Offset;
static void collapseJmp(Offset* offsetPtr, Opcode* instr, Opcode* start) {
static void collapseJmp(Offset* offsetPtr, Op* instr, Op* start) {
if (offsetPtr) {
Opcode* dest = instr + *offsetPtr;
Op* dest = instr + *offsetPtr;
while (*dest == OpJmp && dest != instr) {
dest = start + instrJumpTarget(start, dest - start);
}
@@ -45,10 +43,10 @@ Peephole::Peephole(UnitEmitter &ue, MetaInfoBuilder& metaInfo)
buildJumpTargets();
// Scan the bytecode linearly.
Opcode* start = ue.m_bc;
Opcode* prev = start;
Opcode* cur = prev + instrLen(prev);
Opcode* end = start + ue.m_bclen;
Op* start = (Op*)ue.m_bc;
Op* prev = start;
Op* cur = prev + instrLen(prev);
Op* end = start + ue.m_bclen;
/*
* TODO(1086005): we should try to minimize use of CGetL2/CGetL3.
@@ -164,14 +162,19 @@ void Peephole::buildJumpTargets() {
}
// all jump targets are targets
for (Offset pos = 0; pos < (Offset)m_ue.m_bclen;
pos += instrLen(&m_ue.m_bc[pos])) {
Opcode* instr = &m_ue.m_bc[pos];
pos += instrLen((Op*)&m_ue.m_bc[pos])) {
Op* instr = (Op*)&m_ue.m_bc[pos];
if (isSwitch(*instr)) {
foreachSwitchTarget(instr, [&](Offset& o) {
m_jumpTargets.insert(pos + o);
});
} else if (*instr == OpIterBreak) {
uint32_t veclen = *(uint32_t *)(instr + 1);
assert(veclen > 0);
Offset target = *(Offset *)((uint32_t *)(instr + 1) + 2 * veclen + 1);
m_jumpTargets.insert(pos + target);
} else {
Offset target = instrJumpTarget(m_ue.m_bc, pos);
Offset target = instrJumpTarget((Op*)m_ue.m_bc, pos);
if (target != InvalidAbsoluteOffset) {
m_jumpTargets.insert(target);
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -34,8 +34,8 @@
#ifndef incl_HPHP_COMPILER_ANALYSIS_PEEPHOLE_H_
#define incl_HPHP_COMPILER_ANALYSIS_PEEPHOLE_H_
#include "runtime/vm/unit.h"
#include "runtime/vm/func.h"
#include "hphp/runtime/vm/unit.h"
#include "hphp/runtime/vm/func.h"
namespace HPHP { namespace Compiler {
@@ -43,14 +43,14 @@ class MetaInfoBuilder;
class Peephole {
public:
Peephole(VM::UnitEmitter& ue, MetaInfoBuilder& metaInfo);
Peephole(UnitEmitter& ue, MetaInfoBuilder& metaInfo);
private:
void buildFuncTargets(VM::FuncEmitter* fe);
void buildFuncTargets(FuncEmitter* fe);
void buildJumpTargets();
VM::UnitEmitter& m_ue;
hphp_hash_set<VM::Offset> m_jumpTargets;
UnitEmitter& m_ue;
hphp_hash_set<Offset> m_jumpTargets;
};
}}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,22 +14,22 @@
+----------------------------------------------------------------------+
*/
#include <compiler/analysis/alias_manager.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/analysis/ref_dict.h>
#include "hphp/compiler/analysis/alias_manager.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/ref_dict.h"
#include <compiler/expression/expression.h>
#include <compiler/expression/assignment_expression.h>
#include <compiler/expression/binary_op_expression.h>
#include <compiler/expression/simple_variable.h>
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/assignment_expression.h"
#include "hphp/compiler/expression/binary_op_expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include <compiler/statement/statement.h>
#include <compiler/statement/block_statement.h>
#include <compiler/statement/exp_statement.h>
#include <compiler/statement/method_statement.h>
#include <compiler/statement/statement_list.h>
#include "hphp/compiler/statement/statement.h"
#include "hphp/compiler/statement/block_statement.h"
#include "hphp/compiler/statement/exp_statement.h"
#include "hphp/compiler/statement/method_statement.h"
#include "hphp/compiler/statement/statement_list.h"
#include <util/parser/hphp.tab.hpp>
#include "hphp/util/parser/hphp.tab.hpp"
using namespace HPHP;
using std::vector;
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,17 +14,17 @@
+----------------------------------------------------------------------+
*/
#ifndef __REF_DICT_H__
#define __REF_DICT_H__
#ifndef incl_HPHP_REF_DICT_H_
#define incl_HPHP_REF_DICT_H_
#include <compiler/analysis/dictionary.h>
#include "hphp/compiler/analysis/dictionary.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class RefDict : public Dictionary {
public:
RefDict(AliasManager &am) : Dictionary(am), first_pass(true) {}
explicit RefDict(AliasManager &am) : Dictionary(am), first_pass(true) {}
/* Building the dictionary */
void build(MethodStatementPtr m);
@@ -52,7 +52,7 @@ private:
class RefDictWalker : public ControlFlowGraphWalker {
public:
RefDictWalker(ControlFlowGraph *g) :
explicit RefDictWalker(ControlFlowGraph *g) :
ControlFlowGraphWalker(g), first_pass(true) {}
void walk() { ControlFlowGraphWalker::walk(*this); }
int after(ConstructRawPtr cp);
@@ -63,4 +63,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __REF_DICT_H__
#endif // incl_HPHP_REF_DICT_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,23 +14,24 @@
+----------------------------------------------------------------------+
*/
#include <compiler/analysis/symbol_table.h>
#include <compiler/analysis/type.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/class_scope.h>
#include <compiler/analysis/file_scope.h>
#include <compiler/analysis/function_scope.h>
#include "hphp/compiler/analysis/symbol_table.h"
#include "hphp/compiler/analysis/type.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/function_scope.h"
#include <compiler/expression/constant_expression.h>
#include <compiler/expression/expression_list.h>
#include <compiler/expression/parameter_expression.h>
#include <compiler/expression/simple_variable.h>
#include "hphp/compiler/expression/assignment_expression.h"
#include "hphp/compiler/expression/constant_expression.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/parameter_expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include <runtime/base/class_info.h>
#include <runtime/base/complex_types.h>
#include <runtime/base/variable_serializer.h>
#include "hphp/runtime/base/class_info.h"
#include "hphp/runtime/base/complex_types.h"
#include "hphp/runtime/base/variable_serializer.h"
#include <util/logger.h>
#include "hphp/util/logger.h"
using namespace HPHP;
@@ -284,9 +285,9 @@ void Symbol::serializeParam(JSON::DocTarget::OutputStream &out) const {
assert(valueExp);
const string &init = ExtractInitializer(out.analysisResult(), valueExp);
if (!init.empty()) out << init;
else out << JSON::Null;
else out << JSON::Null();
} else {
out << JSON::Null;
out << JSON::Null();
}
ms.done();
@@ -295,20 +296,18 @@ void Symbol::serializeParam(JSON::DocTarget::OutputStream &out) const {
static inline std::string ExtractDocComment(ExpressionPtr e) {
if (!e) return "";
switch (e->getKindOf()) {
case Expression::KindOfAssignmentExpression:
return ExtractDocComment(e->getNthExpr(0));
case Expression::KindOfSimpleVariable:
{
SimpleVariablePtr sv(
static_pointer_cast<SimpleVariable>(e));
return sv->getDocComment();
}
case Expression::KindOfConstantExpression:
{
ConstantExpressionPtr ce(
static_pointer_cast<ConstantExpression>(e));
return ce->getDocComment();
}
case Expression::KindOfAssignmentExpression: {
AssignmentExpressionPtr ae(static_pointer_cast<AssignmentExpression>(e));
return ExtractDocComment(ae->getVariable());
}
case Expression::KindOfSimpleVariable: {
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
return sv->getDocComment();
}
case Expression::KindOfConstantExpression: {
ConstantExpressionPtr ce(static_pointer_cast<ConstantExpression>(e));
return ce->getDocComment();
}
default: return "";
}
return "";
@@ -337,9 +336,9 @@ void Symbol::serializeClassVar(JSON::DocTarget::OutputStream &out) const {
assert(initExp);
const string &init = ExtractInitializer(out.analysisResult(), initExp);
if (!init.empty()) out << init;
else out << JSON::Null;
else out << JSON::Null();
} else {
out << JSON::Null;
out << JSON::Null();
}
const string &docs = ExtractDocComment(
@@ -452,7 +451,7 @@ const Symbol *SymbolTable::getSymbolImpl(const std::string &name) const {
if (it != m_symbolMap.end()) {
return &it->second;
}
return NULL;
return nullptr;
}
Symbol *SymbolTable::getSymbol(const std::string &name) {
@@ -596,7 +595,7 @@ void SymbolTable::countTypes(std::map<std::string, int> &counts) {
}
string SymbolTable::getEscapedText(Variant v, int &len) {
VariableSerializer vs(VariableSerializer::Serialize);
VariableSerializer vs(VariableSerializer::Type::Serialize);
String str = vs.serialize(v, true);
len = str.length();
string output = Util::escapeStringForCPP(str.data(), len);
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,13 +14,13 @@
+----------------------------------------------------------------------+
*/
#ifndef __SYMBOL_TABLE_H__
#define __SYMBOL_TABLE_H__
#ifndef incl_HPHP_SYMBOL_TABLE_H_
#define incl_HPHP_SYMBOL_TABLE_H_
#include <compiler/hphp.h>
#include <util/json.h>
#include <util/util.h>
#include <util/lock.h>
#include "hphp/compiler/hphp.h"
#include "hphp/util/json.h"
#include "hphp/util/util.h"
#include "hphp/util/lock.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -115,6 +115,8 @@ public:
bool isIndirectAltered() const { return m_flags.m_indirectAltered; }
bool isReferenced() const { return !m_flags.m_notReferenced; }
bool isHidden() const { return m_flags.m_hidden; }
bool isGeneratorParameter() const { return m_flags.m_generatorParameter; }
bool isRefGeneratorParameter() const { return m_flags.m_refGeneratorParameter; }
bool isClosureVar() const { return m_flags.m_closureVar; }
bool isRefClosureVar() const { return m_flags.m_refClosureVar; }
bool isPassClosureVar() const { return m_flags.m_passClosureVar; }
@@ -140,6 +142,8 @@ public:
void setIndirectAltered() { m_flags.m_indirectAltered = true; }
void setReferenced() { m_flags.m_notReferenced = false; }
void setHidden() { m_flags.m_hidden = true; }
void setGeneratorParameter() { m_flags.m_generatorParameter = true; }
void setRefGeneratorParameter() { m_flags.m_refGeneratorParameter = true; }
void setClosureVar() { m_flags.m_closureVar = true; }
void setRefClosureVar() { m_flags.m_refClosureVar = true; }
void setPassClosureVar() { m_flags.m_passClosureVar = true; }
@@ -185,7 +189,7 @@ private:
std::string m_name;
unsigned int m_hash;
union {
unsigned m_flags_val;
uint64_t m_flags_val;
struct {
/* internal */
unsigned m_declaration_set : 1;
@@ -219,6 +223,8 @@ private:
unsigned m_indirectAltered : 1;
unsigned m_notReferenced : 1;
unsigned m_hidden : 1;
unsigned m_generatorParameter : 1;
unsigned m_refGeneratorParameter : 1;
unsigned m_closureVar : 1;
unsigned m_refClosureVar : 1;
unsigned m_passClosureVar : 1;
@@ -227,7 +233,13 @@ private:
unsigned m_stashedVal : 1;
unsigned m_reseated : 1;
} m_flags;
};
static_assert(
sizeof(m_flags_val) == sizeof(m_flags),
"m_flags_val must cover all the flags");
ConstructPtr m_declaration;
ConstructPtr m_value;
TypePtr m_coerced;
@@ -244,7 +256,7 @@ private:
class SymParamWrapper : public JSON::DocTarget::ISerializable {
public:
SymParamWrapper(const Symbol* sym) : m_sym(sym) {
explicit SymParamWrapper(const Symbol* sym) : m_sym(sym) {
assert(sym);
}
virtual void serialize(JSON::DocTarget::OutputStream &out) const {
@@ -256,7 +268,7 @@ private:
class SymClassVarWrapper : public JSON::DocTarget::ISerializable {
public:
SymClassVarWrapper(const Symbol* sym) : m_sym(sym) {
explicit SymClassVarWrapper(const Symbol* sym) : m_sym(sym) {
assert(sym);
}
virtual void serialize(JSON::DocTarget::OutputStream &out) const {
@@ -382,4 +394,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __SYMBOL_TABLE_H__
#endif // incl_HPHP_SYMBOL_TABLE_H_
+801
Ver Arquivo
@@ -0,0 +1,801 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/analysis/type.h"
#include "hphp/compiler/code_generator.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/expression/expression.h"
#include "hphp/runtime/base/builtin_functions.h"
#include <boost/format.hpp>
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// statics
TypePtr Type::Null (new Type(Type::KindOfVoid ));
TypePtr Type::Boolean (new Type(Type::KindOfBoolean ));
TypePtr Type::Int32 (new Type(Type::KindOfInt32 ));
TypePtr Type::Int64 (new Type(Type::KindOfInt64 ));
TypePtr Type::Double (new Type(Type::KindOfDouble ));
TypePtr Type::String (new Type(Type::KindOfString ));
TypePtr Type::Array (new Type(Type::KindOfArray ));
TypePtr Type::Object (new Type(Type::KindOfObject ));
TypePtr Type::Variant (new Type(Type::KindOfVariant ));
TypePtr Type::Numeric (new Type(Type::KindOfNumeric ));
TypePtr Type::PlusOperand (new Type(Type::KindOfPlusOperand ));
TypePtr Type::Primitive (new Type(Type::KindOfPrimitive ));
TypePtr Type::Sequence (new Type(Type::KindOfSequence ));
TypePtr Type::AutoSequence(new Type(Type::KindOfAutoSequence));
TypePtr Type::AutoObject (new Type(Type::KindOfAutoObject ));
TypePtr Type::Any (new Type(Type::KindOfAny ));
TypePtr Type::Some (new Type(Type::KindOfSome ));
Type::TypePtrMap Type::s_TypeHintTypes;
Type::TypePtrMap Type::s_HHTypeHintTypes;
void Type::InitTypeHintMap() {
assert(s_TypeHintTypes.empty());
assert(s_HHTypeHintTypes.empty());
s_TypeHintTypes["array"] = Type::Array;
s_HHTypeHintTypes["array"] = Type::Array;
s_HHTypeHintTypes["bool"] = Type::Boolean;
s_HHTypeHintTypes["boolean"] = Type::Boolean;
s_HHTypeHintTypes["int"] = Type::Int64;
s_HHTypeHintTypes["integer"] = Type::Int64;
s_HHTypeHintTypes["real"] = Type::Double;
s_HHTypeHintTypes["double"] = Type::Double;
s_HHTypeHintTypes["float"] = Type::Double;
s_HHTypeHintTypes["string"] = Type::String;
}
const Type::TypePtrMap &Type::GetTypeHintTypes(bool hhType) {
return hhType ? s_HHTypeHintTypes : s_TypeHintTypes;
}
void Type::ResetTypeHintTypes() {
s_TypeHintTypes.clear();
s_HHTypeHintTypes.clear();
}
TypePtr Type::CreateObjectType(const std::string &clsname) {
// For interfaces that support arrays we're pessimistic and
// we treat it as a Variant
if (interface_supports_array(clsname)) {
return Type::Variant;
}
return TypePtr(new Type(KindOfObject, clsname));
}
TypePtr Type::GetType(KindOf kindOf, const std::string &clsname /* = "" */) {
assert(kindOf);
if (!clsname.empty()) {
// For interfaces that support arrays we're pessimistic and
// we treat it as a Variant
if (interface_supports_array(clsname)) {
return Type::Variant;
}
return TypePtr(new Type(kindOf, clsname));
}
switch (kindOf) {
case KindOfBoolean: return Type::Boolean;
case KindOfInt32: return Type::Int32;
case KindOfInt64: return Type::Int64;
case KindOfDouble: return Type::Double;
case KindOfString: return Type::String;
case KindOfArray: return Type::Array;
case KindOfVariant: return Type::Variant;
case KindOfObject: return Type::Object;
case KindOfNumeric: return Type::Numeric;
case KindOfPrimitive: return Type::Primitive;
case KindOfPlusOperand: return Type::PlusOperand;
case KindOfSequence: return Type::Sequence;
case KindOfSome: return Type::Some;
case KindOfAny: return Type::Any;
default: return TypePtr(new Type(kindOf));
}
}
TypePtr Type::Intersection(AnalysisResultConstPtr ar,
TypePtr from, TypePtr to) {
// Special case: if we're casting to Some or Any, return the "from" type;
// if we're casting to Variant, return Variant.
if (to->m_kindOf == KindOfSome || to->m_kindOf == KindOfAny) {
return from;
} else if (to->m_kindOf == KindOfVariant) {
return Variant;
}
int resultKind = to->m_kindOf & from->m_kindOf;
std::string resultName = "";
if (resultKind & KindOfObject) {
// if they're the same, or we don't know one's name, then use
// the other
if (to->m_name == from->m_name || from->m_name.empty()) {
resultName = to->m_name;
} else if (to->m_name.empty()) {
resultName = from->m_name;
} else {
// make sure there's a subclass relation
ClassScopePtr cls = ar->findClass(from->m_name);
if (cls) {
if (cls->derivesFrom(ar, to->m_name, true, false)) {
resultName = to->m_name;
} else {
resultKind &= ~KindOfObject;
}
}
}
}
TypePtr res;
// If there is overlap (for instance, they were the same, or we've narrowed
// down something like Sequenece to be more specific), then return the
// intersection of the types.
if (resultKind) {
res = GetType(resultKind, resultName);
} else if (from->mustBe(KindOfObject) && to->m_kindOf == KindOfPrimitive) {
// Special case Object -> Primitive: can we tostring it?
if (!from->m_name.empty()) {
ClassScopePtr cls = ar->findClass(from->m_name);
if (cls && cls->findFunction(ar, "__tostring", true)) {
res = Type::String;
}
}
// Otherwise, return Int32
res = Int32;
} else if (from->m_kindOf == KindOfBoolean
&& to->mustBe(KindOfNumeric | KindOfArray | KindOfString)
&& !IsExactType(to->m_kindOf)) {
res = Int32;
} else {
res = to;
}
if (from->mustBe(KindOfBoolean) && to->m_kindOf == KindOfPrimitive) {
res = Int32;
}
return res;
}
bool Type::IsMappedToVariant(TypePtr t) {
if (!t) return true;
switch (t->m_kindOf) {
case KindOfBoolean:
case KindOfInt32 :
case KindOfInt64 :
case KindOfDouble :
case KindOfString :
case KindOfArray :
case KindOfObject :
return false;
default: break;
}
return true;
}
bool Type::IsCastNeeded(AnalysisResultConstPtr ar, TypePtr from, TypePtr to) {
if (SameType(from, to)) return false;
if (!from->m_kindOf) return true;
if (!to->m_kindOf) return true;
// Special case: all Sequence operations are implemented on both String and
// Array, and vice versa, therefore no need to cast between these types.
if ((from->m_kindOf == KindOfSequence && to->mustBe(KindOfSequence))
|| (to->m_kindOf == KindOfSequence && from->mustBe(KindOfSequence))) {
return false;
}
switch (to->m_kindOf) {
case KindOfVariant:
case KindOfNumeric:
case KindOfPrimitive:
case KindOfPlusOperand:
case KindOfSome:
case KindOfSequence:
case KindOfAny:
// Currently these types are all mapped to Variant in runtime/base, and
// that's why these casting are not needed.
return false;
case KindOfObject:
if (from->m_kindOf == KindOfObject && to->m_name.empty() &&
!from->m_name.empty()) return false;
else return true;
default:
// if we don't have a specific type narrowed down, then
// it will be a Variant at at runtime, so no cast is needed.
return IsExactType(to->m_kindOf);
}
}
bool Type::IsCoercionNeeded(AnalysisResultConstPtr ar, TypePtr t1, TypePtr t2) {
if (t1->m_kindOf == KindOfSome ||
t1->m_kindOf == KindOfAny ||
t2->m_kindOf == KindOfSome ||
t2->m_kindOf == KindOfAny) return true;
// special case: we always coerce to a specific object type so we can
// type checking properties and methods
if (t1->m_kindOf == KindOfObject && !t1->m_name.empty() &&
t2->m_kindOf == KindOfObject && t2->m_name.empty()) {
return true;
}
return !Type::IsLegalCast(ar, t1, t2);
}
TypePtr Type::Coerce(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) {
if (SameType(type1, type2)) return type1;
if (type1->m_kindOf == KindOfVariant ||
type2->m_kindOf == KindOfVariant) return Type::Variant;
if (type1->m_kindOf > type2->m_kindOf) {
TypePtr tmp = type1;
type1 = type2;
type2 = tmp;
}
if (type1->m_kindOf == KindOfVoid &&
(type2->m_kindOf == KindOfString ||
type2->m_kindOf == KindOfArray ||
type2->m_kindOf == KindOfObject)) {
return type2;
}
if (type2->m_kindOf == KindOfSome ||
type2->m_kindOf == KindOfAny) return type1;
if (type2->m_kindOf & KindOfAuto) {
if (type1->mustBe(type2->m_kindOf & ~KindOfAuto)) {
if (!(type1->m_kindOf & Type::KindOfString)) {
return type1;
}
if (type2->m_kindOf == KindOfAutoSequence) {
return Type::Sequence;
}
return GetType((KindOf)(type2->m_kindOf & ~KindOfAuto));
}
return Type::Variant;
}
if (type1->mustBe(KindOfInteger)) {
if (type2->mustBe(KindOfInteger)) {
return type2;
} else if (type2->mustBe(KindOfDouble)) {
return Type::Numeric;
}
}
if (type1->mustBe(Type::KindOfObject) &&
type2->mustBe(Type::KindOfObject)) {
if (type1->m_name.empty()) return type1;
if (type2->m_name.empty()) return type2;
ClassScopePtr cls1 = ar->findClass(type1->m_name);
if (cls1 && !cls1->isRedeclaring() &&
cls1->derivesFrom(ar, type2->m_name, true, false)) {
return type2;
}
ClassScopePtr cls2 = ar->findClass(type2->m_name);
if (cls2 && !cls2->isRedeclaring() &&
cls2->derivesFrom(ar, type1->m_name, true, false)) {
return type1;
}
if (cls1 && cls2 &&
!cls1->isRedeclaring() && !cls2->isRedeclaring()) {
ClassScopePtr parent =
ClassScope::FindCommonParent(ar, type1->m_name,
type2->m_name);
if (parent) {
return Type::CreateObjectType(parent->getName());
}
}
return Type::Object;
}
if (type1->mustBe(type2->m_kindOf)) {
return type2;
}
static_assert(Type::KindOfString < Type::KindOfArray,
"Expected Type::KindOfString < Type::KindOfArray");
if (type1->m_kindOf == Type::KindOfString &&
type2->m_kindOf == Type::KindOfArray) {
return Type::Sequence;
}
return Type::Variant;
}
TypePtr Type::Union(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) {
if (SameType(type1, type2)) {
return type1;
}
int resultKind = type1->m_kindOf | type2->m_kindOf;
if (resultKind == KindOfObject) {
std::string resultName("");
// if they're the same, or we don't know one's name, then use
// the other
if (type1->m_name == type2->m_name) {
resultName = type1->m_name;
} else if (type1->m_name.empty() || type2->m_name.empty()) {
// resultName was initialized to "", so leave it as such;
// we know it's an object but not what kind.
} else {
// take the superclass
ClassScopePtr res =
ClassScope::FindCommonParent(ar, type1->m_name,
type2->m_name);
if (res) resultName = res->getName();
}
return TypePtr(Type::CreateObjectType(resultName));
}
return GetType((KindOf)resultKind);
}
bool Type::SameType(TypePtr type1, TypePtr type2) {
if (!type1 && !type2) return true;
if (!type1 || !type2) return false;
if (type1->m_kindOf == type2->m_kindOf) {
if ((type1->m_kindOf & KindOfObject) &&
type1->m_name != type2->m_name) return false;
return true;
}
return false;
}
bool Type::SubType(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) {
if (!type1 && !type2) return true;
if (!type1 || !type2) return false;
if (type1->m_kindOf != type2->m_kindOf) return false;
if (!(type1->m_kindOf & KindOfObject)) return true;
// both are objects...
if (type1->m_name == type2->m_name) return true;
// ... with different classnames; check subtype relationship.
ClassScopePtr cls1 = ar->findClass(type1->m_name);
return cls1 && !cls1->isRedeclaring() &&
cls1->derivesFrom(ar, type2->m_name, true, false);
}
bool Type::IsExactType(KindOf kindOf) {
// clever trick thanks to mwilliams - this will evaluate
// to true iff exactly one bit is set in kindOf
return kindOf && !(kindOf & (kindOf-1));
}
bool Type::HasFastCastMethod(TypePtr t) {
switch (t->getKindOf()) {
case Type::KindOfBoolean:
case Type::KindOfInt32:
case Type::KindOfInt64:
case Type::KindOfDouble:
case Type::KindOfString:
case Type::KindOfArray:
case Type::KindOfObject:
return true;
default: break;
}
return false;
}
string Type::GetFastCastMethod(
TypePtr dst, bool allowRef, bool forConst) {
const char *prefix0 = allowRef ? "to" : "as";
const char *prefix1 = forConst ? "C" : "";
const char *prefix2 = "Ref";
const char *type ATTRIBUTE_UNUSED;
switch (dst->getKindOf()) {
case Type::KindOfBoolean:
case Type::KindOfInt32:
case Type::KindOfInt64:
case Type::KindOfDouble:
prefix0 = "to";
prefix1 = "";
prefix2 = "Val";
break;
default: break;
}
switch (dst->getKindOf()) {
case Type::KindOfBoolean:
type = "Boolean";
break;
case Type::KindOfInt32:
case Type::KindOfInt64:
type = "Int64";
break;
case Type::KindOfDouble:
type = "Double";
break;
case Type::KindOfString:
type = "Str";
break;
case Type::KindOfArray:
type = "Arr";
break;
case Type::KindOfObject:
type = "Obj";
break;
default:
type = ""; // make the compiler happy
assert(false);
break;
}
return string(prefix0) + string(prefix1) + string(type) + string(prefix2);
}
/* This new IsLegalCast returns true in a few cases where the old version
* (which was basically a hardcoded truth table) returned false; it seems
* like "true" is in fact the right thing to return. The cases that appear
* when compiling www are:
* Sequence -> Array
* PlusOperand -> Array
* String -> PlusOperand
* Boolean -> PlusOperand
*/
bool Type::IsLegalCast(AnalysisResultConstPtr ar, TypePtr from, TypePtr to) {
if (!from->m_kindOf) return true;
// since both 'from' and 'to' represent sets of types, we do
// this by computing the set of types that we could possibly cast 'from'
// to, and then determining whether that overlaps with 'to'.
int canCastTo = KindOfBoolean | from->m_kindOf;
if (from->m_kindOf & KindOfVoid) canCastTo |= KindOfVoid;
// Boolean, Numeric, and String can all be cast among each other
if (from->m_kindOf & (KindOfBoolean | KindOfNumeric | KindOfString)) {
canCastTo |= KindOfNumeric | KindOfString;
}
if (from->m_kindOf & KindOfObject) {
// Objects can only cast to string if they have __tostring
if (from->m_name.empty()) {
canCastTo |= KindOfString; // we don't know which class it is
} else {
ClassScopePtr cls = ar->findClass(from->m_name);
if (!cls || cls->isRedeclaring() ||
cls->findFunction(ar, "__tostring", true)) {
canCastTo |= KindOfString;
}
}
// can only cast between objects if there's a subclass relation
if ((to->m_kindOf & KindOfObject) && !to->m_name.empty() &&
!from->m_name.empty() && to->m_name != from->m_name) {
ClassScopePtr cls = ar->findClass(from->m_name);
if (cls && (cls->isRedeclaring() ||
!cls->derivesFrom(ar, to->m_name, true, true))) {
canCastTo &= ~KindOfObject;
}
}
}
bool overlap = (to->m_kindOf & canCastTo);
return overlap;
}
///////////////////////////////////////////////////////////////////////////////
Type::Type(KindOf kindOf) : m_kindOf(kindOf) {
}
Type::Type(KindOf kindOf, const std::string &name)
: m_kindOf(kindOf), m_name(name) {
// m_name must not be empty only when this type could
// be an object
assert(m_name.empty() || (m_kindOf & KindOfObject));
}
bool Type::isInteger() const {
switch (m_kindOf) {
case KindOfInt32:
case KindOfInt64:
return true;
default:
break;
}
return false;
}
bool Type::isStandardObject() const {
return m_kindOf == KindOfObject && m_name.empty();
}
bool Type::isSpecificObject() const {
return m_kindOf == KindOfObject && !m_name.empty();
}
bool Type::isNonConvertibleType() const {
return m_kindOf == KindOfObject || m_kindOf == KindOfArray;
}
bool Type::isNoObjectInvolved() const {
if (couldBe(KindOfObject)
|| couldBe(KindOfArray))
return false;
else
return true;
}
TypePtr Type::combinedArithmeticType(TypePtr t1, TypePtr t2) {
KindOf kind = KindOfAny;
if ((t1 && t1->is(Type::KindOfArray)) ||
(t2 && t2->is(Type::KindOfArray))) {
return TypePtr();
}
if (t1 && t1->isPrimitive()) {
if (t2 && t2->isPrimitive()) {
if (t2->getKindOf() > t1->getKindOf()) {
kind = t2->getKindOf();
} else {
kind = t1->getKindOf();
}
} else if (t1->is(KindOfDouble)) {
kind = KindOfDouble;
} else {
kind = KindOfNumeric;
}
} else if (t2 && t2->isPrimitive()) {
if (t2->is(KindOfDouble)) {
kind = KindOfDouble;
} else {
kind = KindOfNumeric;
}
} else if ((t1 && t1->mustBe(KindOfNumeric)) ||
(t2 && t2->mustBe(KindOfNumeric))) {
kind = KindOfNumeric;
}
if (kind < KindOfInt64) {
kind = KindOfInt64;
}
if (kind != KindOfAny) {
return GetType(kind);
}
return TypePtr();
}
///////////////////////////////////////////////////////////////////////////////
ClassScopePtr Type::getClass(AnalysisResultConstPtr ar,
BlockScopeRawPtr scope) const {
if (m_name.empty()) return ClassScopePtr();
ClassScopePtr cls = ar->findClass(m_name);
if (cls && cls->isRedeclaring()) {
if (!scope) {
cls.reset();
} else {
cls = scope->findExactClass(cls);
}
}
return cls;
}
DataType Type::getDataType() const {
switch (m_kindOf) {
case KindOfBoolean: return HPHP::KindOfBoolean;
case KindOfInt32:
case KindOfInt64: return HPHP::KindOfInt64;
case KindOfDouble: return HPHP::KindOfDouble;
case KindOfString: return HPHP::KindOfString;
case KindOfArray: return HPHP::KindOfArray;
case KindOfObject: return HPHP::KindOfObject;
case KindOfNumeric:
case KindOfPrimitive:
case KindOfPlusOperand:
case KindOfSequence:
default: return HPHP::KindOfUnknown;
}
}
// This is similar to getDataType() except that it returns
// HPHP::KindOfNull for KindOfVoid;
DataType Type::getHhvmDataType() const {
switch (m_kindOf) {
case KindOfVoid: return HPHP::KindOfNull;
default: return getDataType();
}
}
std::string Type::getPHPName() {
switch (m_kindOf) {
case KindOfArray: return "array";
case KindOfObject: return m_name;
default: break;
}
return "";
}
std::string Type::toString() const {
switch (m_kindOf) {
case KindOfBoolean: return "Boolean";
case KindOfInt32: return "Int32";
case KindOfInt64: return "Int64";
case KindOfDouble: return "Double";
case KindOfString: return "String";
case KindOfArray: return "Array";
case KindOfVariant: return "Variant";
case KindOfSome: return "Some";
case KindOfAny: return "Any";
case KindOfObject: return string("Object - ") + m_name;
case KindOfNumeric: return "Numeric";
case KindOfPrimitive: return "Primitive";
case KindOfPlusOperand: return "PlusOperand";
case KindOfSequence: return "Sequence";
default:
return boost::str(boost::format("[0x%x]") % m_kindOf);
}
return "(unknown)";
}
void Type::Dump(TypePtr type, const char *fmt /* = "%s" */) {
printf(fmt, type ? type->toString().c_str() : "(null)");
}
void Type::Dump(ExpressionPtr exp) {
Dump(exp->getExpectedType(), "Expected: %s\t");
Dump(exp->getActualType(), "Actual: %s\n");
}
void Type::serialize(JSON::CodeError::OutputStream &out) const {
out << toString();
}
void Type::serialize(JSON::DocTarget::OutputStream &out) const {
string s("any");
switch (m_kindOf) {
case KindOfBoolean: s = "boolean"; break;
case KindOfInt32:
case KindOfInt64: s = "integer"; break;
case KindOfDouble: s = "double"; break;
case KindOfString: s = "string"; break;
case KindOfArray: s = "array"; break;
case KindOfVariant:
case KindOfSome:
case KindOfAny: s = "any"; break;
case KindOfObject:
{
if (m_name.empty()) s = "object";
else {
ClassScopePtr c(getClass(out.analysisResult(), BlockScopeRawPtr()));
if (c) {
s = c->getOriginalName();
} else {
s = "object";
}
}
break;
}
case KindOfNumeric: s = "numeric"; break;
case KindOfPrimitive: s = "primitive"; break;
case KindOfPlusOperand: s = "any"; break;
case KindOfSequence: s = "sequence"; break;
}
out << s;
}
void Type::count(std::map<std::string, int> &counts) {
if (is(Type::KindOfObject)) {
if (isSpecificObject()) {
counts["Object - Specific"]++;
} else {
counts["Object"]++;
}
} else {
counts[toString()]++;
}
if (IsExactType(m_kindOf)) {
counts["_strong"]++;
} else {
counts["_weak"]++;
}
counts["_all"]++;
}
TypePtr Type::InferredObject(AnalysisResultConstPtr ar,
TypePtr type1,
TypePtr type2) {
assert(type1->m_kindOf == KindOfObject);
assert(type2->m_kindOf == KindOfObject);
TypePtr resultType = Type::Object;
// if they're the same, or we don't know one's name, then use
// the other
if (type1->m_name == type2->m_name || type1->m_name.empty()) {
resultType = type2;
} else if (type2->m_name.empty()) {
resultType = type1;
} else {
// take the subclass
ClassScopePtr cls1 = ar->findClass(type1->m_name);
ClassScopePtr cls2 = ar->findClass(type2->m_name);
bool c1ok = cls1 && !cls1->isRedeclaring();
bool c2ok = cls2 && !cls2->isRedeclaring();
if (c1ok && cls1->derivesFrom(ar, type2->m_name, true, false)) {
resultType = type1;
} else if (c2ok && cls2->derivesFrom(ar, type1->m_name, true, false)) {
resultType = type2;
} else if (c1ok && c2ok && cls1->derivedByDynamic() &&
cls2->derivesFromRedeclaring()) {
resultType = type2;
} else {
resultType = type1;
}
}
return resultType;
}
/* We have inferred type1 and type2 as the actual types for the same
expression.
Check that the types are compatible (it cant be both a string and
an integer, for example), and return the combined type. If they
are not compatible, return a null pointer.
*/
TypePtr Type::Inferred(AnalysisResultConstPtr ar,
TypePtr type1, TypePtr type2) {
if (!type1) return type2;
if (!type2) return type1;
KindOf k1 = type1->m_kindOf;
KindOf k2 = type2->m_kindOf;
if (k1 == k2) {
return k1 == KindOfObject ?
Type::InferredObject(ar, type1, type2) : type1;
}
// If one set is a subset of the other, return the subset.
if ((k1 & k2) == k1) return type1;
if ((k1 & k2) == k2) return type2;
// If one type must be numeric and the other might be, then assume numeric
if (type1->mustBe(KindOfNumeric) && type2->couldBe(KindOfNumeric)) {
return type1;
}
if (type2->mustBe(KindOfNumeric) && type1->couldBe(KindOfNumeric)) {
return type2;
}
// Otherwise, take the intersection
int resultKind = type1->m_kindOf & type2->m_kindOf;
if (resultKind == KindOfObject) {
return Type::InferredObject(ar, type1, type2);
}
return resultKind ? GetType(resultKind) : TypePtr();
}
+278
Ver Arquivo
@@ -0,0 +1,278 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_TYPE_H_
#define incl_HPHP_TYPE_H_
#include "hphp/compiler/hphp.h"
#include "hphp/util/json.h"
#include "hphp/util/case_insensitive.h"
#include "hphp/runtime/base/types.h"
class TestCodeRun;
class TestCodeError;
struct ProgramOptions;
int process(const ProgramOptions&);
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class CodeGenerator;
DECLARE_BOOST_TYPES(Expression);
DECLARE_BOOST_TYPES(AnalysisResult);
DECLARE_BOOST_TYPES(Type);
DECLARE_BOOST_TYPES(BlockScope);
DECLARE_BOOST_TYPES(ClassScope);
class Type : public JSON::CodeError::ISerializable,
public JSON::DocTarget::ISerializable {
friend class ::TestCodeRun;
friend class ::TestCodeError;
public:
typedef int KindOf;
static const KindOf KindOfVoid = 0x0001;
static const KindOf KindOfBoolean = 0x0002;
static const KindOf KindOfInt32 = 0x0010;
static const KindOf KindOfInt64 = 0x0020;
static const KindOf KindOfDouble = 0x0040;
static const KindOf KindOfString = 0x0080;
static const KindOf KindOfArray = 0x0100;
static const KindOf KindOfObject = 0x0200; // with classname
static const KindOf KindOfVariant = 0xFFFF;
/* This bit tells coerce that if the other type
is already one of the specified types, it wont
be modified.
eg $a['foo'] = <whatever>
If $a is already known to be string or array, it stays that way.
If we coerce to Sequence, however, it would become Sequence, and
hence Variant
*/
static const KindOf KindOfAuto = 0x0400;
static const KindOf KindOfInteger = (KindOf)(KindOfInt64 | KindOfInt32);
static const KindOf KindOfNumeric = (KindOf)(KindOfDouble | KindOfInteger);
static const KindOf KindOfPrimitive = (KindOf)(KindOfNumeric | KindOfString);
static const KindOf KindOfPlusOperand = (KindOf)(KindOfNumeric | KindOfArray);
static const KindOf KindOfSequence = (KindOf)(KindOfString | KindOfArray);
static const KindOf KindOfAutoSequence = (KindOf)(KindOfAuto |
KindOfSequence);
static const KindOf KindOfAutoObject = (KindOf)(KindOfAuto | KindOfObject);
static const KindOf KindOfSome = (KindOf)0x7FFE;
static const KindOf KindOfAny = (KindOf)0x7FFF;
/**
* Inferred types: types that a variable or a constant is sure to be.
*/
static TypePtr Null;
static TypePtr Boolean;
static TypePtr Int32;
static TypePtr Int64;
static TypePtr Double;
static TypePtr String;
static TypePtr Array;
static TypePtr Object;
static TypePtr Variant;
static TypePtr Numeric;
static TypePtr PlusOperand;
static TypePtr Primitive;
static TypePtr Sequence;
static TypePtr AutoSequence;
static TypePtr AutoObject;
static TypePtr Any;
static TypePtr Some;
typedef hphp_string_imap<TypePtr> TypePtrMap;
static const TypePtrMap &GetTypeHintTypes(bool hhType);
/**
* Uncertain types: types that are ambiguous yet.
*/
static TypePtr CreateObjectType(const std::string &classname);
/**
* For inferred, return static type objects; for uncertain, create new
* ones.
*/
static TypePtr GetType(KindOf kindOf,
const std::string &clsname = "");
/**
* Whether a type can be used as another type.
*/
static bool IsLegalCast(AnalysisResultConstPtr ar, TypePtr from, TypePtr to);
/**
* Find the intersection between two sets of types.
*/
static TypePtr Intersection(AnalysisResultConstPtr ar,
TypePtr from, TypePtr to);
/**
* Whether or not this type is mapped to type Variant
* in the runtime
*/
static bool IsMappedToVariant(TypePtr t);
/**
* Whether or not a cast is needed during code generation.
*/
static bool IsCastNeeded(AnalysisResultConstPtr ar, TypePtr from, TypePtr to);
/**
* When a variable's type is t1, and it's used as t2, do we need to
* coerce variable's type? Normally, if t2 can be legally casted to t1,
* this returns false.
*/
static bool IsCoercionNeeded(AnalysisResultConstPtr ar,
TypePtr t1, TypePtr t2);
/**
* When a variable is assigned with two types, what type a variable
* should be?
*/
static TypePtr Coerce(AnalysisResultConstPtr ar,
TypePtr type1, TypePtr type2);
static TypePtr Union(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2);
/**
* When two types have been inferred for an expression, what type
* should it be?
*/
static TypePtr Inferred(AnalysisResultConstPtr ar,
TypePtr type1, TypePtr type2);
/**
* When two object types have been inferred for an expression, what type
* should it be?
*/
static TypePtr InferredObject(AnalysisResultConstPtr ar,
TypePtr type1,
TypePtr type2);
/**
* Whether or not two types are the same.
*/
static bool SameType(TypePtr type1, TypePtr type2);
/**
* Return true if SameType(type1,type2) or if type1 and type2
* are objects and type1 derives from type2.
*/
static bool SubType(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2);
/**
* Testing type conversion for constants.
*/
static bool IsExactType(KindOf kindOf);
static bool HasFastCastMethod(TypePtr t);
/**
* Returns the name of the method used to fast cast from
* variant to dst
*/
static std::string GetFastCastMethod(
TypePtr dst, bool allowRef, bool forConst);
private:
Type(KindOf kindOf, const std::string &name);
public:
/**
* KindOf testing.
*/
explicit Type(KindOf kindOf);
bool is(KindOf kindOf) const { return m_kindOf == kindOf;}
bool isExactType() const { return IsExactType(m_kindOf); }
bool mustBe(KindOf kindOf) const { return !(m_kindOf & ~kindOf); }
bool couldBe(KindOf kindOf) const { return m_kindOf & kindOf; }
bool isSubsetOf(TypePtr t) const {
return m_kindOf != t->m_kindOf && mustBe(t->m_kindOf);
}
KindOf getKindOf() const { return m_kindOf;}
bool isInteger() const;
bool isStandardObject() const;
bool isSpecificObject() const;
bool isNonConvertibleType() const; // other types cannot convert to them
bool isPrimitive() const {
return IsExactType(m_kindOf) && (m_kindOf <= KindOfDouble) &&
(m_kindOf != KindOfVoid);
}
bool isNoObjectInvolved() const;
const std::string &getName() const { return m_name;}
static TypePtr combinedArithmeticType(TypePtr t1, TypePtr t2);
ClassScopePtr getClass(AnalysisResultConstPtr ar,
BlockScopeRawPtr scope) const;
DataType getDataType() const;
DataType getHhvmDataType() const;
/**
* Type hint names in PHP.
*/
std::string getPHPName();
/**
* Debug dump.
*/
std::string toString() const;
static void Dump(TypePtr type, const char *fmt = "%s");
static void Dump(ExpressionPtr exp);
/**
* Implements JSON::CodeError::ISerializable.
*/
virtual void serialize(JSON::CodeError::OutputStream &out) const;
/**
* Implements JSON::DocTarget::ISerializable.
*/
virtual void serialize(JSON::DocTarget::OutputStream &out) const;
/**
* For stats reporting.
*/
void count(std::map<std::string, int> &counts);
/**
* Must not be invoked concurrently
*/
static void InitTypeHintMap();
private:
/**
* Must not be invoked concurrently
*/
static void ResetTypeHintTypes();
static TypePtrMap s_TypeHintTypes;
static TypePtrMap s_HHTypeHintTypes;
const KindOf m_kindOf;
const std::string m_name;
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_TYPE_H_
+783
Ver Arquivo
@@ -0,0 +1,783 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/type.h"
#include "hphp/compiler/code_generator.h"
#include "hphp/compiler/expression/modifier_expression.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/builtin_symbols.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/expression/simple_function_call.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/expression/static_member_expression.h"
#include "hphp/runtime/base/class_info.h"
#include "hphp/util/util.h"
#include "hphp/util/parser/location.h"
#include "hphp/util/parser/parser.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
// StaticGlobalInfo
string VariableTable::StaticGlobalInfo::GetId
(ClassScopePtr cls, FunctionScopePtr func,
const string &name) {
assert(cls || func);
// format: <class>$$<func>$$name
string id;
if (cls) {
id += cls->getId();
id += Option::IdPrefix;
}
if (func) {
id += func->getId();
id += Option::IdPrefix;
}
id += name;
return id;
}
///////////////////////////////////////////////////////////////////////////////
VariableTable::VariableTable(BlockScope &blockScope)
: SymbolTable(blockScope, false), m_attribute(0), m_nextParam(0),
m_hasGlobal(false), m_hasStatic(false),
m_hasPrivate(false), m_hasNonStaticPrivate(false),
m_forcedVariants(0) {
}
void VariableTable::getLocalVariableNames(vector<string> &syms) const {
FunctionScopeRawPtr fs = getScopePtr()->getContainingFunction();
bool dollarThisIsSpecial = (fs->getContainingClass() ||
fs->inPseudoMain());
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
const string& name = m_symbolVec[i]->getName();
if (name == "this" && dollarThisIsSpecial) {
// The "this" variable in methods and pseudo-main is special and is
// handled separately below.
continue;
}
syms.push_back(name);
}
if (fs->needsLocalThis()) {
assert(dollarThisIsSpecial);
// We only need a local variable named "this" if the current function
// contains an occurrence of "$this" that is not part of a property
// expression or object method call expression
syms.push_back("this");
}
}
void VariableTable::getNames(std::set<string> &names,
bool collectPrivate /* = true */) const {
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
if (collectPrivate || !m_symbolVec[i]->isPrivate()) {
names.insert(m_symbolVec[i]->getName());
}
}
}
bool VariableTable::isParameter(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isParameter();
}
bool VariableTable::isPublic(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isPublic();
}
bool VariableTable::isProtected(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isProtected();
}
bool VariableTable::isPrivate(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isPrivate();
}
bool VariableTable::isStatic(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isStatic();
}
bool VariableTable::isGlobal(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isGlobal();
}
bool VariableTable::isRedeclared(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isRedeclared();
}
bool VariableTable::isLocalGlobal(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isLocalGlobal();
}
bool VariableTable::isNestedStatic(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isNestedStatic();
}
bool VariableTable::isLvalParam(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isLvalParam();
}
bool VariableTable::isUsed(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isUsed();
}
bool VariableTable::isNeeded(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isNeeded();
}
bool VariableTable::isSuperGlobal(const string &name) const {
const Symbol *sym = getSymbol(name);
return sym && sym->isSuperGlobal();
}
bool VariableTable::isLocal(const string &name) const {
return isLocal(getSymbol(name));
}
bool VariableTable::isLocal(const Symbol *sym) const {
if (!sym) return false;
if (getScopePtr()->is(BlockScope::FunctionScope)) {
/*
isSuperGlobal is not wanted here. It just means that
$GLOBALS[name] was referenced in this scope.
It doesnt say anything about the variable $name.
*/
return (!sym->isStatic() &&
!sym->isGlobal() &&
!sym->isGeneratorParameter() &&
!sym->isRefGeneratorParameter() &&
!sym->isParameter());
}
return false;
}
bool VariableTable::needLocalCopy(const string &name) const {
return needLocalCopy(getSymbol(name));
}
bool VariableTable::needLocalCopy(const Symbol *sym) const {
return sym &&
(sym->isGlobal() || sym->isStatic()) &&
(sym->isRedeclared() ||
sym->isNestedStatic() ||
sym->isLocalGlobal() ||
getAttribute(ContainsDynamicVariable) ||
getAttribute(ContainsExtract) ||
getAttribute(ContainsUnset));
}
bool VariableTable::needGlobalPointer() const {
return !isPseudoMainTable() &&
(m_hasGlobal ||
m_hasStatic ||
getAttribute(ContainsDynamicVariable) ||
getAttribute(ContainsExtract) ||
getAttribute(ContainsUnset) ||
getAttribute(NeedGlobalPointer));
}
bool VariableTable::isInherited(const string &name) const {
const Symbol *sym = getSymbol(name);
return !sym ||
(!sym->isGlobal() && !sym->isSystem() && !sym->getDeclaration());
}
ConstructPtr VariableTable::getStaticInitVal(string varName) {
if (Symbol *sym = getSymbol(varName)) {
return sym->getStaticInitVal();
}
return ConstructPtr();
}
bool VariableTable::setStaticInitVal(string varName,
ConstructPtr value) {
Symbol *sym = addSymbol(varName);
bool exists = (sym->getStaticInitVal() != nullptr);
sym->setStaticInitVal(value);
return exists;
}
ConstructPtr VariableTable::getClassInitVal(string varName) {
if (Symbol *sym = getSymbol(varName)) {
return sym->getClassInitVal();
}
return ConstructPtr();
}
bool VariableTable::setClassInitVal(string varName, ConstructPtr value) {
Symbol *sym = addSymbol(varName);
bool exists = (sym->getClassInitVal() != nullptr);
sym->setClassInitVal(value);
return exists;
}
///////////////////////////////////////////////////////////////////////////////
TypePtr VariableTable::addParam(const string &name, TypePtr type,
AnalysisResultConstPtr ar,
ConstructPtr construct) {
Symbol *sym = addDeclaredSymbol(name, construct);
if (!sym->isParameter()) {
sym->setParameterIndex(m_nextParam++);
}
return type ?
add(sym, type, false, ar, construct, ModifierExpressionPtr()) : type;
}
TypePtr VariableTable::addParamLike(const string &name, TypePtr type,
AnalysisResultPtr ar,
ConstructPtr construct, bool firstPass) {
TypePtr ret = type;
if (firstPass) {
ret = add(name, ret, false, ar,
construct, ModifierExpressionPtr());
} else {
ret = checkVariable(name, ret, true, ar, construct);
if (ret->is(Type::KindOfSome)) {
// This is probably too conservative. The problem is that
// a function never called will have parameter types of Any.
// Functions that it calls won't be able to accept variant unless
// it is forced here.
forceVariant(ar, name, VariableTable::AnyVars);
ret = Type::Variant;
}
}
return ret;
}
void VariableTable::addStaticVariable(Symbol *sym,
AnalysisResultPtr ar,
bool member /* = false */) {
if (isGlobalTable(ar) ||
sym->isStatic()) {
return; // a static variable at global scope is the same as non-static
}
sym->setStatic();
m_hasStatic = true;
FunctionScopeRawPtr funcScope = getFunctionScope();
if (funcScope &&
(funcScope->isClosure() || funcScope->isGeneratorFromClosure())) {
// static variables for closures/closure generators are local to the
// function scope
m_staticLocalsVec.push_back(sym);
} else {
VariableTablePtr globalVariables = ar->getVariables();
StaticGlobalInfoPtr sgi(new StaticGlobalInfo());
sgi->sym = sym;
sgi->variables = this;
sgi->cls = getClassScope();
sgi->func = member ? FunctionScopeRawPtr() : getFunctionScope();
globalVariables->m_staticGlobalsVec.push_back(sgi);
}
}
void VariableTable::addStaticVariable(Symbol *sym,
AnalysisResultConstPtr ar,
bool member /* = false */) {
if (isGlobalTable(ar) ||
sym->isStatic()) {
return; // a static variable at global scope is the same as non-static
}
addStaticVariable(sym, ar->lock().get(), member);
}
void VariableTable::cleanupForError(AnalysisResultConstPtr ar) {
if (!m_hasStatic) return;
AnalysisResult::Locker lock(ar);
VariableTablePtr g = lock->getVariables();
ClassScopeRawPtr cls = getClassScope();
for (unsigned i = g->m_staticGlobalsVec.size(); i--; ) {
if (g->m_staticGlobalsVec[i]->cls == cls) {
g->m_staticGlobalsVec.erase(g->m_staticGlobalsVec.begin() + i);
}
}
}
bool VariableTable::markOverride(AnalysisResultPtr ar, const string &name) {
Symbol *sym = getSymbol(name);
assert(sym && sym->isPresent());
bool ret = false;
if (!sym->isStatic() ||
(sym->isPublic() && !sym->getClassInitVal())) {
Symbol *s2;
ClassScopePtr parent = findParent(ar, name, s2);
if (parent) {
assert(s2 && s2->isPresent());
if (!s2->isPrivate()) {
if (!sym->isStatic() || s2->isProtected()) {
if (sym->isPrivate() || sym->isStatic()) {
// don't mark the symbol as overridden
return true;
}
if (sym->isProtected() && s2->isPublic()) {
// still mark the symbol as overridden
ret = true;
}
sym->setOverride();
}
}
}
}
return ret;
}
TypePtr VariableTable::add(const string &name, TypePtr type,
bool implicit, AnalysisResultConstPtr ar,
ConstructPtr construct,
ModifierExpressionPtr modifiers) {
return add(addSymbol(name), type, implicit, ar,
construct, modifiers);
}
TypePtr VariableTable::add(Symbol *sym, TypePtr type,
bool implicit, AnalysisResultConstPtr ar,
ConstructPtr construct,
ModifierExpressionPtr modifiers) {
if (getAttribute(InsideStaticStatement)) {
addStaticVariable(sym, ar);
if (ClassScope::NeedStaticArray(getClassScope(), getFunctionScope())) {
forceVariant(ar, sym->getName(), AnyVars);
}
} else if (getAttribute(InsideGlobalStatement)) {
sym->setGlobal();
m_hasGlobal = true;
AnalysisResult::Locker lock(ar);
if (!isGlobalTable(ar)) {
lock->getVariables()->add(sym->getName(), type, implicit,
ar, construct, modifiers);
}
assert(type->is(Type::KindOfSome) || type->is(Type::KindOfAny));
TypePtr varType = ar->getVariables()->getFinalType(sym->getName());
if (varType) {
type = varType;
} else {
lock->getVariables()->setType(ar, sym->getName(), type, true);
}
} else if (!sym->isHidden() && isPseudoMainTable()) {
// A variable used in a pseudomain
// only need to do this once... should mark the sym.
ar->lock()->getVariables()->add(sym->getName(), type, implicit, ar,
construct, modifiers);
}
if (modifiers) {
if (modifiers->isProtected()) {
sym->setProtected();
} else if (modifiers->isPrivate()) {
sym->setPrivate();
m_hasPrivate = true;
if (!sym->isStatic() && !modifiers->isStatic()) {
m_hasNonStaticPrivate = true;
}
}
if (modifiers->isStatic()) {
addStaticVariable(sym, ar);
}
}
type = setType(ar, sym, type, true);
sym->setDeclaration(construct);
if (!implicit && m_blockScope.isFirstPass()) {
if (!sym->getValue()) {
sym->setValue(construct);
}
}
return type;
}
TypePtr VariableTable::checkVariable(const string &name, TypePtr type,
bool coerce, AnalysisResultConstPtr ar,
ConstructPtr construct) {
return checkVariable(addSymbol(name), type,
coerce, ar, construct);
}
TypePtr VariableTable::checkVariable(Symbol *sym, TypePtr type,
bool coerce, AnalysisResultConstPtr ar,
ConstructPtr construct) {
// Variable used in pseudomain
if (!sym->isHidden() && isPseudoMainTable()) {
// only need to do this once... should mark the sym.
ar->lock()->getVariables()->checkVariable(sym->getName(), type,
coerce, ar, construct);
}
if (!sym->declarationSet()) {
type = setType(ar, sym, type, coerce);
sym->setDeclaration(construct);
return type;
}
return setType(ar, sym, type, coerce);
}
Symbol *VariableTable::findProperty(ClassScopePtr &cls,
const string &name,
AnalysisResultConstPtr ar) {
Symbol *sym = getSymbol(name);
if (sym) {
assert(sym->declarationSet());
if (!sym->isOverride()) {
return sym;
}
assert(!sym->isStatic());
sym = nullptr;
}
if (!sym) {
if (ClassScopePtr parent = findParent(ar, name, sym)) {
sym = parent->findProperty(parent, name, ar);
if (sym) {
cls = parent;
return sym;
}
}
}
return sym;
}
TypePtr VariableTable::checkProperty(BlockScopeRawPtr context,
Symbol *sym, TypePtr type,
bool coerce, AnalysisResultConstPtr ar) {
always_assert(sym->isPresent());
if (sym->isOverride()) {
Symbol *base;
ClassScopePtr parent = findParent(ar, sym->getName(), base);
assert(parent);
assert(parent.get() != &m_blockScope);
assert(base && !base->isPrivate());
if (context->is(BlockScope::FunctionScope)) {
GET_LOCK(parent);
type = parent->getVariables()->setType(ar, base, type, coerce);
} else {
TRY_LOCK(parent);
type = parent->getVariables()->setType(ar, base, type, coerce);
}
}
return setType(ar, sym, type, coerce);
}
bool VariableTable::checkRedeclared(const string &name,
Statement::KindOf kindOf)
{
Symbol *sym = getSymbol(name);
assert(kindOf == Statement::KindOfStaticStatement ||
kindOf == Statement::KindOfGlobalStatement);
if (kindOf == Statement::KindOfStaticStatement && sym->isPresent()) {
if (sym->isStatic()) {
return true;
} else if (!sym->isRedeclared()) {
sym->setRedeclared();
return true;
} else {
return false;
}
} else if (kindOf == Statement::KindOfGlobalStatement &&
sym && !sym->isGlobal() && !sym->isRedeclared()) {
sym->setRedeclared();
return true;
} else {
return false;
}
}
void VariableTable::addLocalGlobal(const string &name) {
addSymbol(name)->setLocalGlobal();
}
void VariableTable::addNestedStatic(const string &name) {
addSymbol(name)->setNestedStatic();
}
void VariableTable::addLvalParam(const string &name) {
addSymbol(name)->setLvalParam();
}
void VariableTable::addUsed(const string &name) {
addSymbol(name)->setUsed();
}
void VariableTable::addNeeded(const string &name) {
addSymbol(name)->setNeeded();
}
bool VariableTable::checkUnused(Symbol *sym) {
if ((!sym || !sym->isHidden()) &&
(isPseudoMainTable() || getAttribute(ContainsDynamicVariable))) {
return false;
}
if (sym) {
return !sym->isUsed() && isLocal(sym);
}
return false;
}
void VariableTable::clearUsed() {
typedef std::pair<const string,Symbol> symPair;
bool ps = isPseudoMainTable();
BOOST_FOREACH(symPair &sym, m_symbolMap) {
if (!ps || sym.second.isHidden()) {
sym.second.clearUsed();
sym.second.clearNeeded();
sym.second.clearReferenced();
sym.second.clearGlobal();
sym.second.clearReseated();
} else {
sym.second.setReferenced();
}
if (sym.second.isRefGeneratorParameter()) {
sym.second.setReferenced();
}
}
}
void VariableTable::forceVariants(AnalysisResultConstPtr ar, int varClass,
bool recur /* = true */) {
int mask = varClass & ~m_forcedVariants;
if (mask) {
if (!m_hasPrivate) mask &= ~AnyPrivateVars;
if (!m_hasStatic) mask &= ~AnyStaticVars;
if (mask) {
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
Symbol *sym = m_symbolVec[i];
if (!sym->isHidden() && sym->declarationSet() &&
mask & GetVarClassMaskForSym(sym)) {
setType(ar, sym, Type::Variant, true);
sym->setIndirectAltered();
}
}
}
m_forcedVariants |= varClass;
if (recur) {
ClassScopePtr parent = m_blockScope.getParentScope(ar);
if (parent && !parent->isRedeclaring()) {
parent->getVariables()->forceVariants(ar, varClass & ~AnyPrivateVars);
}
}
}
}
void VariableTable::forceVariant(AnalysisResultConstPtr ar,
const string &name, int varClass) {
int mask = varClass & ~m_forcedVariants;
if (!mask) return;
if (!m_hasPrivate) mask &= ~AnyPrivateVars;
if (!m_hasStatic) mask &= ~AnyStaticVars;
if (!mask) return;
if (Symbol *sym = getSymbol(name)) {
if (!sym->isHidden() && sym->declarationSet() &&
mask & GetVarClassMaskForSym(sym)) {
setType(ar, sym, Type::Variant, true);
sym->setIndirectAltered();
}
}
}
TypePtr VariableTable::setType(AnalysisResultConstPtr ar,
const std::string &name,
TypePtr type, bool coerce) {
return setType(ar, addSymbol(name), type, coerce);
}
TypePtr VariableTable::setType(AnalysisResultConstPtr ar, Symbol *sym,
TypePtr type, bool coerce) {
bool force_coerce = coerce;
int mask = GetVarClassMaskForSym(sym);
if (m_forcedVariants & mask && !sym->isHidden()) {
type = Type::Variant;
force_coerce = true;
}
TypePtr ret = SymbolTable::setType(ar, sym, type, force_coerce);
if (!ret) return ret;
if (sym->isGlobal() && !isGlobalTable(ar)) {
ar->lock()->getVariables()->setType(ar, sym->getName(), type, coerce);
}
if (coerce) {
if (sym->isParameter()) {
FunctionScope *func = dynamic_cast<FunctionScope *>(&m_blockScope);
assert(func);
TypePtr paramType = func->setParamType(ar,
sym->getParameterIndex(), type);
if (!Type::SameType(paramType, type)) {
return setType(ar, sym, paramType, true); // recursively
}
}
}
return ret;
}
void VariableTable::dumpStats(std::map<string, int> &typeCounts) {
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
Symbol *sym = m_symbolVec[i];
if (sym->isGlobal()) continue;
typeCounts[sym->getFinalType()->toString()]++;
}
}
void VariableTable::addSuperGlobal(const string &name) {
addSymbol(name)->setSuperGlobal();
}
bool VariableTable::isConvertibleSuperGlobal(const string &name) const {
return !getAttribute(ContainsDynamicVariable) && isSuperGlobal(name);
}
ClassScopePtr VariableTable::findParent(AnalysisResultConstPtr ar,
const string &name,
const Symbol *&sym) const {
sym = nullptr;
for (ClassScopePtr parent = m_blockScope.getParentScope(ar);
parent && !parent->isRedeclaring();
parent = parent->getParentScope(ar)) {
sym = parent->getVariables()->getSymbol(name);
assert(!sym || sym->isPresent());
if (sym) return parent;
}
return ClassScopePtr();
}
bool VariableTable::isGlobalTable(AnalysisResultConstPtr ar) const {
return ar->getVariables().get() == this;
}
bool VariableTable::isPseudoMainTable() const {
return m_blockScope.inPseudoMain();
}
bool VariableTable::hasPrivate() const {
return m_hasPrivate;
}
bool VariableTable::hasNonStaticPrivate() const {
return m_hasNonStaticPrivate;
}
void VariableTable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (Option::GenerateInferredTypes) {
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
Symbol *sym = m_symbolVec[i];
if (isInherited(sym->getName())) continue;
if (sym->isParameter()) {
cg_printf("// @param ");
} else if (sym->isGlobal()) {
cg_printf("// @global ");
} else if (sym->isStatic()) {
cg_printf("// @static ");
} else {
cg_printf("// @local ");
}
cg_printf("%s\t$%s\n", sym->getFinalType()->toString().c_str(),
sym->getName().c_str());
}
}
if (Option::ConvertSuperGlobals && !getAttribute(ContainsDynamicVariable)) {
std::set<string> convertibles;
typedef std::pair<const string,Symbol> symPair;
BOOST_FOREACH(symPair &sym, m_symbolMap) {
if (sym.second.isSuperGlobal() && !sym.second.declarationSet()) {
convertibles.insert(sym.second.getName());
}
}
if (!convertibles.empty()) {
cg_printf("/* converted super globals */ global ");
for (std::set<string>::const_iterator iter = convertibles.begin();
iter != convertibles.end(); ++iter) {
if (iter != convertibles.begin()) cg_printf(",");
cg_printf("$%s", iter->c_str());
}
cg_printf(";\n");
}
}
}
static bool by_location(const VariableTable::StaticGlobalInfoPtr &p1,
const VariableTable::StaticGlobalInfoPtr &p2) {
ConstructRawPtr d1 = p1->sym->getDeclaration();
ConstructRawPtr d2 = p2->sym->getDeclaration();
if (!d1) return !!d2;
if (!d2) return false;
return d1->getLocation()->compare(d2->getLocation().get()) < 0;
}
void VariableTable::canonicalizeStaticGlobals() {
assert(m_staticGlobals.empty());
sort(m_staticGlobalsVec.begin(), m_staticGlobalsVec.end(), by_location);
for (unsigned int i = 0; i < m_staticGlobalsVec.size(); i++) {
StaticGlobalInfoPtr &sgi = m_staticGlobalsVec[i];
if (!sgi->sym->getDeclaration()) continue;
string id = StaticGlobalInfo::GetId(sgi->cls, sgi->func,
sgi->sym->getName());
assert(m_staticGlobals.find(id) == m_staticGlobals.end());
m_staticGlobals[id] = sgi;
}
}
// Make sure GlobalVariables::getRefByIdx has the correct indices
void VariableTable::checkSystemGVOrder(SymbolSet &variants,
unsigned int max) {
always_assert(variants.size() >= max &&
BuiltinSymbols::NumGlobalNames());
unsigned int i = 0;
for (SymbolSet::const_iterator iterName = variants.begin();
iterName != variants.end(); ++iterName) {
string s = string("gvm_") + BuiltinSymbols::GlobalNames[i];
always_assert(s == iterName->c_str());
i++;
}
}
///////////////////////////////////////////////////////////////////////////////
}
+356
Ver Arquivo
@@ -0,0 +1,356 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_VARIABLE_TABLE_H_
#define incl_HPHP_VARIABLE_TABLE_H_
#include "hphp/compiler/analysis/symbol_table.h"
#include "hphp/compiler/statement/statement.h"
#include "hphp/compiler/analysis/class_scope.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
DECLARE_BOOST_TYPES(ModifierExpression);
DECLARE_BOOST_TYPES(CodeError);
DECLARE_BOOST_TYPES(VariableTable);
DECLARE_BOOST_TYPES(Expression);
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(FunctionScope);
/**
* These are the only places that a new variable can be declared:
*
* variable = expr|variable|new obj(...)
* static_var_list: T_STATIC T_VARIABLE = static_scalar,...
* class_variable_declaration: class { T_VARIABLE = static_scalar,...}
* T_LIST (variable, T_LIST(...), ...) = ...
* try {...} catch (T obj) {...}
* extract(name_value_pair)
*/
class VariableTable : public SymbolTable {
friend class AssignmentExpression;
public:
enum Attribute {
ContainsDynamicVariable = 1,
ContainsLDynamicVariable = ContainsDynamicVariable | 2,
ContainsExtract = 4,
ContainsCompact = 8,
InsideStaticStatement = 16,
InsideGlobalStatement = 32,
ForceGlobal = 64,
ContainsUnset = 128,
NeedGlobalPointer = 256,
ContainsDynamicStatic = 512,
ContainsGetDefinedVars = 1024,
ContainsDynamicFunctionCall = 2048,
};
enum JumpTableType {
JumpReturn,
JumpSet,
JumpInitialized,
JumpInitializedString,
JumpIndex,
JumpReturnString
};
enum JumpTableName {
JumpTableGlobalGetImpl,
JumpTableGlobalExists,
JumpTableGlobalGetIndex,
JumpTableLocalGetImpl,
JumpTableLocalExists,
};
enum AlteredVarClass {
NonPrivateNonStaticVars = 1,
NonPrivateStaticVars = 2,
PrivateNonStaticVars = 4,
PrivateStaticVars = 8,
AnyNonStaticVars = NonPrivateNonStaticVars | PrivateNonStaticVars,
AnyStaticVars = NonPrivateStaticVars | PrivateStaticVars,
AnyNonPrivateVars = NonPrivateNonStaticVars | NonPrivateStaticVars,
AnyPrivateVars = PrivateNonStaticVars | PrivateStaticVars,
AnyVars = AnyStaticVars | AnyNonStaticVars
};
static int GetVarClassMask(bool privates, bool statics) {
return (statics ? 2 : 1) << (privates ? 2 : 0);
}
static int GetVarClassMaskForSym(const Symbol *sym) {
return GetVarClassMask(sym->isPrivate(), sym->isStatic());
}
public:
explicit VariableTable(BlockScope &blockScope);
/**
* Get/set attributes.
*/
void setAttribute(Attribute attr) { m_attribute |= attr;}
void clearAttribute(Attribute attr) { m_attribute &= ~attr;}
bool getAttribute(Attribute attr) const {
return (m_attribute & attr) == attr;
}
bool isParameter(const std::string &name) const;
bool isPublic(const std::string &name) const;
bool isProtected(const std::string &name) const;
bool isPrivate(const std::string &name) const;
bool isStatic(const std::string &name) const;
bool isGlobal(const std::string &name) const;
bool isSuperGlobal(const std::string &name) const;
bool isLocal(const std::string &name) const;
bool isLocal(const Symbol *sym) const;
bool isRedeclared(const std::string &name) const;
bool isLocalGlobal(const std::string &name) const;
bool isNestedStatic(const std::string &name) const;
bool isLvalParam(const std::string &name) const;
bool isUsed(const std::string &name) const;
bool isNeeded(const std::string &name) const;
bool needLocalCopy(const Symbol *sym) const;
bool needLocalCopy(const std::string &name) const;
bool needGlobalPointer() const;
bool isPseudoMainTable() const;
bool hasPrivate() const;
bool hasNonStaticPrivate() const;
bool hasStatic() const { return m_hasStatic; }
virtual bool isInherited(const std::string &name) const;
void getLocalVariableNames(std::vector<std::string> &syms) const;
/**
* Get all variable's names.
*/
void getNames(std::set<std::string> &names,
bool collectPrivate = true) const;
Symbol *addSymbol(const std::string &name) {
return genSymbol(name, false);
}
Symbol *addDeclaredSymbol(const std::string &name, ConstructPtr construct) {
return genSymbol(name, false, construct);
}
/**
* Add a function's parameter to this table.
*/
TypePtr addParam(const std::string &name, TypePtr type,
AnalysisResultConstPtr ar, ConstructPtr construct);
TypePtr addParamLike(const std::string &name, TypePtr type,
AnalysisResultPtr ar, ConstructPtr construct,
bool firstPass);
/**
* Called when a variable is declared or being assigned (l-value).
*/
TypePtr add(const std::string &name, TypePtr type, bool implicit,
AnalysisResultConstPtr ar, ConstructPtr construct,
ModifierExpressionPtr modifiers);
TypePtr add(Symbol *sym, TypePtr type, bool implicit,
AnalysisResultConstPtr ar, ConstructPtr construct,
ModifierExpressionPtr modifiers);
/**
* Called to note whether a class variable overrides
* a definition in a base class. Returns whether or not there
* was an error in marking as override.
*/
bool markOverride(AnalysisResultPtr ar, const std::string &name);
/**
* Called when a variable is used or being evaluated (r-value).
*/
TypePtr checkVariable(const std::string &name, TypePtr type, bool coerce,
AnalysisResultConstPtr ar, ConstructPtr construct);
TypePtr checkVariable(Symbol *sym, TypePtr type, bool coerce,
AnalysisResultConstPtr ar, ConstructPtr construct);
/**
* Find the class which contains the property, and return
* its Symbol
*/
Symbol *findProperty(ClassScopePtr &cls,
const std::string &name,
AnalysisResultConstPtr ar);
/**
* Caller is responsible for grabbing a lock on this class scope,
* This function will be responsible for grabbing (and releasing)
* a lock on the parent scope if necessary.
*/
TypePtr checkProperty(BlockScopeRawPtr context,
Symbol *sym, TypePtr type,
bool coerce, AnalysisResultConstPtr ar);
/**
* Walk up to find first parent that has the specified symbol.
*/
ClassScopePtr findParent(AnalysisResultConstPtr ar,
const std::string &name,
const Symbol *&sym) const;
ClassScopePtr findParent(AnalysisResultConstPtr ar,
const std::string &name,
Symbol *&sym) {
const Symbol *ss;
ClassScopePtr p = findParent(ar, name, ss); // const version
sym = const_cast<Symbol*>(ss);
return p;
}
/**
* Called when analyze global and static statement.
*/
bool checkRedeclared(const std::string &name, Statement::KindOf kindOf);
void addLocalGlobal(const std::string &name);
void addNestedStatic(const std::string &name);
/**
* Helper for static variable default value
*/
ConstructPtr getStaticInitVal(std::string varName);
bool setStaticInitVal(std::string varName, ConstructPtr value);
/**
* Helper for class variable default value
*/
ConstructPtr getClassInitVal(std::string varName);
bool setClassInitVal(std::string varName, ConstructPtr value);
/**
* Called when analyze simple variable
*/
void addLvalParam(const std::string &name);
void addUsed(const std::string &name);
bool checkUnused(Symbol *sym);
void addNeeded(const std::string &name);
void clearUsed();
void addStaticVariable(Symbol *sym, AnalysisResultConstPtr ar,
bool member = false);
void addStaticVariable(Symbol *sym, AnalysisResultPtr ar,
bool member = false);
void cleanupForError(AnalysisResultConstPtr ar);
/**
* Set all matching variables to variants, since l-dynamic value was used.
*/
void forceVariants(AnalysisResultConstPtr ar, int varClass,
bool recur = true);
/**
* Set one matching variable to be Type::Variant.
*/
void forceVariant(AnalysisResultConstPtr ar, const std::string &name,
int varClass);
/**
* Keep track of $GLOBALS['var'].
*/
void addSuperGlobal(const std::string &name);
bool isConvertibleSuperGlobal(const std::string &name) const;
/**
* Canonicalize symbol order of static globals.
*/
void canonicalizeStaticGlobals();
/**
* Generate all variable declarations for this symbol table.
*/
void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* Whether or not the specified jump table is empty.
*/
bool hasAllJumpTables() const {
return m_emptyJumpTables.empty();
}
bool hasJumpTable(JumpTableName name) const {
return m_emptyJumpTables.find(name) == m_emptyJumpTables.end();
}
/**
* These are static variables collected from different local scopes,
* as they have to be turned into global variables defined in
* GlobalVariables class to make ThreadLocal<GlobalVaribles> work.
* This data structure is only needed by global scope.
*/
DECLARE_BOOST_TYPES(StaticGlobalInfo);
struct StaticGlobalInfo {
Symbol *sym;
VariableTable *variables; // where this variable was from
ClassScopeRawPtr cls; // these need to be raw to avoid reference cycles
FunctionScopeRawPtr func;
// get unique identifier for this variable
static std::string GetId(ClassScopePtr cls,
FunctionScopePtr func, const std::string &name);
};
bool hasStaticLocals() const { return !m_staticLocalsVec.empty(); }
private:
enum StaticSelection {
NonStatic = 1,
Static = 2,
EitherStatic = 3
};
enum PrivateSelection {
NonPrivate = 1,
Private = 2,
EitherPrivate = 3
};
int m_attribute;
int m_nextParam;
unsigned m_hasGlobal : 1;
unsigned m_hasStatic : 1;
unsigned m_hasPrivate : 1;
unsigned m_hasNonStaticPrivate : 1;
unsigned m_forcedVariants : 4;
std::set<JumpTableName> m_emptyJumpTables;
StaticGlobalInfoPtrVec m_staticGlobalsVec;
StringToStaticGlobalInfoPtrMap m_staticGlobals;
/** static symbols local to this variable table (ie for closures) */
SymbolVec m_staticLocalsVec;
bool isGlobalTable(AnalysisResultConstPtr ar) const;
virtual TypePtr setType(AnalysisResultConstPtr ar, const std::string &name,
TypePtr type, bool coerce);
virtual TypePtr setType(AnalysisResultConstPtr ar, Symbol *sym,
TypePtr type, bool coerce);
virtual void dumpStats(std::map<std::string, int> &typeCounts);
void checkSystemGVOrder(SymbolSet &variants, unsigned int max);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_VARIABLE_TABLE_H_
+489
Ver Arquivo
@@ -0,0 +1,489 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/builtin_symbols.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/statement/statement_list.h"
#include "hphp/compiler/analysis/type.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/expression/modifier_expression.h"
#include "hphp/compiler/expression/simple_function_call.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/parser/parser.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/constant_table.h"
#include "hphp/util/parser/hphp.tab.hpp"
#include "hphp/runtime/base/class_info.h"
#include "hphp/runtime/base/program_functions.h"
#include "hphp/runtime/base/array/array_iterator.h"
#include "hphp/runtime/base/execution_context.h"
#include "hphp/runtime/base/thread_init_fini.h"
#include "hphp/util/logger.h"
#include "hphp/util/util.h"
#include <dlfcn.h>
using namespace HPHP;
#define BF_COLUMN_COUNT 3
#define BF_COLUMN_NAME 0
#define BF_COLUMN_RETURN 1
#define BF_COLUMN_PARAMS 2
#define CLASS_TYPE 999
///////////////////////////////////////////////////////////////////////////////
bool BuiltinSymbols::Loaded = false;
StringBag BuiltinSymbols::s_strings;
StringToFunctionScopePtrMap BuiltinSymbols::s_functions;
const char *const BuiltinSymbols::GlobalNames[] = {
"HTTP_RAW_POST_DATA",
"_COOKIE",
"_ENV",
"_FILES",
"_GET",
"_POST",
"_REQUEST",
"_SERVER",
"_SESSION",
"argc",
"argv",
"http_response_header",
};
const char *BuiltinSymbols::SystemClasses[] = {
"stdclass",
"exception",
"arrayaccess",
"iterator",
"collections",
"reflection",
"splobjectstorage",
"directory",
"splfile",
"debugger",
"xhprof",
"directoryiterator",
"soapfault",
"fbmysqllexer",
nullptr
};
StringToClassScopePtrMap BuiltinSymbols::s_classes;
VariableTablePtr BuiltinSymbols::s_variables;
ConstantTablePtr BuiltinSymbols::s_constants;
StringToTypePtrMap BuiltinSymbols::s_superGlobals;
AnalysisResultPtr BuiltinSymbols::s_systemAr;
void *BuiltinSymbols::s_handle_main = nullptr;
///////////////////////////////////////////////////////////////////////////////
int BuiltinSymbols::NumGlobalNames() {
return sizeof(BuiltinSymbols::GlobalNames) /
sizeof(BuiltinSymbols::GlobalNames[0]);
}
static TypePtr typePtrFromDataType(DataType dt, TypePtr unknown) {
switch (dt) {
case KindOfNull: return Type::Null;
case KindOfBoolean: return Type::Boolean;
case KindOfInt64: return Type::Int64;
case KindOfDouble: return Type::Double;
case KindOfString: return Type::String;
case KindOfArray: return Type::Array;
case KindOfObject: return Type::Object;
case KindOfUnknown:
default:
return unknown;
}
}
FunctionScopePtr BuiltinSymbols::ImportFunctionScopePtr(AnalysisResultPtr ar,
ClassInfo *cls, ClassInfo::MethodInfo *method) {
int attrs = method->attribute;
bool isMethod = cls != ClassInfo::GetSystem();
FunctionScopePtr f(new FunctionScope(isMethod,
method->name.data(),
attrs & ClassInfo::IsReference));
int reqCount = 0, totalCount = 0;
for(auto it = method->parameters.begin();
it != method->parameters.end(); ++it) {
const ClassInfo::ParameterInfo *pinfo = *it;
if (!pinfo->value || !pinfo->value[0]) {
++reqCount;
}
++totalCount;
}
f->setParamCounts(ar, reqCount, totalCount);
int idx = 0;
for(auto it = method->parameters.begin();
it != method->parameters.end(); ++it, ++idx) {
const ClassInfo::ParameterInfo *pinfo = *it;
f->setParamName(idx, pinfo->name);
if (pinfo->attribute & ClassInfo::IsReference) {
f->setRefParam(idx);
}
f->setParamType(ar, idx, typePtrFromDataType(pinfo->argType, Type::Any));
if (pinfo->valueLen) {
f->setParamDefault(idx, pinfo->value, pinfo->valueLen,
std::string(pinfo->valueText, pinfo->valueTextLen));
}
}
if (method->returnType != KindOfNull) {
f->setReturnType(ar, typePtrFromDataType(method->returnType,
Type::Variant));
}
f->setClassInfoAttribute(attrs);
if (attrs & ClassInfo::HasDocComment) {
f->setDocComment(method->docComment);
}
if (!isMethod && (attrs & ClassInfo::HasOptFunction)) {
// Legacy optimization functions
if (method->name.same("fb_call_user_func_safe") ||
method->name.same("fb_call_user_func_safe_return") ||
method->name.same("fb_call_user_func_array_safe")) {
f->setOptFunction(hphp_opt_fb_call_user_func);
} else if (method->name.same("is_callable")) {
f->setOptFunction(hphp_opt_is_callable);
} else if (method->name.same("call_user_func_array")) {
f->setOptFunction(hphp_opt_call_user_func);
}
}
if (isMethod) {
if (attrs & ClassInfo::IsProtected) {
f->addModifier(T_PROTECTED);
} else if (attrs & ClassInfo::IsPrivate) {
f->addModifier(T_PRIVATE);
}
if (attrs & ClassInfo::IsStatic) {
f->addModifier(T_STATIC);
}
}
// This block of code is not needed, if BlockScope directly takes flags.
if (attrs & ClassInfo::MixedVariableArguments) {
f->setVariableArgument(-1);
} else if (attrs & ClassInfo::RefVariableArguments) {
f->setVariableArgument(1);
} else if (attrs & ClassInfo::VariableArguments) {
f->setVariableArgument(0);
}
if (attrs & ClassInfo::NoEffect) {
f->setNoEffect();
}
if (attrs & ClassInfo::FunctionIsFoldable) {
f->setIsFoldable();
}
if (attrs & ClassInfo::ContextSensitive) {
f->setContextSensitive(true);
}
if (attrs & ClassInfo::NeedsActRec) {
f->setNeedsActRec();
}
if ((attrs & ClassInfo::AllowOverride) && !isMethod) {
f->setAllowOverride();
}
FunctionScope::RecordFunctionInfo(f->getName(), f);
return f;
}
void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar,
StringToFunctionScopePtrMap &map,
ClassInfo *cls) {
const ClassInfo::MethodVec &methods = cls->getMethodsVec();
for (auto it = methods.begin(); it != methods.end(); ++it) {
FunctionScopePtr f = ImportFunctionScopePtr(ar, cls, *it);
assert(!map[f->getName()]);
map[f->getName()] = f;
}
}
void BuiltinSymbols::ImportExtFunctions(AnalysisResultPtr ar,
FunctionScopePtrVec &vec,
ClassInfo *cls) {
const ClassInfo::MethodVec &methods = cls->getMethodsVec();
for (auto it = methods.begin(); it != methods.end(); ++it) {
FunctionScopePtr f = ImportFunctionScopePtr(ar, cls, *it);
vec.push_back(f);
}
}
void BuiltinSymbols::ImportExtProperties(AnalysisResultPtr ar,
VariableTablePtr dest,
ClassInfo *cls) {
ClassInfo::PropertyVec src = cls->getPropertiesVec();
for (auto it = src.begin(); it != src.end(); ++it) {
ClassInfo::PropertyInfo *pinfo = *it;
int attrs = pinfo->attribute;
ModifierExpressionPtr modifiers(
new ModifierExpression(BlockScopePtr(), LocationPtr()));
if (attrs & ClassInfo::IsPrivate) {
modifiers->add(T_PRIVATE);
} else if (attrs & ClassInfo::IsProtected) {
modifiers->add(T_PROTECTED);
}
if (attrs & ClassInfo::IsStatic) {
modifiers->add(T_STATIC);
}
dest->add(pinfo->name.data(),
typePtrFromDataType(pinfo->type, Type::Variant),
false, ar, ExpressionPtr(), modifiers);
}
}
void BuiltinSymbols::ImportExtConstants(AnalysisResultPtr ar,
ConstantTablePtr dest,
ClassInfo *cls) {
ClassInfo::ConstantVec src = cls->getConstantsVec();
for (auto it = src.begin(); it != src.end(); ++it) {
// We make an assumption that if the constant is a callback type
// (e.g. STDIN, STDOUT, STDERR) then it will return an Object.
// And that if it's deferred (SID, PHP_SAPI) it'll be a String.
ClassInfo::ConstantInfo *cinfo = *it;
dest->add(cinfo->name.data(),
cinfo->isDeferred() ?
(cinfo->isCallback() ? Type::Object : Type::String) :
typePtrFromDataType(cinfo->getValue().getType(), Type::Variant),
ExpressionPtr(), ar, ConstructPtr());
}
}
ClassScopePtr BuiltinSymbols::ImportClassScopePtr(AnalysisResultPtr ar,
ClassInfo *cls) {
FunctionScopePtrVec methods;
ImportExtFunctions(ar, methods, cls);
ClassInfo::InterfaceVec ifaces = cls->getInterfacesVec();
String parent = cls->getParentClass();
std::vector<std::string> stdIfaces;
if (!parent.empty() && (ifaces.empty() || ifaces[0] != parent)) {
stdIfaces.push_back(parent.data());
}
for (auto it = ifaces.begin(); it != ifaces.end(); ++it) {
stdIfaces.push_back(it->data());
}
ClassScopePtr cl(new ClassScope(ar, cls->getName().data(), parent.data(),
stdIfaces, methods));
for (uint i = 0; i < methods.size(); ++i) {
methods[i]->setOuterScope(cl);
}
ImportExtProperties(ar, cl->getVariables(), cls);
ImportExtConstants(ar, cl->getConstants(), cls);
int attrs = cls->getAttribute();
cl->setClassInfoAttribute(attrs);
if (attrs & ClassInfo::HasDocComment) {
cl->setDocComment(cls->getDocComment());
}
cl->setSystem();
return cl;
}
void BuiltinSymbols::ImportExtClasses(AnalysisResultPtr ar) {
const ClassInfo::ClassMap &classes = ClassInfo::GetClassesMap();
for (auto it = classes.begin(); it != classes.end(); ++it) {
ClassScopePtr cl = ImportClassScopePtr(ar, it->second);
assert(!s_classes[cl->getName()]);
s_classes[cl->getName()] = cl;
}
}
bool BuiltinSymbols::Load(AnalysisResultPtr ar) {
if (Loaded) return true;
Loaded = true;
if (g_context.isNull()) init_thread_locals();
ClassInfo::Load();
// load extension functions first, so system/php may call them
ImportExtFunctions(ar, s_functions, ClassInfo::GetSystem());
AnalysisResultPtr ar2 = AnalysisResultPtr(new AnalysisResult());
s_variables = VariableTablePtr(new VariableTable(*ar2.get()));
s_constants = ConstantTablePtr(new ConstantTable(*ar2.get()));
// load extension constants, classes and dynamics
ImportExtConstants(ar, s_constants, ClassInfo::GetSystem());
ImportExtClasses(ar);
Array constants = ClassInfo::GetSystemConstants();
LocationPtr loc(new Location);
for (ArrayIter it = constants.begin(); it; ++it) {
CVarRef key = it.first();
if (!key.isString()) continue;
std::string name = key.toCStrRef().data();
if (s_constants->getSymbol(name)) continue;
if (name == "true" || name == "false" || name == "null") continue;
CVarRef value = it.secondRef();
if (!value.isInitialized() || value.isObject()) continue;
ExpressionPtr e = Expression::MakeScalarExpression(ar2, ar2, loc, value);
TypePtr t =
value.isNull() ? Type::Null :
value.isBoolean() ? Type::Boolean :
value.isInteger() ? Type::Int64 :
value.isDouble() ? Type::Double :
value.isArray() ? Type::Array : Type::Variant;
s_constants->add(key.toCStrRef().data(), t, e, ar2, e);
}
s_variables = ar2->getVariables();
for (int i = 0, n = NumGlobalNames(); i < n; ++i) {
s_variables->add(GlobalNames[i], Type::Variant, false, ar,
ConstructPtr(), ModifierExpressionPtr());
}
s_constants->setDynamic(ar, "SID", true);
s_constants->setDynamic(ar, "PHP_SAPI", true);
// parse all PHP files under system/php
s_systemAr = ar = AnalysisResultPtr(new AnalysisResult());
ar->loadBuiltins();
string slib = get_systemlib();
Scanner scanner(slib.c_str(), slib.size(),
Option::GetScannerType(), "systemlib.php");
Compiler::Parser parser(scanner, "systemlib.php", ar);
if (!parser.parse()) {
Logger::Error("Unable to parse systemlib.php: %s",
parser.getMessage().c_str());
assert(false);
}
ar->analyzeProgram(true);
ar->inferTypes();
const StringToFileScopePtrMap &files = ar->getAllFiles();
for (StringToFileScopePtrMap::const_iterator iterFile = files.begin();
iterFile != files.end(); iterFile++) {
const StringToClassScopePtrVecMap &classes =
iterFile->second->getClasses();
for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin();
iter != classes.end(); ++iter) {
assert(iter->second.size() == 1);
iter->second[0]->setSystem();
assert(!s_classes[iter->first]);
s_classes[iter->first] = iter->second[0];
}
const StringToFunctionScopePtrMap &functions =
iterFile->second->getFunctions();
for (StringToFunctionScopePtrMap::const_iterator iter = functions.begin();
iter != functions.end(); ++iter) {
iter->second->setSystem();
s_functions[iter->first] = iter->second;
}
}
return true;
}
AnalysisResultPtr BuiltinSymbols::LoadGlobalSymbols(const char *fileName) {
AnalysisResultPtr ar(new AnalysisResult());
string phpBaseName = "/system/globals/";
phpBaseName += fileName;
string phpFileName = Option::GetSystemRoot() + phpBaseName;
const char *baseName = s_strings.add(phpBaseName.c_str());
fileName = s_strings.add(phpFileName.c_str());
try {
Scanner scanner(fileName, Option::GetScannerType());
Compiler::Parser parser(scanner, baseName, ar);
if (!parser.parse()) {
assert(false);
Logger::Error("Unable to parse file %s: %s", fileName,
parser.getMessage().c_str());
}
} catch (FileOpenException &e) {
Logger::Error("%s", e.getMessage().c_str());
}
ar->analyzeProgram(true);
ar->inferTypes();
return ar;
}
void BuiltinSymbols::LoadFunctions(AnalysisResultPtr ar,
StringToFunctionScopePtrMap &functions) {
assert(Loaded);
functions.insert(s_functions.begin(), s_functions.end());
}
void BuiltinSymbols::LoadClasses(AnalysisResultPtr ar,
StringToClassScopePtrMap &classes) {
assert(Loaded);
classes.insert(s_classes.begin(), s_classes.end());
}
void BuiltinSymbols::LoadVariables(AnalysisResultPtr ar,
VariableTablePtr variables) {
assert(Loaded);
if (s_variables) {
variables->import(s_variables);
}
}
void BuiltinSymbols::LoadConstants(AnalysisResultPtr ar,
ConstantTablePtr constants) {
assert(Loaded);
if (s_constants) {
constants->import(s_constants);
}
}
ConstantTablePtr BuiltinSymbols::LoadSystemConstants() {
AnalysisResultPtr ar = LoadGlobalSymbols("constants.php");
const auto &fileScopes = ar->getAllFilesVector();
if (!fileScopes.empty()) {
return fileScopes[0]->getConstants();
}
throw std::runtime_error("LoadSystemConstants failed");
}
void BuiltinSymbols::LoadSuperGlobals() {
if (s_superGlobals.empty()) {
s_superGlobals["_SERVER"] = Type::Variant;
s_superGlobals["_GET"] = Type::Variant;
s_superGlobals["_POST"] = Type::Variant;
s_superGlobals["_COOKIE"] = Type::Variant;
s_superGlobals["_FILES"] = Type::Variant;
s_superGlobals["_ENV"] = Type::Variant;
s_superGlobals["_REQUEST"] = Type::Variant;
s_superGlobals["_SESSION"] = Type::Variant;
s_superGlobals["http_response_header"] = Type::Variant;
}
}
bool BuiltinSymbols::IsSuperGlobal(const std::string &name) {
return s_superGlobals.find(name) != s_superGlobals.end();
}
TypePtr BuiltinSymbols::GetSuperGlobalType(const std::string &name) {
StringToTypePtrMap::const_iterator iter = s_superGlobals.find(name);
if (iter != s_superGlobals.end()) {
return iter->second;
}
return TypePtr();
}
+105
Ver Arquivo
@@ -0,0 +1,105 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_BUILTIN_SYMBOLS_H_
#define incl_HPHP_BUILTIN_SYMBOLS_H_
#include "hphp/compiler/hphp.h"
#include "hphp/util/string_bag.h"
#include "hphp/runtime/base/class_info.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
DECLARE_BOOST_TYPES(Type);
DECLARE_BOOST_TYPES(AnalysisResult);
DECLARE_BOOST_TYPES(FunctionScope);
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(VariableTable);
DECLARE_BOOST_TYPES(ConstantTable);
class BuiltinSymbols {
public:
static bool Loaded;
static bool Load(AnalysisResultPtr ar);
static void LoadFunctions(AnalysisResultPtr ar,
StringToFunctionScopePtrMap &functions);
static void LoadClasses(AnalysisResultPtr ar,
StringToClassScopePtrMap &classes);
static void LoadVariables(AnalysisResultPtr ar,
VariableTablePtr variables);
static void LoadConstants(AnalysisResultPtr ar,
ConstantTablePtr constants);
/*
* Load system/globals/constants.php.
*/
static ConstantTablePtr LoadSystemConstants();
/**
* Testing whether a variable is a PHP superglobal.
*/
static bool IsSuperGlobal(const std::string &name);
static TypePtr GetSuperGlobalType(const std::string &name);
static bool IsDeclaredDynamic(const std::string& name);
static void LoadSuperGlobals();
static StringToFunctionScopePtrMap s_functions;
static StringToClassScopePtrMap s_classes;
static VariableTablePtr s_variables;
static ConstantTablePtr s_constants;
static AnalysisResultPtr s_systemAr;
static const char *const GlobalNames[];
static int NumGlobalNames();
private:
static StringBag s_strings;
static const char *SystemClasses[];
static AnalysisResultPtr LoadGlobalSymbols(const char *fileName);
static StringToTypePtrMap s_superGlobals;
static std::set<std::string> s_declaredDynamic;
static void *s_handle_main;
static FunctionScopePtr ImportFunctionScopePtr(AnalysisResultPtr ar,
ClassInfo *cls,
ClassInfo::MethodInfo *method);
static void ImportExtFunctions(AnalysisResultPtr ar,
StringToFunctionScopePtrMap &map,
ClassInfo *cls);
static void ImportExtFunctions(AnalysisResultPtr ar,
FunctionScopePtrVec &vec,
ClassInfo *cls);
static void ImportExtProperties(AnalysisResultPtr ar,
VariableTablePtr dest,
ClassInfo *cls);
static void ImportExtConstants(AnalysisResultPtr ar,
ConstantTablePtr dest,
ClassInfo *cls);
static ClassScopePtr ImportClassScopePtr(AnalysisResultPtr ar,
ClassInfo *cls);
static void ImportExtClasses(AnalysisResultPtr ar);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_BUILTIN_SYMBOLS_H_
+426
Ver Arquivo
@@ -0,0 +1,426 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include <stdarg.h>
#include "hphp/compiler/code_generator.h"
#include "hphp/compiler/statement/statement_list.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/util/util.h"
#include "hphp/util/hash.h"
#include <boost/format.hpp>
#include <boost/scoped_array.hpp>
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// statics
void CodeGenerator::BuildJumpTable(const std::vector<const char *> &strings,
MapIntToStringVec &out, int tableSize,
bool caseInsensitive) {
assert(!strings.empty());
assert(out.empty());
assert(tableSize > 0);
for (unsigned int i = 0; i < strings.size(); i++) {
const char *s = strings[i];
int hash = (caseInsensitive ? hash_string_i(s) : hash_string(s)) %
tableSize;
out[hash].push_back(s);
}
}
const char *CodeGenerator::STARTER_MARKER =
"namespace hphp_impl_starter {}";
const char *CodeGenerator::SPLITTER_MARKER =
"namespace hphp_impl_splitter {}";
const char *CodeGenerator::HASH_INCLUDE =
"#include";
///////////////////////////////////////////////////////////////////////////////
CodeGenerator::CodeGenerator(std::ostream *primary,
Output output /* = PickledPHP */,
const std::string *filename /* = NULL */)
: m_out(nullptr), m_output(output),
m_context(NoContext), m_itemIndex(-1) {
for (int i = 0; i < StreamCount; i++) {
m_streams[i] = nullptr;
m_indentation[i] = 0;
m_indentPending[i] = true;
m_lineNo[i] = 1;
m_inComments[i] = 0;
m_wrappedExpression[i] = false;
m_inExpression[i] = false;
}
setStream(PrimaryStream, primary);
useStream(PrimaryStream);
if (filename) m_filename = *filename;
m_translatePredefined = false;
m_scalarVariant = false;
m_initListFirstElem = false;
m_inFileOrClassHeader = false;
m_inNamespace = false;
}
void CodeGenerator::useStream(Stream stream) {
assert(stream >= NullStream && stream < StreamCount);
m_curStream = stream;
if (stream == NullStream) {
m_out = nullptr;
} else {
m_out = m_streams[stream];
}
}
bool CodeGenerator::usingStream(Stream stream) {
assert(stream >= 0 && stream < StreamCount);
return m_out == m_streams[stream];
}
std::ostream *CodeGenerator::getStream(Stream stream) const {
assert(stream >= 0 && stream < StreamCount);
return m_streams[stream];
}
void CodeGenerator::setStream(Stream stream, std::ostream *out) {
assert(out);
assert(stream >= 0 && stream < StreamCount);
m_streams[stream] = out;
}
int CodeGenerator::getLineNo(Stream stream) const {
assert(stream >= 0 && stream < StreamCount);
return m_lineNo[stream];
}
///////////////////////////////////////////////////////////////////////////////
void CodeGenerator::printf(const char *fmt, ...) {
va_list ap; va_start(ap, fmt); print(fmt, ap); va_end(ap);
}
void CodeGenerator::indentBegin(const char *fmt, ...) {
va_list ap; va_start(ap, fmt); print(fmt, ap); va_end(ap);
m_indentation[m_curStream]++;
}
void CodeGenerator::indentBegin() {
m_indentation[m_curStream]++;
}
void CodeGenerator::indentEnd(const char *fmt, ...) {
assert(m_indentation[m_curStream]);
m_indentation[m_curStream]--;
va_list ap; va_start(ap, fmt); print(fmt, ap); va_end(ap);
}
void CodeGenerator::indentEnd() {
assert(m_indentation[m_curStream]);
m_indentation[m_curStream]--;
}
bool CodeGenerator::inComments() const {
return m_inComments[m_curStream] > 0;
}
void CodeGenerator::startComments() {
m_inComments[m_curStream]++;
printf(" /*");
}
void CodeGenerator::endComments() {
assert(m_inComments[m_curStream] > 0);
m_inComments[m_curStream]--;
printf(" */");
}
void CodeGenerator::printSection(const char *name, bool newline /* = true */) {
if (newline) printf("\n");
printf("// %s\n", name);
}
void CodeGenerator::printSeparator() {
printf("///////////////////////////////////////"
"////////////////////////////////////////\n");
}
void CodeGenerator::namespaceBegin() {
always_assert(!m_inNamespace);
m_inNamespace = true;
printf("\n");
printf("namespace HPHP {\n");
printSeparator();
printf("\n");
}
void CodeGenerator::namespaceEnd() {
always_assert(m_inNamespace);
m_inNamespace = false;
printf("\n");
printSeparator();
printf("}\n");
}
std::string CodeGenerator::getFormattedName(const std::string &file) {
char *fn = strdup(file.c_str());
int len = strlen(fn);
always_assert(len == (int)file.size());
for (int i = 0; i < len; i++) {
if (!isalnum(fn[i])) fn[i] = '_';
}
string formatted = fn;
free(fn);
int hash = hash_string(file.data(), file.size());
formatted += boost::str(boost::format("%08x") % hash);
return formatted;
}
bool CodeGenerator::ensureInNamespace() {
if (m_inNamespace) return false;
namespaceBegin();
return true;
}
bool CodeGenerator::ensureOutOfNamespace() {
if (!m_inNamespace) return false;
namespaceEnd();
return true;
}
void CodeGenerator::ifdefBegin(bool ifdef, const char *fmt, ...) {
printf(ifdef ? "#ifdef " : "#ifndef ");
va_list ap; va_start(ap, fmt); print(fmt, ap); va_end(ap);
printf("\n");
}
void CodeGenerator::ifdefEnd(const char *fmt, ...) {
printf("#endif // ");
va_list ap; va_start(ap, fmt); print(fmt, ap); va_end(ap);
printf("\n");
}
void CodeGenerator::printDocComment(const std::string comment) {
if (comment.empty()) return;
string escaped;
escaped.reserve(comment.size() + 10);
for (unsigned int i = 0; i < comment.size(); i++) {
char ch = comment[i];
escaped += ch;
if (ch == '/' && i > 1 && comment[i+1] == '*') {
escaped += '\\'; // splitting illegal /* into /\*
}
}
print(escaped.c_str(), false);
printf("\n");
}
std::string CodeGenerator::FormatLabel(const std::string &name) {
string ret;
ret.reserve(name.size());
for (size_t i = 0; i < name.size(); i++) {
unsigned char ch = name[i];
if ((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') || ch == '_') {
ret += ch;
} else {
char buf[10];
snprintf(buf, sizeof(buf), "%s%02X", Option::LabelEscape.c_str(),
(int)ch);
ret += buf;
}
}
return ret;
}
std::string CodeGenerator::EscapeLabel(const std::string &name,
bool *binary /* = NULL */) {
return Util::escapeStringForCPP(name, binary);
}
///////////////////////////////////////////////////////////////////////////////
// helpers
void CodeGenerator::print(const char *fmt, va_list ap) {
if (!m_out) return;
boost::scoped_array<char> buf;
bool done = false;
for (int len = 1024; !done; len <<= 1) {
va_list v;
va_copy(v, ap);
buf.reset(new char[len]);
if (vsnprintf(buf.get(), len, fmt, v) < len) done = true;
va_end(v);
}
print(buf.get());
}
void CodeGenerator::print(const char *msg, bool indent /* = true */) {
const char *start = msg;
int length = 1;
for (const char *iter = msg; ; ++iter, ++length) {
if (*iter == '\n') {
if (indent) {
// Only indent if it is pending and if it is not an empty line
if (m_indentPending[m_curStream] && length > 1) printIndent();
// Printing substrings requires an additional copy operation,
// so do it only if necessary
if (iter[1] != '\0') {
printSubstring(start, length);
} else {
*m_out << start;
}
start = iter + 1;
length = 0;
}
m_lineNo[m_curStream]++;
m_indentPending[m_curStream] = true;
} else if (*iter == '\0') {
// Perform print only in case what's left is not an empty string
if (length > 1) {
if (indent && m_indentPending[m_curStream]) {
printIndent();
m_indentPending[m_curStream] = false;
}
*m_out << start;
}
break;
}
}
}
void CodeGenerator::printSubstring(const char *start, int length) {
const int BUF_LEN = 0x100;
char buf[BUF_LEN];
while (length > 0) {
int curLength = std::min(length, BUF_LEN - 1);
memcpy(buf, start, curLength);
buf[curLength] = '\0';
*m_out << buf;
length -= curLength;
start += curLength;
}
}
void CodeGenerator::printIndent() {
for (int i = 0; i < m_indentation[m_curStream]; i++) {
*m_out << Option::Tab;
}
}
///////////////////////////////////////////////////////////////////////////////
int CodeGenerator::s_idLambda = 0;
string CodeGenerator::GetNewLambda() {
return Option::LambdaPrefix + "lambda_" +
boost::lexical_cast<string>(++s_idLambda);
}
void CodeGenerator::resetIdCount(const std::string &key) {
m_idCounters[key] = 0;
}
int CodeGenerator::createNewId(const std::string &key) {
return ++m_idCounters[key];
}
int CodeGenerator::createNewId(ConstructPtr cs) {
FileScopePtr fs = cs->getFileScope();
if (fs) {
return createNewId(fs->getName());
}
return createNewId("");
}
int CodeGenerator::createNewLocalId(ConstructPtr ar) {
if (m_wrappedExpression[m_curStream]) {
return m_localId[m_curStream]++;
}
FunctionScopePtr func = ar->getFunctionScope();
if (func) {
return func->nextInlineIndex();
}
FileScopePtr fs = ar->getFileScope();
if (fs) {
return createNewId(fs->getName());
}
return createNewId("");
}
void CodeGenerator::pushBreakScope(int labelId,
bool loopCounter /* = true */) {
m_breakScopes.push_back(labelId);
if (loopCounter) {
printf("LOOP_COUNTER(%d);\n", int(labelId & ~BreakScopeBitMask));
}
}
void CodeGenerator::popBreakScope() {
m_breakScopes.pop_back();
if (m_breakScopes.size() == 0) {
m_breakLabelIds.clear();
m_contLabelIds.clear();
}
}
void CodeGenerator::pushCallInfo(int cit) {
m_callInfos.push_back(cit);
}
void CodeGenerator::popCallInfo() {
m_callInfos.pop_back();
}
int CodeGenerator::callInfoTop() {
if (m_callInfos.empty()) return -1;
return m_callInfos.back();
}
void CodeGenerator::addLabelId(const char *name, int labelId) {
if (!strcmp(name, "break")) {
m_breakLabelIds.insert(labelId);
} else if (!strcmp(name, "continue")) {
m_contLabelIds.insert(labelId);
} else {
assert(false);
}
}
bool CodeGenerator::findLabelId(const char *name, int labelId) {
if (!strcmp(name, "break")) {
return m_breakLabelIds.find(labelId) != m_breakLabelIds.end();
} else if (!strcmp(name, "continue")) {
return m_contLabelIds.find(labelId) != m_contLabelIds.end();
} else {
assert(false);
}
return false;
}
int CodeGenerator::ClassScopeCompare::cmp(const ClassScopeRawPtr &p1,
const ClassScopeRawPtr &p2) const {
int d = p1->getRedeclaringId() - p2->getRedeclaringId();
if (d) return d;
return strcasecmp(p1->getName().c_str(), p2->getName().c_str());
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __CODE_GENERATOR_H__
#define __CODE_GENERATOR_H__
#ifndef incl_HPHP_CODE_GENERATOR_H_
#define incl_HPHP_CODE_GENERATOR_H_
#include <compiler/hphp.h>
#include "hphp/compiler/hphp.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -131,8 +131,8 @@ public:
public:
CodeGenerator() {} // only for creating a dummy code generator
CodeGenerator(std::ostream *primary, Output output = PickledPHP,
const std::string *filename = NULL);
explicit CodeGenerator(std::ostream *primary, Output output = PickledPHP,
const std::string *filename = nullptr);
/**
* ...if it was passed in from constructor.
@@ -163,17 +163,6 @@ public:
void indentEnd(const char *fmt, ...) ATTRIBUTE_PRINTF(2,3);
void indentEnd();
void printRaw(const char *msg) { print(msg, false);}
bool wrapExpressionBegin();
bool wrapExpressionEnd();
void genReferenceTemp(ConstructPtr scope);
void clearRefereceTemp() { m_referenceTemps[m_curStream].clear(); }
const std::string &getReferenceTemp();
bool hasReferenceTemp() const {
return !m_referenceTemps[m_curStream].empty();
}
void setReferenceTempUsed(bool flag) {
m_referenceTempsUsed[m_curStream] = flag;
}
/**
* Pre-formatted outputs.
*/
@@ -183,20 +172,12 @@ public:
void namespaceEnd();
bool ensureInNamespace();
bool ensureOutOfNamespace();
void headerBegin(const std::string &file);
void headerEnd(const std::string &file);
void ifdefBegin(bool ifdef, const char *fmt, ...) ATTRIBUTE_PRINTF(3,4);
void ifdefEnd(const char *fmt, ...) ATTRIBUTE_PRINTF(2,3);
void printInclude(const std::string &file);
void printBasicIncludes();
void printDeclareGlobals();
void printStartOfJumpTable(int tableSize);
void printDocComment(const std::string comment);
void printImplStarter(); // end of includes
void printImplSplitter(); // marker to split .cpp into smaller files
const char *getGlobals(AnalysisResultPtr ar);
static std::string FormatLabel(const std::string &name);
static std::string EscapeLabel(const std::string &name, bool *binary = NULL);
static std::string EscapeLabel(const std::string &name, bool *binary = nullptr);
/**
* Make sure PHP variables, functions and typenames are unique and
@@ -268,31 +249,13 @@ public:
m_loopStatement = loop;
}
void setInsideScalarArray(bool flag);
bool getInsideScalarArray();
void setFileOrClassHeader(bool value) { m_inFileOrClassHeader = value; }
bool isFileOrClassHeader() { return m_inFileOrClassHeader; }
void beginHoistedClasses();
void endHoistedClasses();
void collectHoistedClasses(bool flag);
void addHoistedClass(const std::string &cls);
bool checkHoistedClass(const std::string &cls);
void setScalarVariant() { m_scalarVariant = true; }
bool hasScalarVariant() { return m_scalarVariant; }
void clearScalarVariant() { m_scalarVariant = false; }
void setInitListFirstElem() { m_initListFirstElem = true; }
bool hasInitListFirstElem() { return m_initListFirstElem; }
void clearInitListFirstElem() { m_initListFirstElem = false; }
const StringToClassScopePtrVecMap &getClasses() const { return m_classes; }
void addClass(const std::string &name, ClassScopePtr cls) {
m_classes[name].push_back(cls);
}
void clearClasses() { m_classes.clear(); }
bool insertDeclaredClosure(const FunctionScope *f) {
return m_declaredClosures.insert(f).second;
}
@@ -321,8 +284,6 @@ private:
bool m_inFileOrClassHeader;
bool m_inNamespace;
int m_localId[StreamCount];
std::set<std::string, stdltistr> *m_hoistedClasses;
bool m_collectHoistedClasses;
static int s_idLambda;
std::map<std::string, int> m_idCounters;
@@ -332,7 +293,6 @@ private:
std::set<int> m_contLabelIds; // continue labels referenced
std::deque<int> m_callInfos;
LoopStatementPtr m_loopStatement;
bool m_insideScalarArray;
StringToClassScopePtrVecMap m_classes;
std::set<const FunctionScope*> m_declaredClosures;
FileScopeRawPtr m_literalScope;
@@ -348,28 +308,23 @@ private:
public: void print(const char *msg, bool indent = true);
private:
void print(const char *fmt, va_list ap);
void print(const char *fmt, va_list ap) ATTRIBUTE_PRINTF(2,0);
void printSubstring(const char *start, int length);
void printIndent();
std::string getFormattedName(const std::string &file);
};
#define STR(x) #x
#define XSTR(x) STR(x)
#define FLANN(stream,func,nl) (Option::FlAnnotate ? \
stream.printf("/* %s:" XSTR(__LINE__) "*/" nl, __func__): \
void()), stream.func
#define cg_printf FLANN(cg,printf,"")
#define m_cg_printf FLANN(m_cg,printf,"")
#define cg_print FLANN(cg,print,"")
#define m_cg_print FLANN(m_cg,print,"")
#define cg_indentBegin FLANN(cg,indentBegin,"")
#define m_cg_indentBegin FLANN(m_cg,indentBegin,"")
#define cg_indentEnd FLANN(cg,indentEnd,"")
#define m_cg_indentEnd FLANN(m_cg,indentEnd,"")
#define cg_printInclude FLANN(cg,printInclude,"\n")
#define cg_printString FLANN(cg,printString,"")
#define cg_printf cg.printf
#define m_cg_printf m_cg.printf
#define cg_print cg.print
#define m_cg_print m_cg.print
#define cg_indentBegin cg.indentBegin
#define m_cg_indentBegin m_cg.indentBegin
#define cg_indentEnd cg.indentEnd
#define m_cg_indentEnd cg.indentEnd
#define cg_printInclude cg.printInclude
#define cg_printString cg.printString
///////////////////////////////////////////////////////////////////////////////
}
#endif // __CODE_GENERATOR_H__
#endif // incl_HPHP_CODE_GENERATOR_H_
+959
Ver Arquivo
@@ -0,0 +1,959 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/compiler.h"
#include "hphp/compiler/package.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/alias_manager.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/emitter.h"
#include "hphp/compiler/analysis/type.h"
#include "hphp/compiler/analysis/symbol_table.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/parser/parser.h"
#include "hphp/compiler/builtin_symbols.h"
#include "hphp/util/json.h"
#include "hphp/util/logger.h"
#include "hphp/util/db_conn.h"
#include "hphp/util/exception.h"
#include "hphp/util/process.h"
#include "hphp/util/util.h"
#include "hphp/util/timer.h"
#include "hphp/util/hdf.h"
#include "hphp/util/async_func.h"
#include "hphp/runtime/base/program_functions.h"
#include "hphp/runtime/base/memory/smart_allocator.h"
#include "hphp/runtime/base/externals.h"
#include "hphp/runtime/base/thread_init_fini.h"
#include "hphp/runtime/vm/repo.h"
#include "hphp/system/systemlib.h"
#include "hphp/util/repo_schema.h"
#include "hphp/hhvm/process_init.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <dlfcn.h>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/parsers.hpp>
using namespace boost::program_options;
using std::cout;
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
struct CompilerOptions {
string target;
string format;
string outputDir;
string syncDir;
vector<string> config;
string configDir;
vector<string> confStrings;
string inputDir;
vector<string> inputs;
string inputList;
vector<string> includePaths;
vector<string> modules;
vector<string> excludeDirs;
vector<string> excludeFiles;
vector<string> excludePatterns;
vector<string> excludeStaticDirs;
vector<string> excludeStaticFiles;
vector<string> excludeStaticPatterns;
vector<string> fmodules;
vector<string> ffiles;
vector<string> cfiles;
vector<string> cmodules;
bool parseOnDemand;
string program;
string programArgs;
string branch;
int revision;
bool genStats;
bool keepTempDir;
string dbStats;
bool noTypeInference;
int logLevel;
bool force;
int optimizeLevel;
string filecache;
bool dump;
string docjson;
bool coredump;
bool nofork;
string optimizations;
};
///////////////////////////////////////////////////////////////////////////////
class AsyncFileCacheSaver : public AsyncFunc<AsyncFileCacheSaver> {
public:
AsyncFileCacheSaver(Package *package, const char *name)
: AsyncFunc<AsyncFileCacheSaver>(this, &AsyncFileCacheSaver::saveCache),
m_package(package), m_name(name) {
}
void saveCache() {
Timer timer(Timer::WallTime, "saving file cache...");
m_package->getFileCache()->save(m_name);
struct stat sb;
stat(m_name, &sb);
Logger::Info("%" PRId64" MB %s saved",
(int64_t)sb.st_size/(1024*1024), m_name);
}
private:
Package *m_package;
const char *m_name;
};
///////////////////////////////////////////////////////////////////////////////
// forward declarations
int prepareOptions(CompilerOptions &po, int argc, char **argv);
void createOutputDirectory(CompilerOptions &po);
int process(const CompilerOptions &po);
int lintTarget(const CompilerOptions &po);
int analyzeTarget(const CompilerOptions &po, AnalysisResultPtr ar);
int phpTarget(const CompilerOptions &po, AnalysisResultPtr ar);
void hhbcTargetInit(const CompilerOptions &po, AnalysisResultPtr ar);
int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
AsyncFileCacheSaver &fcThread);
int runTargetCheck(const CompilerOptions &po, AnalysisResultPtr ar,
AsyncFileCacheSaver &fcThread);
int runTarget(const CompilerOptions &po);
///////////////////////////////////////////////////////////////////////////////
extern "C" void compiler_hook_initialize();
int compiler_main(int argc, char **argv) {
try {
Hdf empty;
RuntimeOption::Load(empty);
initialize_repo();
// we need to initialize pcre cache table very early
pcre_init();
CompilerOptions po;
#ifdef FACEBOOK
compiler_hook_initialize();
#endif
int ret = prepareOptions(po, argc, argv);
if (ret == 1) return 0; // --help
if (ret == -1) return -1; // command line error
Timer totalTimer(Timer::WallTime, "running hphp");
createOutputDirectory(po);
if (ret == 0) {
if (!po.nofork && !Process::IsUnderGDB()) {
int pid = fork();
if (pid == 0) {
ret = process(po);
_exit(ret);
}
wait(&ret);
ret = WIFEXITED(ret) ? WEXITSTATUS(ret) : -1;
} else {
ret = process(po);
}
}
if (ret == 0) {
if (po.target == "run") {
ret = runTarget(po);
}
}
if (ret) {
Logger::Error("hphp failed");
} else {
Logger::Info("all files saved in %s ...", po.outputDir.c_str());
}
return ret;
} catch (Exception &e) {
Logger::Error("Exception: %s\n", e.getMessage().c_str());
} catch (const FailedAssertion& fa) {
fa.print();
StackTraceNoHeap::AddExtraLogging("Assertion failure", fa.summary);
abort();
} catch (std::exception &e) {
Logger::Error("std::exception: %s\n", e.what());
} catch (...) {
Logger::Error("(unknown exception was thrown)\n");
}
return -1;
}
///////////////////////////////////////////////////////////////////////////////
int prepareOptions(CompilerOptions &po, int argc, char **argv) {
options_description desc("HipHop Compiler for PHP Usage:\n\n"
"\thphp <options> <inputs>\n\n"
"Options");
desc.add_options()
("help", "display this message")
("version", "display version number")
("target,t", value<string>(&po.target)->default_value("run"),
"lint | "
"analyze | "
"php | "
"hhbc | "
"filecache | "
"run (default)")
("format,f", value<string>(&po.format),
"lint: (none); \n"
"analyze: (none); \n"
"php: trimmed (default) | inlined | pickled | typeinfo |"
" <any combination of them by any separator>; \n"
"hhbc: binary (default) | text; \n"
"run: cluster (default) | file")
("input-dir", value<string>(&po.inputDir), "input directory")
("program", value<string>(&po.program)->default_value("program"),
"final program name to use")
("args", value<string>(&po.programArgs), "program arguments")
("inputs,i", value<vector<string> >(&po.inputs), "input file names")
("input-list", value<string>(&po.inputList),
"file containing list of file names, one per line")
("include-path",
value<vector<string> >(&po.includePaths)->composing(),
"a list of full paths to search for files being included in includes "
"or requires but cannot be found assuming relative paths")
("module", value<vector<string> >(&po.modules)->composing(),
"directories containing all input files")
("exclude-dir", value<vector<string> >(&po.excludeDirs)->composing(),
"directories to exclude from the input")
("fmodule", value<vector<string> >(&po.fmodules)->composing(),
"same with module, except no exclusion checking is performed, so these "
"modules are forced to be included")
("ffile", value<vector<string> >(&po.ffiles)->composing(),
"extra PHP files forced to include without exclusion checking")
("exclude-file", value<vector<string> >(&po.excludeFiles)->composing(),
"files to exclude from the input, even if parse-on-demand finds it")
("exclude-pattern",
value<vector<string> >(&po.excludePatterns)->composing(),
"regex (in 'find' command's regex command line option format) of files "
"or directories to exclude from the input, even if parse-on-demand finds "
"it")
("exclude-static-pattern",
value<vector<string> >(&po.excludeStaticPatterns)->composing(),
"regex (in 'find' command's regex command line option format) of files "
"or directories to exclude from static content cache")
("exclude-static-dir",
value<vector<string> >(&po.excludeStaticDirs)->composing(),
"directories to exclude from static content cache")
("exclude-static-file",
value<vector<string> >(&po.excludeStaticFiles)->composing(),
"files to exclude from static content cache")
("cfile", value<vector<string> >(&po.cfiles)->composing(),
"extra static files forced to include without exclusion checking")
("cmodule", value<vector<string> >(&po.cmodules)->composing(),
"extra directories for static files without exclusion checking")
("parse-on-demand", value<bool>(&po.parseOnDemand)->default_value(true),
"whether to parse files that are not specified from command line")
("branch", value<string>(&po.branch), "SVN branch")
("revision", value<int>(&po.revision), "SVN revision")
("output-dir,o", value<string>(&po.outputDir), "output directory")
("sync-dir", value<string>(&po.syncDir),
"Files will be created in this directory first, then sync with output "
"directory without overwriting identical files. Great for incremental "
"compilation and build.")
("optimize-level", value<int>(&po.optimizeLevel)->default_value(-1),
"optimization level")
("gen-stats", value<bool>(&po.genStats)->default_value(false),
"whether to generate code errors")
("keep-tempdir,k", value<bool>(&po.keepTempDir)->default_value(false),
"whether to keep the temporary directory")
("db-stats", value<string>(&po.dbStats),
"database connection string to save code errors: "
"<username>:<password>@<host>:<port>/<db>")
("no-type-inference",
value<bool>(&po.noTypeInference)->default_value(false),
"turn off type inference for C++ code generation")
("config,c", value<vector<string> >(&po.config)->composing(),
"config file name")
("config-dir", value<string>(&po.configDir),
"root directory configuration is based on (for example, "
"excluded directories may be relative path in configuration.")
("config-value,v", value<vector<string> >(&po.confStrings)->composing(),
"individual configuration string in a format of name=value, where "
"name can be any valid configuration for a config file")
("log,l",
value<int>(&po.logLevel)->default_value(-1),
"-1: (default); 0: no logging; 1: errors only; 2: warnings and errors; "
"3: informational as well; 4: really verbose.")
("force",
value<bool>(&po.force)->default_value(true),
"force to ignore code generation errors and continue compilations")
("file-cache",
value<string>(&po.filecache),
"if specified, generate a static file cache with this file name")
("dump",
value<bool>(&po.dump)->default_value(false),
"dump the program graph")
("docjson",
value<string>(&po.docjson)->default_value(""),
"Filename to generate a JSON file for PHP docs")
("coredump",
value<bool>(&po.coredump)->default_value(false),
"turn on coredump")
("nofork",
value<bool>(&po.nofork)->default_value(false),
"forking is needed for large compilation to release memory before g++"
"compilation. turning off forking can help gdb debugging.")
("opts",
value<string>(&po.optimizations)->default_value(""),
"Set optimizations to enable/disable")
("compiler-id", "display the git hash for the compiler id")
("repo-schema", "display the repo schema id used by this app")
;
positional_options_description p;
p.add("inputs", -1);
variables_map vm;
try {
store(command_line_parser(argc, argv).options(desc).positional(p).run(),
vm);
notify(vm);
} catch (const unknown_option& e) {
Logger::Error("Error in command line: %s\n\n", e.what());
cout << desc << "\n";
return -1;
}
if (argc <= 1 || vm.count("help")) {
cout << desc << "\n";
return 1;
}
if (vm.count("version")) {
#ifdef HPHP_VERSION
#undef HPHP_VERSION
#endif
#ifdef HPHP_COMPILER_STR
#undef HPHP_COMPILER_STR
#endif
#ifdef DEBUG
#define HPHP_COMPILER_STR "HipHop Compiler (Debug Build) v"
#else
#define HPHP_COMPILER_STR "HipHop Compiler v"
#endif
#define HPHP_VERSION(v) cout << HPHP_COMPILER_STR #v << "\n";
#include "../version"
cout << "Compiler: " << kCompilerId << "\n";
cout << "Repo schema: " << kRepoSchemaId << "\n";
return 1;
}
if (vm.count("compiler-id")) {
cout << kCompilerId << "\n";
return 1;
}
if (vm.count("repo-schema")) {
cout << kRepoSchemaId << "\n";
return 1;
}
if ((po.target == "hhbc" || po.target == "run") &&
po.format.find("exe") == string::npos) {
if (po.program == "program") {
po.program = "hhvm.hhbc";
}
}
// log level
if (po.logLevel != -1) {
Logger::LogLevel = (Logger::LogLevelType)po.logLevel;
} else if (po.target == "run") {
Logger::LogLevel = Logger::LogNone;
} else {
Logger::LogLevel = Logger::LogInfo;
}
Hdf config;
for (vector<string>::const_iterator it = po.config.begin();
it != po.config.end(); ++it) {
config.append(*it);
}
for (unsigned int i = 0; i < po.confStrings.size(); i++) {
config.fromString(po.confStrings[i].c_str());
}
Option::Load(config);
vector<string> badnodes;
config.lint(badnodes);
for (unsigned int i = 0; i < badnodes.size(); i++) {
Logger::Error("Possible bad config node: %s", badnodes[i].c_str());
}
if (po.dump) Option::DumpAst = true;
if (po.inputDir.empty()) {
po.inputDir = '.';
}
po.inputDir = Util::normalizeDir(po.inputDir);
if (po.configDir.empty()) {
po.configDir = po.inputDir;
}
po.configDir = Util::normalizeDir(po.configDir);
Option::RootDirectory = po.configDir;
Option::IncludeSearchPaths = po.includePaths;
for (unsigned int i = 0; i < po.excludeDirs.size(); i++) {
Option::PackageExcludeDirs.insert
(Util::normalizeDir(po.excludeDirs[i]));
}
for (unsigned int i = 0; i < po.excludeFiles.size(); i++) {
Option::PackageExcludeFiles.insert(po.excludeFiles[i]);
}
for (unsigned int i = 0; i < po.excludePatterns.size(); i++) {
Option::PackageExcludePatterns.insert
(Util::format_pattern(po.excludePatterns[i], true));
}
for (unsigned int i = 0; i < po.excludeStaticDirs.size(); i++) {
Option::PackageExcludeStaticDirs.insert
(Util::normalizeDir(po.excludeStaticDirs[i]));
}
for (unsigned int i = 0; i < po.excludeStaticFiles.size(); i++) {
Option::PackageExcludeStaticFiles.insert(po.excludeStaticFiles[i]);
}
for (unsigned int i = 0; i < po.excludeStaticPatterns.size(); i++) {
Option::PackageExcludeStaticPatterns.insert
(Util::format_pattern(po.excludeStaticPatterns[i], true));
}
if (po.target == "hhbc" || po.target == "run") {
Option::AnalyzePerfectVirtuals = false;
}
Option::ProgramName = po.program;
if (po.format.empty()) {
if (po.target == "php") {
po.format = "trimmed";
} else if (po.target == "run") {
po.format = "binary";
} else if (po.target == "hhbc") {
po.format = "binary";
}
}
if (!po.docjson.empty()) {
if (po.target != "run" &&
po.target != "hhbc" &&
po.target != "analyze") {
Logger::Error(
"Cannot generate doc JSON file unless target is "
"'hhbc', 'run', or 'analyze'");
} else {
Option::DocJson = po.docjson;
}
}
if (po.optimizeLevel == -1) {
po.optimizeLevel = 1;
}
// we always do pre/post opt no matter the opt level
Option::PreOptimization = true;
Option::PostOptimization = true;
if (po.optimizeLevel == 0) {
// --optimize-level=0 is equivalent to --opts=none
po.optimizations = "none";
Option::ParseTimeOpts = false;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
int process(const CompilerOptions &po) {
if (po.coredump) {
#if defined(__APPLE__) || defined(__FreeBSD__)
struct rlimit rl;
getrlimit(RLIMIT_CORE, &rl);
rl.rlim_cur = 80000000LL;
if (rl.rlim_max < rl.rlim_cur) {
rl.rlim_max = rl.rlim_cur;
}
setrlimit(RLIMIT_CORE, &rl);
#else
struct rlimit64 rl;
getrlimit64(RLIMIT_CORE, &rl);
rl.rlim_cur = 8000000000LL;
if (rl.rlim_max < rl.rlim_cur) {
rl.rlim_max = rl.rlim_cur;
}
setrlimit64(RLIMIT_CORE, &rl);
#endif
}
// lint doesn't need analysis
if (po.target == "lint") {
return lintTarget(po);
}
register_process_init();
init_thread_locals();
Timer timer(Timer::WallTime);
AnalysisResultPtr ar;
// prepare a package
Package package(po.inputDir.c_str());
ar = package.getAnalysisResult();
hhbcTargetInit(po, ar);
std::string errs;
if (!AliasManager::parseOptimizations(po.optimizations, errs)) {
Logger::Error("%s\n", errs.c_str());
return false;
}
// one time initialization
Type::InitTypeHintMap();
BuiltinSymbols::LoadSuperGlobals();
ClassInfo::Load();
bool isPickledPHP = (po.target == "php" && po.format == "pickled");
if (!isPickledPHP) {
if (po.target == "hhbc" && !Option::WholeProgram) {
// We're trying to produce the same bytecode as runtime parsing.
// There's nothing to do.
} else {
if (!BuiltinSymbols::Load(ar)) {
return false;
}
ar->loadBuiltins();
}
hphp_process_init();
}
{
Timer timer(Timer::WallTime, "parsing inputs");
if (!po.inputs.empty() && isPickledPHP) {
for (unsigned int i = 0; i < po.inputs.size(); i++) {
package.addSourceFile(po.inputs[i].c_str());
}
} else {
ar->setPackage(&package);
ar->setParseOnDemand(po.parseOnDemand);
if (!po.parseOnDemand) {
ar->setParseOnDemandDirs(Option::ParseOnDemandDirs);
}
if (po.modules.empty() && po.fmodules.empty() &&
po.ffiles.empty() && po.inputs.empty() && po.inputList.empty()) {
package.addAllFiles(false);
} else {
for (unsigned int i = 0; i < po.modules.size(); i++) {
package.addDirectory(po.modules[i], false);
}
for (unsigned int i = 0; i < po.fmodules.size(); i++) {
package.addDirectory(po.fmodules[i], true);
}
for (unsigned int i = 0; i < po.ffiles.size(); i++) {
package.addSourceFile(po.ffiles[i].c_str());
}
for (unsigned int i = 0; i < po.cmodules.size(); i++) {
package.addStaticDirectory(po.cmodules[i].c_str());
}
for (unsigned int i = 0; i < po.cfiles.size(); i++) {
package.addStaticFile(po.cfiles[i].c_str());
}
for (unsigned int i = 0; i < po.inputs.size(); i++) {
package.addSourceFile(po.inputs[i].c_str());
}
if (!po.inputList.empty()) {
package.addInputList(po.inputList.c_str());
}
}
}
if (po.target != "filecache") {
if (!package.parse(!po.force)) {
return 1;
}
if (Option::WholeProgram || po.target == "analyze") {
ar->analyzeProgram();
}
}
}
// saving file cache
AsyncFileCacheSaver fileCacheThread(&package, po.filecache.c_str());
if (po.target != "analyze" && !po.filecache.empty()) {
fileCacheThread.start();
}
if (Option::DumpAst) {
ar->dump();
}
int ret = 0;
if (po.target == "analyze") {
ret = analyzeTarget(po, ar);
} else if (po.target == "php") {
ret = phpTarget(po, ar);
} else if (po.target == "hhbc") {
ret = hhbcTarget(po, ar, fileCacheThread);
} else if (po.target == "run") {
ret = runTargetCheck(po, ar, fileCacheThread);
} else if (po.target == "filecache") {
// do nothing
} else {
Logger::Error("Unknown target: %s", po.target.c_str());
return 1;
}
if (Option::DumpAst) {
ar->dump();
}
if (!Option::DocJson.empty()) {
Timer timer(Timer::WallTime, "Saving doc JSON file");
ar->docJson(Option::DocJson);
}
// saving stats
if (po.target == "analyze" || po.genStats || !po.dbStats.empty()) {
int seconds = timer.getMicroSeconds() / 1000000;
Logger::Info("saving code errors and stats...");
Timer timer(Timer::WallTime, "saving stats");
if (!po.dbStats.empty()) {
try {
ServerDataPtr server = ServerData::Create(po.dbStats);
int runId = package.saveStatsToDB(server, seconds, po.branch,
po.revision);
package.commitStats(server, runId);
} catch (const DatabaseException& e) {
Logger::Error("%s", e.what());
}
} else {
Compiler::SaveErrors(ar, (po.outputDir + "/CodeError.js").c_str());
package.saveStatsToFile((po.outputDir + "/Stats.js").c_str(), seconds);
}
} else if (Compiler::HasError()) {
Logger::Info("saving code errors...");
Compiler::SaveErrors(ar, (po.outputDir + "/CodeError.js").c_str());
}
if (!po.filecache.empty()) {
fileCacheThread.waitForEnd();
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
int lintTarget(const CompilerOptions &po) {
int ret = 0;
for (unsigned int i = 0; i < po.inputs.size(); i++) {
string filename = po.inputDir + "/" + po.inputs[i];
try {
Scanner scanner(filename.c_str(), Option::GetScannerType());
Compiler::Parser parser(scanner, filename.c_str(),
AnalysisResultPtr(new AnalysisResult()));
if (!parser.parse()) {
Logger::Error("Unable to parse file %s: %s", filename.c_str(),
parser.getMessage().c_str());
ret = 1;
} else {
Logger::Info("%s parsed successfully...", filename.c_str());
}
} catch (FileOpenException &e) {
Logger::Error("%s", e.getMessage().c_str());
ret = 1;
}
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
int analyzeTarget(const CompilerOptions &po, AnalysisResultPtr ar) {
int ret = 0;
if (!po.noTypeInference) {
Option::GenerateInferredTypes = true;
}
if (Option::PreOptimization) {
Timer timer(Timer::WallTime, "pre-optimizing");
ar->preOptimize();
}
if (!Option::AllVolatile) {
Timer timer(Timer::WallTime, "analyze includes");
ar->analyzeIncludes();
}
if (Option::GenerateInferredTypes) {
Timer timer(Timer::WallTime, "inferring types");
ar->inferTypes();
}
if (Option::PostOptimization) {
Timer timer(Timer::WallTime, "post-optimizing");
ar->postOptimize();
}
ar->analyzeProgramFinal();
return ret;
}
///////////////////////////////////////////////////////////////////////////////
int phpTarget(const CompilerOptions &po, AnalysisResultPtr ar) {
int ret = 0;
// format
int formatCount = 0;
if (po.format.find("pickled") != string::npos) {
Option::GeneratePickledPHP = true;
formatCount++;
}
if (po.format.find("inlined") != string::npos) {
Option::GenerateInlinedPHP = true;
formatCount++;
}
if (po.format.find("trimmed") != string::npos) {
Option::GenerateTrimmedPHP = true;
formatCount++;
}
if (po.format.find("typeinfo") != string::npos) {
Option::GenerateInferredTypes = true;
}
if (formatCount == 0) {
Logger::Error("Unknown format for PHP target: %s", po.format.c_str());
return 1;
}
// analyze
if (Option::GenerateInferredTypes || Option::ConvertSuperGlobals) {
Logger::Info("inferring types...");
ar->inferTypes();
}
// generate
ar->setOutputPath(po.outputDir);
if (Option::GeneratePickledPHP) {
Logger::Info("creating pickled PHP files...");
string outputDir = po.outputDir;
if (formatCount > 1) outputDir += "/pickled";
mkdir(outputDir.c_str(), 0777);
ar->outputAllPHP(CodeGenerator::PickledPHP);
}
if (Option::GenerateInlinedPHP) {
Logger::Info("creating inlined PHP files...");
string outputDir = po.outputDir;
if (formatCount > 1) outputDir += "/inlined";
mkdir(outputDir.c_str(), 0777);
if (!ar->outputAllPHP(CodeGenerator::InlinedPHP)) {
ret = -1;
}
}
if (Option::GenerateTrimmedPHP) {
Logger::Info("creating trimmed PHP files...");
string outputDir = po.outputDir;
if (formatCount > 1) outputDir += "/trimmed";
mkdir(outputDir.c_str(), 0777);
if (!ar->outputAllPHP(CodeGenerator::TrimmedPHP)) {
ret = -1;
}
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
void hhbcTargetInit(const CompilerOptions &po, AnalysisResultPtr ar) {
if (po.syncDir.empty()) {
ar->setOutputPath(po.outputDir);
} else {
ar->setOutputPath(po.syncDir);
}
// Propagate relevant compiler-specific options to the runtime.
RuntimeOption::RepoCentralPath = ar->getOutputPath() + '/' + po.program;
if (po.format.find("exe") != string::npos) {
RuntimeOption::RepoCentralPath += ".hhbc";
}
RuntimeOption::RepoLocalMode = "--";
RuntimeOption::RepoDebugInfo = Option::RepoDebugInfo;
RuntimeOption::RepoJournal = "memory";
RuntimeOption::EnableHipHopSyntax = Option::EnableHipHopSyntax;
RuntimeOption::EvalJitEnableRenameFunction = Option::JitEnableRenameFunction;
// Turn off commits, because we don't want systemlib to get included
RuntimeOption::RepoCommit = false;
}
int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
AsyncFileCacheSaver &fcThread) {
int ret = 0;
int formatCount = 0;
const char *type = 0;
if (po.format.find("text") != string::npos) {
Option::GenerateTextHHBC = true;
type = "creating text HHBC files";
formatCount++;
}
if (po.format.find("binary") != string::npos) {
Option::GenerateBinaryHHBC = true;
type = "creating binary HHBC files";
formatCount++;
}
if (po.format.find("exe") != string::npos) {
Option::GenerateBinaryHHBC = true;
type = "creating binary HHBC files";
formatCount++;
}
if (formatCount == 0) {
Logger::Error("Unknown format for HHBC target: %s", po.format.c_str());
return 1;
}
/* without this, emitClass allows classes with interfaces to be
hoistable */
SystemLib::s_inited = true;
RuntimeOption::RepoCommit = true;
Option::AutoInline = -1;
if (po.optimizeLevel > 0) {
ret = analyzeTarget(po, ar);
}
Timer timer(Timer::WallTime, type);
Compiler::emitAllHHBC(ar);
if (!po.syncDir.empty()) {
if (!po.filecache.empty()) {
fcThread.waitForEnd();
}
Util::syncdir(po.outputDir, po.syncDir);
boost::filesystem::remove_all(po.syncDir);
}
if (!ret && po.format.find("exe") != string::npos) {
/*
* We need to create an executable with the repo
* embedded in it.
* Copy ourself, and embed the repo as a section
* named "repo".
*/
string exe = po.outputDir + '/' + po.program;
string repo = "repo=" + exe + ".hhbc";
char buf[PATH_MAX];
if (!realpath("/proc/self/exe", buf)) return -1;
const char *argv[] = { "objcopy", "--add-section", repo.c_str(),
buf, exe.c_str(), 0 };
string out;
ret = Process::Exec(argv[0], argv, nullptr, out, nullptr) ? 0 : 1;
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
int runTargetCheck(const CompilerOptions &po, AnalysisResultPtr ar,
AsyncFileCacheSaver &fcThread) {
// generate code
if (hhbcTarget(po, ar, fcThread)) {
return 1;
}
// check error
if (Compiler::HasError() && !po.force) {
Compiler::DumpErrors(ar);
return 1;
}
return 0;
}
int runTarget(const CompilerOptions &po) {
int ret = 0;
// If there are more than one input files, we need one extra arg to run.
// If it's missing, we will stop right here, with compiled code.
if ((po.inputs.size() != 1 && po.programArgs.empty()) ||
!po.inputList.empty()) {
return 0;
}
// run the executable
string cmd;
if (po.format.find("exe") == string::npos) {
char buf[PATH_MAX];
if (!realpath("/proc/self/exe", buf)) return -1;
cmd += buf;
cmd += " -vRepo.Authoritative=true";
cmd += " -vRepo.Local.Mode=r- -vRepo.Local.Path=";
}
cmd += po.outputDir + '/' + po.program;
cmd += string(" --file ") +
(po.inputs.size() == 1 ? po.inputs[0] : "") +
" " + po.programArgs;
Logger::Info("running executable: %s", cmd.c_str());
ret = Util::ssystem(cmd.c_str());
if (ret && ret != -1) ret = 1;
// delete the temporary directory if not needed
if (!po.keepTempDir) {
Logger::Info("deleting temporary directory %s...", po.outputDir.c_str());
boost::filesystem::remove_all(po.outputDir);
}
return ret;
}
void createOutputDirectory(CompilerOptions &po) {
if (po.outputDir.empty()) {
const char *t = getenv("TEMP");
if (!t) {
t = "/tmp";
}
string temp = t;
temp += "/hphp_XXXXXX";
char path[PATH_MAX + 1];
strncpy(path, temp.c_str(), PATH_MAX);
path[PATH_MAX] = '\0';
po.outputDir = mkdtemp(path);
Logger::Info("creating temporary directory %s ...", po.outputDir.c_str());
}
mkdir(po.outputDir.c_str(), 0777);
if (!po.syncDir.empty()) {
Logger::Info("re-creating sync directory %s ...", po.syncDir.c_str());
boost::filesystem::remove_all(po.syncDir);
mkdir(po.syncDir.c_str(), 0777);
}
}
///////////////////////////////////////////////////////////////////////////////
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,21 +14,21 @@
+----------------------------------------------------------------------+
*/
#include <compiler/construct.h>
#include <compiler/parser/parser.h>
#include <util/util.h>
#include "hphp/compiler/construct.h"
#include "hphp/compiler/parser/parser.h"
#include "hphp/util/util.h"
#include <compiler/analysis/file_scope.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/analysis/class_scope.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/ast_walker.h>
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/analysis_result.h"
#include "hphp/compiler/analysis/ast_walker.h"
#include <compiler/statement/function_statement.h>
#include "hphp/compiler/statement/function_statement.h"
#include <compiler/expression/simple_function_call.h>
#include <compiler/expression/simple_variable.h>
#include <compiler/expression/closure_expression.h>
#include "hphp/compiler/expression/simple_function_call.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/expression/closure_expression.h"
#include <iomanip>
using namespace HPHP;
@@ -313,7 +313,7 @@ void Construct::dumpNode(int spc) {
}
std::cout << "-> 0x" << std::hex << std::setfill('0')
<< std::setw(10) << (int64)this << std::dec;
<< std::setw(10) << (int64_t)this << std::dec;
std::cout << " " << name << "(" << type << ") ";
if (id) {
@@ -322,12 +322,12 @@ void Construct::dumpNode(int spc) {
if (idPtr) {
std::cout << "idp=0x" <<
std::hex << std::setfill('0') << std::setw(10) <<
(int64)idPtr.get() << " ";
(int64_t)idPtr.get() << " ";
}
if (idCsePtr) {
std::cout << "idcsep=0x" <<
std::hex << std::setfill('0') << std::setw(10) <<
(int64)idCsePtr.get() << " ";
(int64_t)idCsePtr.get() << " ";
}
if (value != "") {
@@ -364,7 +364,7 @@ void Construct::dumpNode(int spc) {
}
string refstr;
if (dynamic_cast<SimpleVariable*>(this) != NULL) {
if (dynamic_cast<SimpleVariable*>(this) != nullptr) {
if (isReferencedValid()) {
if (isReferenced()) {
refstr += ",Referenced";
@@ -380,7 +380,7 @@ void Construct::dumpNode(int spc) {
if (refstr != "") refstr = " (" + refstr.substr(1) + ")";
string objstr;
if (dynamic_cast<SimpleVariable*>(this) != NULL) {
if (dynamic_cast<SimpleVariable*>(this) != nullptr) {
if (isNeededValid()) {
if (isNeeded()) {
objstr += "Object";
@@ -454,7 +454,8 @@ private:
void Construct::dump(int spc, AnalysisResultConstPtr ar) {
ConstructDumper cd(spc, ar);
cd.walk(ConstructRawPtr(this), ConstructRawPtr(), ConstructRawPtr());
cd.walk(AstWalkerStateVec(ConstructRawPtr(this)),
ConstructRawPtr(), ConstructRawPtr());
}
void Construct::dump(int spc, AnalysisResultConstPtr ar, bool functionOnly,
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,13 +14,13 @@
+----------------------------------------------------------------------+
*/
#ifndef __CONSTRUCT_H__
#define __CONSTRUCT_H__
#ifndef incl_HPHP_CONSTRUCT_H_
#define incl_HPHP_CONSTRUCT_H_
#include <util/json.h>
#include <compiler/code_generator.h>
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/block_scope.h>
#include "hphp/util/json.h"
#include "hphp/compiler/code_generator.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/block_scope.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -178,7 +178,8 @@ public:
return m_blockScope->getContainingClass();
}
void resetScope(BlockScopeRawPtr scope, bool resetOrigScope=false);
void parseTimeFatal(Compiler::ErrorType error, const char *fmt, ...);
void parseTimeFatal(Compiler::ErrorType error, const char *fmt, ...)
ATTRIBUTE_PRINTF(3,4);
virtual int getLocalEffects() const { return UnknownEffect;}
int getChildrenEffects() const;
int getContainedEffects() const;
@@ -246,7 +247,6 @@ public:
* Called when generating code.
*/
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
/**
* Implements JSON::CodeError::ISerializable.
@@ -315,7 +315,7 @@ public:
int getLocalEffects() const { return m_localEffects; }
virtual void effectsCallback() = 0;
protected:
LocalEffectsContainer(Construct::Effect localEffect) :
explicit LocalEffectsContainer(Construct::Effect localEffect) :
m_localEffects(localEffect) {}
LocalEffectsContainer() :
m_localEffects(0) {}
@@ -334,4 +334,4 @@ protected:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __CONSTRUCT_H__
#endif // incl_HPHP_CONSTRUCT_H_
@@ -0,0 +1,407 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/array_element_expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/expression/static_member_expression.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/util/parser/hphp.tab.hpp"
#include "hphp/runtime/base/complex_types.h"
#include "hphp/runtime/base/builtin_functions.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
ArrayElementExpression::ArrayElementExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionPtr variable, ExpressionPtr offset)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ArrayElementExpression)),
LocalEffectsContainer(AccessorEffect),
m_variable(variable), m_offset(offset), m_global(false),
m_dynamicGlobal(false) {
m_variable->setContext(Expression::AccessContext);
if (m_variable->is(Expression::KindOfSimpleVariable)) {
SimpleVariablePtr var =
dynamic_pointer_cast<SimpleVariable>(m_variable);
if (var->getName() == "GLOBALS") {
m_global = true;
m_dynamicGlobal = true;
if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
ScalarExpressionPtr offset =
dynamic_pointer_cast<ScalarExpression>(m_offset);
if (offset->isLiteralString()) {
m_globalName = offset->getIdentifier();
if (!m_globalName.empty()) {
m_dynamicGlobal = false;
}
}
}
}
}
}
ExpressionPtr ArrayElementExpression::clone() {
ArrayElementExpressionPtr exp(new ArrayElementExpression(*this));
Expression::deepCopy(exp);
exp->m_variable = Clone(m_variable);
exp->m_offset = Clone(m_offset);
return exp;
}
void ArrayElementExpression::setContext(Context context) {
m_context |= context;
switch (context) {
case Expression::LValue:
if (!hasContext(Expression::UnsetContext)) {
m_variable->setContext(Expression::LValue);
}
if (m_variable->is(Expression::KindOfObjectPropertyExpression)) {
m_variable->clearContext(Expression::NoLValueWrapper);
}
// special case for $GLOBALS[], we do not need lvalue wrapper
if (m_variable->is(Expression::KindOfSimpleVariable)) {
SimpleVariablePtr var =
dynamic_pointer_cast<SimpleVariable>(m_variable);
if (var->getName() == "GLOBALS") {
m_context |= Expression::NoLValueWrapper;
}
}
break;
case Expression::DeepAssignmentLHS:
case Expression::DeepOprLValue:
case Expression::ExistContext:
case Expression::UnsetContext:
case Expression::DeepReference:
m_variable->setContext(context);
break;
case Expression::RefValue:
case Expression::RefParameter:
m_variable->setContext(DeepReference);
break;
case Expression::InvokeArgument:
m_variable->setContext(context);
setContext(NoLValueWrapper);
default:
break;
}
}
void ArrayElementExpression::clearContext(Context context) {
m_context &= ~context;
switch (context) {
case Expression::LValue:
case Expression::DeepOprLValue:
case Expression::DeepAssignmentLHS:
case Expression::UnsetContext:
case Expression::DeepReference:
m_variable->clearContext(context);
break;
case Expression::InvokeArgument:
m_variable->clearContext(context);
clearContext(NoLValueWrapper);
break;
case Expression::RefValue:
case Expression::RefParameter:
m_variable->clearContext(DeepReference);
break;
default:
break;
}
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
bool ArrayElementExpression::appendClass(ExpressionPtr cls,
AnalysisResultConstPtr ar,
FileScopePtr file) {
if (m_variable->is(Expression::KindOfArrayElementExpression)) {
return dynamic_pointer_cast<ArrayElementExpression>(m_variable)
->appendClass(cls, ar, file);
}
if (m_variable->is(Expression::KindOfSimpleVariable) ||
m_variable->is(Expression::KindOfDynamicVariable)) {
StaticMemberExpressionPtr sme(
new StaticMemberExpression(
m_variable->getScope(), m_variable->getLocation(),
cls, m_variable));
sme->onParse(ar, file);
m_variable = sme;
m_global = m_dynamicGlobal = false;
m_globalName.clear();
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
bool ArrayElementExpression::isTemporary() const {
return !m_global &&
!(m_context & (AccessContext|LValue|RefValue|UnsetContext));
}
void ArrayElementExpression::analyzeProgram(AnalysisResultPtr ar) {
m_variable->analyzeProgram(ar);
if (m_offset) m_offset->analyzeProgram(ar);
if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
if (m_global) {
if (getContext() & (LValue|RefValue|DeepReference)) {
setContext(NoLValueWrapper);
} else if (!m_dynamicGlobal &&
!(getContext() &
(LValue|RefValue|RefParameter|DeepReference|
UnsetContext|ExistContext))) {
VariableTablePtr vars = ar->getVariables();
Symbol *sym = vars->getSymbol(m_globalName);
if (!sym || sym->getDeclaration().get() == this) {
Compiler::Error(Compiler::UseUndeclaredGlobalVariable,
shared_from_this());
}
}
} else {
TypePtr at(m_variable->getActualType());
TypePtr et(m_variable->getExpectedType());
if (et &&
(et->is(Type::KindOfSequence) ||
et->is(Type::KindOfAutoSequence)) &&
at && at->isExactType()) {
// since Sequence maps to Variant in the runtime,
// using Sequence for the expected type will
// never allow the necessary casts to be generated.
m_variable->setExpectedType(at);
}
}
}
}
ConstructPtr ArrayElementExpression::getNthKid(int n) const {
switch (n) {
case 0:
return m_variable;
case 1:
return m_offset;
default:
assert(false);
break;
}
return ConstructPtr();
}
int ArrayElementExpression::getKidCount() const {
return 2;
}
void ArrayElementExpression::setNthKid(int n, ConstructPtr cp) {
switch (n) {
case 0:
m_variable = boost::dynamic_pointer_cast<Expression>(cp);
break;
case 1:
m_offset = boost::dynamic_pointer_cast<Expression>(cp);
break;
default:
assert(false);
break;
}
}
bool ArrayElementExpression::canonCompare(ExpressionPtr e) const {
return m_offset && Expression::canonCompare(e);
}
ExpressionPtr ArrayElementExpression::preOptimize(AnalysisResultConstPtr ar) {
if (!(m_context & (RefValue|LValue|UnsetContext|OprLValue|
InvokeArgument|DeepReference|DeepOprLValue))) {
if (m_offset && m_variable->isScalar()) {
Variant v, o;
if (m_variable->getScalarValue(v)) {
if (m_context & ExistContext &&
!v.isArray() &&
!v.isString() &&
!m_offset->hasEffect()) {
return replaceValue(makeConstant(ar, "null"));
}
if (m_offset->isScalar() && m_offset->getScalarValue(o)) {
if (v.isString()) {
if (!o.isInteger() ||
o.toInt64Val() < 0 ||
o.toInt64Val() >= v.toCStrRef().size()) {
// warnings should be raised...
return ExpressionPtr();
}
}
try {
g_context->setThrowAllErrors(true);
Variant res = v.rvalAt(
o, hasContext(ExistContext) ?
AccessFlags::None : AccessFlags::Error);
g_context->setThrowAllErrors(false);
return replaceValue(makeScalarExpression(ar, res));
} catch (...) {
g_context->setThrowAllErrors(false);
}
}
}
}
}
return ExpressionPtr();
}
ExpressionPtr ArrayElementExpression::postOptimize(AnalysisResultConstPtr ar) {
if (!hasLocalEffect(AccessorEffect)) return ExpressionPtr();
TypePtr at(m_variable->getActualType());
if (at && (at->is(Type::KindOfString) || at->is(Type::KindOfArray))) {
clearLocalEffect(AccessorEffect);
return dynamic_pointer_cast<Expression>(shared_from_this());
}
return ExpressionPtr();
}
/**
* ArrayElementExpression comes from:
*
* reference_variable[|expr]
* ->object_dim_list[|expr]
* encaps T_VARIABLE[expr]
* encaps ${T_STRING[expr]}
*/
TypePtr ArrayElementExpression::inferTypes(AnalysisResultPtr ar,
TypePtr type, bool coerce) {
ConstructPtr self = shared_from_this();
if (m_offset &&
!(m_context & (UnsetContext | ExistContext |
InvokeArgument | LValue | RefValue))) {
setLocalEffect(DiagnosticEffect);
}
if (m_context & (AssignmentLHS|OprLValue)) {
clearLocalEffect(AccessorEffect);
} else if (m_context & (LValue | RefValue)) {
setLocalEffect(CreateEffect);
}
// handling $GLOBALS[...]
if (m_variable->is(Expression::KindOfSimpleVariable)) {
SimpleVariablePtr var =
dynamic_pointer_cast<SimpleVariable>(m_variable);
if (var->getName() == "GLOBALS") {
clearLocalEffect(AccessorEffect);
m_global = true;
m_dynamicGlobal = true;
getScope()->getVariables()->
setAttribute(VariableTable::NeedGlobalPointer);
VariableTablePtr vars = ar->getVariables();
Lock l(ar->getMutex());
if (m_offset && m_offset->is(Expression::KindOfScalarExpression)) {
ScalarExpressionPtr offset =
dynamic_pointer_cast<ScalarExpression>(m_offset);
if (offset->isLiteralString()) {
m_globalName = offset->getIdentifier();
if (!m_globalName.empty()) {
m_dynamicGlobal = false;
clearLocalEffect(DiagnosticEffect);
getScope()->getVariables()->
setAttribute(VariableTable::NeedGlobalPointer);
TypePtr ret;
if (coerce) {
ret = vars->add(m_globalName, type, true, ar, self,
ModifierExpressionPtr());
} else {
ret = vars->checkVariable(m_globalName, type, coerce, ar, self);
}
getScope()->getVariables()->addSuperGlobal(m_globalName);
return ret;
}
}
} else {
vars->setAttribute(VariableTable::ContainsDynamicVariable);
}
if (hasContext(LValue) || hasContext(RefValue)) {
vars->forceVariants(ar, VariableTable::AnyVars);
vars->setAttribute(VariableTable::ContainsLDynamicVariable);
}
if (m_offset) {
m_offset->inferAndCheck(ar, Type::Primitive, false);
}
return m_implementedType = Type::Variant; // so not to lose values
}
}
if ((hasContext(LValue) || hasContext(RefValue)) &&
!hasContext(UnsetContext)) {
m_variable->setContext(LValue);
}
TypePtr varType;
if (m_offset) {
varType = m_variable->inferAndCheck(ar, coerce ? Type::AutoSequence :
Type::Sequence, coerce);
m_offset->inferAndCheck(ar, Type::Some, false);
} else {
if (hasContext(ExistContext) || hasContext(UnsetContext)) {
if (getScope()->isFirstPass()) {
Compiler::Error(Compiler::InvalidArrayElement, self);
}
}
m_variable->inferAndCheck(ar, Type::Array, true);
}
if (varType && Type::SameType(varType, Type::String)) {
m_implementedType.reset();
return Type::String;
}
TypePtr ret = propagateTypes(ar, Type::Variant);
m_implementedType = Type::Variant;
return ret; // so not to lose values
}
ExpressionPtr ArrayElementExpression::unneeded() {
if (m_global) {
if (m_offset) return m_offset->unneeded();
}
return Expression::unneeded();
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void ArrayElementExpression::outputPHP(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (Option::ConvertSuperGlobals && m_global && !m_dynamicGlobal &&
getScope() && (getScope()->is(BlockScope::ProgramScope) ||
getScope()-> getVariables()->
isConvertibleSuperGlobal(m_globalName))) {
cg_printf("$%s", m_globalName.c_str());
} else {
m_variable->outputPHP(cg, ar);
cg_printf("[");
if (m_offset) m_offset->outputPHP(cg, ar);
cg_printf("]");
}
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __ARRAY_ELEMENT_EXPRESSION_H__
#define __ARRAY_ELEMENT_EXPRESSION_H__
#ifndef incl_HPHP_ARRAY_ELEMENT_EXPRESSION_H_
#define incl_HPHP_ARRAY_ELEMENT_EXPRESSION_H_
#include <compiler/expression/expression.h>
#include "hphp/compiler/expression/expression.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -56,11 +56,6 @@ public:
bool appendClass(ExpressionPtr cls,
AnalysisResultConstPtr ar, FileScopePtr file);
virtual void outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
int op);
virtual void outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
virtual bool canonCompare(ExpressionPtr e) const;
private:
@@ -75,4 +70,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __ARRAY_ELEMENT_EXPRESSION_H__
#endif // incl_HPHP_ARRAY_ELEMENT_EXPRESSION_H_
@@ -0,0 +1,136 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/array_pair_expression.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/expression/unary_op_expression.h"
#include "hphp/util/parser/hphp.tab.hpp"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
ArrayPairExpression::ArrayPairExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionPtr name, ExpressionPtr value, bool ref,
bool collection /* = false */)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ArrayPairExpression)),
m_name(name), m_value(value), m_ref(ref), m_collection(collection) {
if (m_ref) {
m_value->setContext(Expression::RefValue);
}
}
ExpressionPtr ArrayPairExpression::clone() {
ArrayPairExpressionPtr exp(new ArrayPairExpression(*this));
Expression::deepCopy(exp);
exp->m_name = Clone(m_name);
exp->m_value = Clone(m_value);
return exp;
}
bool ArrayPairExpression::isScalar() const {
return isScalarArrayPair();
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
bool ArrayPairExpression::isScalarArrayPair() const {
if (!m_value->isScalar()) return false;
if (!m_name) return true;
if (!m_name->isScalar()) return false;
if (m_name->is(KindOfUnaryOpExpression) &&
static_pointer_cast<UnaryOpExpression>(m_name)->getOp() == T_ARRAY) {
return false;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
bool ArrayPairExpression::containsDynamicConstant(AnalysisResultPtr ar) const {
return (m_name && m_name->containsDynamicConstant(ar)) ||
m_value->containsDynamicConstant(ar);
}
void ArrayPairExpression::analyzeProgram(AnalysisResultPtr ar) {
if (m_name) m_name->analyzeProgram(ar);
m_value->analyzeProgram(ar);
}
ConstructPtr ArrayPairExpression::getNthKid(int n) const {
switch (n) {
case 0:
return m_name;
case 1:
return m_value;
default:
assert(false);
break;
}
return ConstructPtr();
}
int ArrayPairExpression::getKidCount() const {
return 2;
}
void ArrayPairExpression::setNthKid(int n, ConstructPtr cp) {
switch (n) {
case 0:
m_name = boost::dynamic_pointer_cast<Expression>(cp);
break;
case 1:
m_value = boost::dynamic_pointer_cast<Expression>(cp);
break;
default:
assert(false);
break;
}
}
TypePtr ArrayPairExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
if (m_name) {
m_name->inferAndCheck(ar, Type::Some, false);
}
m_value->inferAndCheck(ar, Type::Some, false);
return type;
}
bool ArrayPairExpression::canonCompare(ExpressionPtr e) const {
if (!Expression::canonCompare(e)) return false;
ArrayPairExpressionPtr a =
static_pointer_cast<ArrayPairExpression>(e);
return m_ref == a->m_ref;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void ArrayPairExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_name) {
m_name->outputPHP(cg, ar);
cg_printf(" => ");
}
if (m_ref) cg_printf("&");
m_value->outputPHP(cg, ar);
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __ARRAY_PAIR_EXPRESSION_H__
#define __ARRAY_PAIR_EXPRESSION_H__
#ifndef incl_HPHP_ARRAY_PAIR_EXPRESSION_H_
#define incl_HPHP_ARRAY_PAIR_EXPRESSION_H_
#include <compiler/expression/expression.h>
#include "hphp/compiler/expression/expression.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -40,9 +40,6 @@ public:
virtual int getLocalEffects() const { return NoEffect; }
bool isScalarArrayPair() const;
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool isRef() const { return m_ref; }
bool canonCompare(ExpressionPtr e) const;
@@ -51,11 +48,9 @@ private:
ExpressionPtr m_value;
bool m_ref;
bool m_collection;
bool outputCPPName(CodeGenerator &cg, AnalysisResultPtr ar);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // __ARRAY_PAIR_EXPRESSION_H__
#endif // incl_HPHP_ARRAY_PAIR_EXPRESSION_H_
@@ -0,0 +1,317 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/assignment_expression.h"
#include "hphp/compiler/expression/array_element_expression.h"
#include "hphp/compiler/expression/object_property_expression.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/expression/constant_expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/analysis/block_scope.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/constant_table.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/expression/unary_op_expression.h"
#include "hphp/util/parser/hphp.tab.hpp"
#include "hphp/compiler/option.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/simple_function_call.h"
#include "hphp/runtime/base/complex_types.h"
#include "hphp/runtime/base/builtin_functions.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
AssignmentExpression::AssignmentExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionPtr variable, ExpressionPtr value, bool ref,
bool rhsFirst /* = false */)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(AssignmentExpression)),
m_variable(variable), m_value(value), m_ref(ref), m_rhsFirst(rhsFirst) {
assert(!m_ref || !m_rhsFirst);
m_variable->setContext(Expression::DeepAssignmentLHS);
m_variable->setContext(Expression::AssignmentLHS);
m_variable->setContext(Expression::LValue);
m_variable->setContext(Expression::NoLValueWrapper);
m_value->setContext(Expression::AssignmentRHS);
if (ref) {
m_variable->setContext(Expression::RefAssignmentLHS);
m_value->setContext(Expression::RefValue);
// we have &new special case that's handled in this class
m_value->setContext(Expression::NoRefWrapper);
}
}
ExpressionPtr AssignmentExpression::clone() {
AssignmentExpressionPtr exp(new AssignmentExpression(*this));
Expression::deepCopy(exp);
exp->m_variable = Clone(m_variable);
exp->m_value = Clone(m_value);
return exp;
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
void AssignmentExpression::onParseRecur(AnalysisResultConstPtr ar,
ClassScopePtr scope) {
// This is that much we can do during parse phase.
TypePtr type;
if (m_value->is(Expression::KindOfScalarExpression)) {
type = static_pointer_cast<ScalarExpression>(m_value)->inferenceImpl(
ar, Type::Some, false);
} else if (m_value->is(Expression::KindOfUnaryOpExpression)) {
UnaryOpExpressionPtr uexp =
dynamic_pointer_cast<UnaryOpExpression>(m_value);
if (uexp->getOp() == T_ARRAY) {
type = Type::Array;
}
}
if (!type) type = Type::Some;
if (m_variable->is(Expression::KindOfConstantExpression)) {
// ...as in ClassConstant statement
// We are handling this one here, not in ClassConstant, purely because
// we need "value" to store in constant table.
if (type->is(Type::KindOfArray)) {
parseTimeFatal(Compiler::NoError,
"Arrays are not allowed in class constants");
}
ConstantExpressionPtr exp =
dynamic_pointer_cast<ConstantExpression>(m_variable);
scope->getConstants()->add(exp->getName(), type, m_value, ar, m_variable);
} else if (m_variable->is(Expression::KindOfSimpleVariable)) {
SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable);
scope->getVariables()->add(var->getName(), type, true, ar,
shared_from_this(), scope->getModifiers());
var->clearContext(Declaration); // to avoid wrong CodeError
} else {
assert(false); // parse phase shouldn't handle anything else
}
}
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
int AssignmentExpression::getLocalEffects() const {
return AssignEffect;
}
void AssignmentExpression::analyzeProgram(AnalysisResultPtr ar) {
m_variable->analyzeProgram(ar);
m_value->analyzeProgram(ar);
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
if (m_ref && m_variable->is(Expression::KindOfSimpleVariable)) {
SimpleVariablePtr var =
dynamic_pointer_cast<SimpleVariable>(m_variable);
const std::string &name = var->getName();
VariableTablePtr variables = getScope()->getVariables();
variables->addUsed(name);
}
} else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
if (m_variable->is(Expression::KindOfConstantExpression)) {
ConstantExpressionPtr exp =
dynamic_pointer_cast<ConstantExpression>(m_variable);
if (!m_value->isScalar()) {
getScope()->getConstants()->setDynamic(ar, exp->getName(), false);
}
} else {
CheckNeeded(m_variable, m_value);
}
}
}
ConstructPtr AssignmentExpression::getNthKid(int n) const {
switch (m_rhsFirst ? 1 - n : n) {
case 0:
return m_variable;
case 1:
return m_value;
default:
assert(false);
break;
}
return ConstructPtr();
}
int AssignmentExpression::getKidCount() const {
return 2;
}
void AssignmentExpression::setNthKid(int n, ConstructPtr cp) {
switch (m_rhsFirst ? 1 - n : n) {
case 0:
m_variable = boost::dynamic_pointer_cast<Expression>(cp);
break;
case 1:
m_value = boost::dynamic_pointer_cast<Expression>(cp);
break;
default:
assert(false);
break;
}
}
bool AssignmentExpression::isSimpleGlobalAssign(StringData **name,
TypedValue *tv) const {
if (!m_variable->is(KindOfArrayElementExpression)) return false;
ArrayElementExpressionPtr ae(
static_pointer_cast<ArrayElementExpression>(m_variable));
if (!ae->isSuperGlobal() || ae->isDynamicGlobal()) return false;
Variant v;
if (!m_value->getScalarValue(v) || v.is(KindOfArray)) return false;
if (name) {
*name = StringData::GetStaticString(ae->getGlobalName());
}
if (tv) {
if (v.isString()) {
v = StringData::GetStaticString(v.toCStrRef().get());
}
*tv = *v.asTypedValue();
}
return true;
}
ExpressionPtr AssignmentExpression::optimize(AnalysisResultConstPtr ar) {
if (m_variable->is(Expression::KindOfSimpleVariable)) {
SimpleVariablePtr var =
dynamic_pointer_cast<SimpleVariable>(m_variable);
if (var->checkUnused() &&
!CheckNeeded(var, m_value)) {
if (m_value->getContainedEffects() != getContainedEffects()) {
recomputeEffects();
}
return replaceValue(m_value);
}
}
return ExpressionPtr();
}
ExpressionPtr AssignmentExpression::preOptimize(AnalysisResultConstPtr ar) {
if (Option::EliminateDeadCode &&
ar->getPhase() >= AnalysisResult::FirstPreOptimize) {
// otherwise used & needed flags may not be up to date yet
ExpressionPtr rep = optimize(ar);
if (rep) return rep;
}
if (m_variable->getContainedEffects() & ~(CreateEffect|AccessorEffect)) {
return ExpressionPtr();
}
ExpressionPtr val = m_value;
while (val) {
if (val->is(KindOfExpressionList)) {
ExpressionListPtr el(static_pointer_cast<ExpressionList>(val));
val = el->listValue();
continue;
}
if (val->is(KindOfAssignmentExpression)) {
val = static_pointer_cast<AssignmentExpression>(val)->m_value;
continue;
}
break;
}
if (val && val->isScalar()) {
if (val != m_value) {
ExpressionListPtr rep(new ExpressionList(
getScope(), getLocation(),
ExpressionList::ListKindWrapped));
rep->addElement(m_value);
m_value = val->clone();
rep->addElement(static_pointer_cast<Expression>(shared_from_this()));
return replaceValue(rep);
}
if (!m_ref && m_variable->is(KindOfArrayElementExpression)) {
ArrayElementExpressionPtr ae(
static_pointer_cast<ArrayElementExpression>(m_variable));
ExpressionPtr avar(ae->getVariable());
ExpressionPtr aoff(ae->getOffset());
if (!aoff || aoff->isScalar()) {
avar = avar->getCanonLVal();
while (avar) {
if (avar->isScalar()) {
Variant v,o,r;
if (!avar->getScalarValue(v)) break;
if (!val->getScalarValue(r)) break;
try {
g_context->setThrowAllErrors(true);
if (aoff) {
if (!aoff->getScalarValue(o)) break;
if (v.isString()) {
if (!o.isInteger() ||
o.toInt64Val() < 0 ||
o.toInt64Val() >= v.toCStrRef().size()) {
// warnings should be raised...
break;
}
}
v.set(o, r);
} else {
v.append(r);
}
g_context->setThrowAllErrors(false);
} catch (...) {
break;
}
ExpressionPtr rep(
new AssignmentExpression(
getScope(), getLocation(),
m_variable->replaceValue(Clone(ae->getVariable())),
makeScalarExpression(ar, v), false));
if (!isUnused()) {
ExpressionListPtr el(
new ExpressionList(
getScope(), getLocation(),
ExpressionList::ListKindWrapped));
el->addElement(rep);
el->addElement(val);
rep = el;
}
return replaceValue(rep);
}
avar = avar->getCanonPtr();
}
g_context->setThrowAllErrors(false);
}
}
}
return ExpressionPtr();
}
ExpressionPtr AssignmentExpression::postOptimize(AnalysisResultConstPtr ar) {
return optimize(ar);
}
TypePtr AssignmentExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
return inferAssignmentTypes(ar, type, coerce, m_variable, m_value);
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void AssignmentExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_variable->outputPHP(cg, ar);
cg_printf(" = ");
if (m_ref) cg_printf("&");
m_value->outputPHP(cg, ar);
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __ASSIGNMENT_EXPRESSION_H__
#define __ASSIGNMENT_EXPRESSION_H__
#ifndef incl_HPHP_ASSIGNMENT_EXPRESSION_H_
#define incl_HPHP_ASSIGNMENT_EXPRESSION_H_
#include <compiler/expression/expression.h>
#include "hphp/compiler/expression/expression.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -29,7 +29,7 @@ class AssignmentExpression : public Expression, public IParseHandler {
public:
AssignmentExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionPtr variable, ExpressionPtr value,
bool ref);
bool ref, bool rhsFirst = false);
DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS;
ExpressionPtr preOptimize(AnalysisResultConstPtr ar);
@@ -45,16 +45,12 @@ public:
}
ExpressionPtr getVariable() { return m_variable;}
ExpressionPtr getStoreVariable() const { return m_variable; }
ExpressionPtr getValue() { return m_value;}
void setVariable(ExpressionPtr v) { m_variable = v; }
void setValue(ExpressionPtr v) { m_value = v; }
bool isRhsFirst() { return m_rhsFirst; }
int getLocalEffects() const;
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar, int state);
static bool SpecialAssignment(CodeGenerator &cg,
AnalysisResultPtr ar,
ExpressionPtr lval,
ExpressionPtr rval,
const char *rvalStr, bool ref);
// $GLOBALS[<literal-string>] = <scalar>;
bool isSimpleGlobalAssign(StringData **name, TypedValue *tv) const;
@@ -64,9 +60,10 @@ private:
ExpressionPtr m_variable;
ExpressionPtr m_value;
bool m_ref;
bool m_rhsFirst;
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // __ASSIGNMENT_EXPRESSION_H__
#endif // incl_HPHP_ASSIGNMENT_EXPRESSION_H_
@@ -0,0 +1,977 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/binary_op_expression.h"
#include "hphp/compiler/expression/array_element_expression.h"
#include "hphp/compiler/expression/object_property_expression.h"
#include "hphp/compiler/expression/unary_op_expression.h"
#include "hphp/util/parser/hphp.tab.hpp"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/expression/constant_expression.h"
#include "hphp/runtime/base/complex_types.h"
#include "hphp/runtime/base/type_conversions.h"
#include "hphp/runtime/base/builtin_functions.h"
#include "hphp/runtime/base/comparisons.h"
#include "hphp/runtime/base/zend/zend_string.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/encaps_list_expression.h"
#include "hphp/compiler/expression/simple_function_call.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/statement/loop_statement.h"
#include "hphp/runtime/base/tv_arith.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
BinaryOpExpression::BinaryOpExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionPtr exp1, ExpressionPtr exp2, int op)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(BinaryOpExpression)),
m_exp1(exp1), m_exp2(exp2), m_op(op), m_assign(false), m_canThrow(false) {
switch (m_op) {
case T_PLUS_EQUAL:
case T_MINUS_EQUAL:
case T_MUL_EQUAL:
case T_DIV_EQUAL:
case T_CONCAT_EQUAL:
case T_MOD_EQUAL:
case T_AND_EQUAL:
case T_OR_EQUAL:
case T_XOR_EQUAL:
case T_SL_EQUAL:
case T_SR_EQUAL:
m_assign = true;
m_exp1->setContext(Expression::LValue);
m_exp1->setContext(Expression::OprLValue);
m_exp1->setContext(Expression::DeepOprLValue);
if (m_exp1->is(Expression::KindOfObjectPropertyExpression)) {
m_exp1->setContext(Expression::NoLValueWrapper);
}
break;
case T_COLLECTION: {
std::string s = m_exp1->getLiteralString();
int cType = 0;
if (strcasecmp(s.c_str(), "vector") == 0) {
cType = Collection::VectorType;
} else if (strcasecmp(s.c_str(), "map") == 0) {
cType = Collection::MapType;
} else if (strcasecmp(s.c_str(), "stablemap") == 0) {
cType = Collection::StableMapType;
} else if (strcasecmp(s.c_str(), "set") == 0) {
cType = Collection::SetType;
} else if (strcasecmp(s.c_str(), "pair") == 0) {
cType = Collection::PairType;
}
ExpressionListPtr el = static_pointer_cast<ExpressionList>(m_exp2);
el->setCollectionType(cType);
break;
}
default:
break;
}
}
ExpressionPtr BinaryOpExpression::clone() {
BinaryOpExpressionPtr exp(new BinaryOpExpression(*this));
Expression::deepCopy(exp);
exp->m_exp1 = Clone(m_exp1);
exp->m_exp2 = Clone(m_exp2);
return exp;
}
bool BinaryOpExpression::isTemporary() const {
switch (m_op) {
case '+':
case '-':
case '*':
case '/':
case T_SL:
case T_SR:
case T_BOOLEAN_OR:
case T_BOOLEAN_AND:
case T_LOGICAL_OR:
case T_LOGICAL_AND:
case T_INSTANCEOF:
case T_COLLECTION:
return true;
}
return false;
}
bool BinaryOpExpression::isRefable(bool checkError /* = false */) const {
return checkError && m_assign;
}
bool BinaryOpExpression::isLiteralString() const {
if (m_op == '.') {
return m_exp1->isLiteralString() && m_exp2->isLiteralString();
}
return false;
}
std::string BinaryOpExpression::getLiteralString() const {
if (m_op == '.') {
return m_exp1->getLiteralString() + m_exp2->getLiteralString();
}
return "";
}
bool BinaryOpExpression::containsDynamicConstant(AnalysisResultPtr ar) const {
switch (m_op) {
case T_COLLECTION:
return m_exp2->containsDynamicConstant(ar);
default:
break;
}
return false;
}
bool BinaryOpExpression::isShortCircuitOperator() const {
switch (m_op) {
case T_BOOLEAN_OR:
case T_BOOLEAN_AND:
case T_LOGICAL_OR:
case T_LOGICAL_AND:
return true;
default:
break;
}
return false;
}
bool BinaryOpExpression::isLogicalOrOperator() const {
switch (m_op) {
case T_BOOLEAN_OR:
case T_LOGICAL_OR:
return true;
default:
break;
}
return false;
}
ExpressionPtr BinaryOpExpression::unneededHelper() {
bool shortCircuit = isShortCircuitOperator();
if (!m_exp2->getContainedEffects() ||
(!shortCircuit && !m_exp1->getContainedEffects())) {
return Expression::unneededHelper();
}
if (shortCircuit) {
m_exp2 = m_exp2->unneeded();
m_exp2->setExpectedType(Type::Boolean);
}
return static_pointer_cast<Expression>(shared_from_this());
}
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
int BinaryOpExpression::getLocalEffects() const {
int effect = NoEffect;
m_canThrow = false;
switch (m_op) {
case '/':
case '%':
case T_DIV_EQUAL:
case T_MOD_EQUAL: {
Variant v2;
if (!m_exp2->getScalarValue(v2) || equal(v2, 0)) {
effect = CanThrow;
m_canThrow = true;
}
break;
}
default:
break;
}
if (m_assign) effect |= AssignEffect;
return effect;
}
void BinaryOpExpression::analyzeProgram(AnalysisResultPtr ar) {
if (ar->getPhase() == AnalysisResult::AnalyzeFinal &&
m_op == T_INSTANCEOF && m_exp2->is(Expression::KindOfScalarExpression)) {
ScalarExpressionPtr s = dynamic_pointer_cast<ScalarExpression>(m_exp2);
addUserClass(ar, s->getString());
}
m_exp1->analyzeProgram(ar);
m_exp2->analyzeProgram(ar);
}
ExpressionPtr BinaryOpExpression::simplifyLogical(AnalysisResultConstPtr ar) {
try {
ExpressionPtr rep = foldConst(ar);
if (rep) return replaceValue(rep);
} catch (const Exception& e) {
}
return ExpressionPtr();
}
ConstructPtr BinaryOpExpression::getNthKid(int n) const {
switch (n) {
case 0:
return m_exp1;
case 1:
return m_exp2;
default:
assert(false);
break;
}
return ConstructPtr();
}
int BinaryOpExpression::getKidCount() const {
return 2;
}
void BinaryOpExpression::setNthKid(int n, ConstructPtr cp) {
switch (n) {
case 0:
m_exp1 = boost::dynamic_pointer_cast<Expression>(cp);
break;
case 1:
m_exp2 = boost::dynamic_pointer_cast<Expression>(cp);
break;
default:
assert(false);
break;
}
}
bool BinaryOpExpression::canonCompare(ExpressionPtr e) const {
return Expression::canonCompare(e) &&
getOp() == static_cast<BinaryOpExpression*>(e.get())->getOp();
}
ExpressionPtr BinaryOpExpression::preOptimize(AnalysisResultConstPtr ar) {
if (!m_exp2->isScalar()) {
if (!m_exp1->isScalar()) {
if (m_exp1->is(KindOfBinaryOpExpression)) {
BinaryOpExpressionPtr b(
dynamic_pointer_cast<BinaryOpExpression>(m_exp1));
if (b->m_op == m_op && b->m_exp1->isScalar()) {
return foldRightAssoc(ar);
}
}
return ExpressionPtr();
}
} else if (m_canThrow && !(getLocalEffects() & CanThrow)) {
recomputeEffects();
}
ExpressionPtr optExp;
try {
optExp = foldConst(ar);
} catch (Exception &e) {
// runtime/base threw an exception, perhaps bad operands
}
if (optExp) optExp = replaceValue(optExp);
return optExp;
}
ExpressionPtr BinaryOpExpression::simplifyArithmetic(
AnalysisResultConstPtr ar) {
Variant v1;
Variant v2;
if (m_exp1->getScalarValue(v1)) {
if (v1.isInteger()) {
int64_t ival1 = v1.toInt64();
// 1 * $a => $a, 0 + $a => $a
if ((ival1 == 1 && m_op == '*') || (ival1 == 0 && m_op == '+')) {
TypePtr actType2 = m_exp2->getActualType();
TypePtr expType = getExpectedType();
if (actType2 &&
(actType2->mustBe(Type::KindOfNumeric) ||
(expType && expType->mustBe(Type::KindOfNumeric) &&
!actType2->couldBe(Type::KindOfArray) &&
Type::IsCastNeeded(ar, actType2, expType)))) {
return m_exp2;
}
}
} else if (v1.isString()) {
String sval1 = v1.toString();
if ((sval1.empty() && m_op == '.')) {
TypePtr actType2 = m_exp2->getActualType();
TypePtr expType = getExpectedType();
// '' . $a => $a
if ((expType && expType->is(Type::KindOfString)) ||
(actType2 && actType2->is(Type::KindOfString))) {
return m_exp2;
}
ExpressionPtr rep(new UnaryOpExpression(
getScope(), getLocation(),
m_exp2, T_STRING_CAST, true));
rep->setActualType(Type::String);
return rep;
}
}
}
if (m_exp2->getScalarValue(v2)) {
if (v2.isInteger()) {
int64_t ival2 = v2.toInt64();
// $a * 1 => $a, $a + 0 => $a
if ((ival2 == 1 && m_op == '*') || (ival2 == 0 && m_op == '+')) {
TypePtr actType1 = m_exp1->getActualType();
TypePtr expType = getExpectedType();
if (actType1 &&
(actType1->mustBe(Type::KindOfNumeric) ||
(expType && expType->mustBe(Type::KindOfNumeric) &&
!actType1->couldBe(Type::KindOfArray) &&
Type::IsCastNeeded(ar, actType1, expType)))) {
return m_exp1;
}
}
} else if (v2.isString()) {
String sval2 = v2.toString();
if ((sval2.empty() && m_op == '.')) {
TypePtr actType1 = m_exp1->getActualType();
TypePtr expType = getExpectedType();
// $a . '' => $a
if ((expType && expType->is(Type::KindOfString)) ||
(actType1 && actType1->is(Type::KindOfString))) {
return m_exp1;
}
ExpressionPtr rep(new UnaryOpExpression(
getScope(), getLocation(),
m_exp1, T_STRING_CAST, true));
rep->setActualType(Type::String);
return rep;
}
}
}
return ExpressionPtr();
}
void BinaryOpExpression::optimizeTypes(AnalysisResultConstPtr ar) {
switch (m_op) {
case '<':
case T_IS_SMALLER_OR_EQUAL:
case '>':
case T_IS_GREATER_OR_EQUAL:
case T_IS_IDENTICAL:
case T_IS_NOT_IDENTICAL:
case T_IS_EQUAL:
case T_IS_NOT_EQUAL:
{
// not needed for correctness, but will allow us to
// generate better code, since we can use the more
// specific runtime function
TypePtr a1(m_exp1->getActualType());
TypePtr i1(m_exp1->getImplementedType());
if (a1 && i1 &&
Type::IsMappedToVariant(i1) && Type::HasFastCastMethod(a1)) {
m_exp1->setExpectedType(a1);
}
TypePtr a2(m_exp2->getActualType());
TypePtr i2(m_exp2->getImplementedType());
if (a2 && i2 &&
Type::IsMappedToVariant(i2) && Type::HasFastCastMethod(a2)) {
m_exp2->setExpectedType(a2);
}
}
default: break;
}
}
ExpressionPtr BinaryOpExpression::postOptimize(AnalysisResultConstPtr ar) {
optimizeTypes(ar);
ExpressionPtr optExp = simplifyArithmetic(ar);
if (!optExp) {
if (isShortCircuitOperator()) optExp = simplifyLogical(ar);
}
if (optExp) optExp = replaceValue(optExp);
return optExp;
}
static ExpressionPtr makeIsNull(AnalysisResultConstPtr ar,
LocationPtr loc, ExpressionPtr exp,
bool invert) {
/* Replace "$x === null" with an is_null call; this requires slightly
* less work at runtime. */
ExpressionListPtr expList =
ExpressionListPtr(new ExpressionList(exp->getScope(), loc));
expList->insertElement(exp);
SimpleFunctionCallPtr call
(new SimpleFunctionCall(exp->getScope(), loc,
"is_null", false, expList, ExpressionPtr()));
call->setValid();
call->setActualType(Type::Boolean);
call->setupScopes(ar);
ExpressionPtr result(call);
if (invert) {
result = ExpressionPtr(new UnaryOpExpression(
exp->getScope(), loc,
result, '!', true));
}
return result;
}
// foldConst() is callable from the parse phase as well as the analysis phase.
// We take advantage of this during the parse phase to reduce very simple
// expressions down to a single scalar and keep the parse tree smaller,
// especially in cases of long chains of binary operators. However, we limit
// the effectivness of this during parse to ensure that we eliminate only
// very simple scalars that don't require analysis in later phases. For now,
// that's just simply scalar values.
ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
ExpressionPtr optExp;
Variant v1;
Variant v2;
if (!m_exp2->getScalarValue(v2)) {
if ((ar->getPhase() != AnalysisResult::ParseAllFiles) &&
m_exp1->isScalar() && m_exp1->getScalarValue(v1)) {
switch (m_op) {
case T_IS_IDENTICAL:
case T_IS_NOT_IDENTICAL:
if (v1.isNull()) {
return makeIsNull(ar, getLocation(), m_exp2,
m_op == T_IS_NOT_IDENTICAL);
}
break;
case T_LOGICAL_AND:
case T_BOOLEAN_AND:
case T_LOGICAL_OR:
case T_BOOLEAN_OR: {
ExpressionPtr rep =
v1.toBoolean() == (m_op == T_LOGICAL_AND ||
m_op == T_BOOLEAN_AND) ? m_exp2 : m_exp1;
rep = ExpressionPtr(
new UnaryOpExpression(
getScope(), getLocation(),
rep, T_BOOL_CAST, true));
rep->setActualType(Type::Boolean);
return replaceValue(rep);
}
case '+':
case '.':
case '*':
case '&':
case '|':
case '^':
if (m_exp2->is(KindOfBinaryOpExpression)) {
BinaryOpExpressionPtr binOpExp =
dynamic_pointer_cast<BinaryOpExpression>(m_exp2);
if (binOpExp->m_op == m_op && binOpExp->m_exp1->isScalar()) {
ExpressionPtr aExp = m_exp1;
ExpressionPtr bExp = binOpExp->m_exp1;
ExpressionPtr cExp = binOpExp->m_exp2;
m_exp1 = binOpExp = Clone(binOpExp);
m_exp2 = cExp;
binOpExp->m_exp1 = aExp;
binOpExp->m_exp2 = bExp;
if (ExpressionPtr optExp = binOpExp->foldConst(ar)) {
m_exp1 = optExp;
}
return static_pointer_cast<Expression>(shared_from_this());
}
}
break;
default:
break;
}
}
return ExpressionPtr();
}
if (m_exp1->isScalar()) {
if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
try {
ScalarExpressionPtr scalar1 =
dynamic_pointer_cast<ScalarExpression>(m_exp1);
ScalarExpressionPtr scalar2 =
dynamic_pointer_cast<ScalarExpression>(m_exp2);
// Some data, like the values of __CLASS__ and friends, are not available
// while we're still in the initial parse phase.
if (ar->getPhase() == AnalysisResult::ParseAllFiles) {
if ((scalar1 && scalar1->needsTranslation()) ||
(scalar2 && scalar2->needsTranslation())) {
return ExpressionPtr();
}
}
if (!Option::WholeProgram || !Option::ParseTimeOpts) {
// In the VM, don't optimize __CLASS__ if within a trait, since
// __CLASS__ is not resolved yet.
ClassScopeRawPtr clsScope = getOriginalClass();
if (clsScope && clsScope->isTrait()) {
if ((scalar1 && scalar1->getType() == T_CLASS_C) ||
(scalar2 && scalar2->getType() == T_CLASS_C)) {
return ExpressionPtr();
}
}
}
Variant result;
switch (m_op) {
case T_LOGICAL_XOR:
result = static_cast<bool>(v1.toBoolean() ^ v2.toBoolean());
break;
case '|':
*result.asCell() = cellBitOr(*v1.asCell(), *v2.asCell());
break;
case '&':
*result.asCell() = cellBitAnd(*v1.asCell(), *v2.asCell());
break;
case '^':
*result.asCell() = cellBitXor(*v1.asCell(), *v2.asCell());
break;
case '.':
result = concat(v1.toString(), v2.toString());
break;
case T_IS_IDENTICAL:
result = same(v1, v2);
break;
case T_IS_NOT_IDENTICAL:
result = !same(v1, v2);
break;
case T_IS_EQUAL:
result = equal(v1, v2);
break;
case T_IS_NOT_EQUAL:
result = !equal(v1, v2);
break;
case '<':
result = less(v1, v2);
break;
case T_IS_SMALLER_OR_EQUAL:
result = cellLessOrEqual(*v1.asCell(), *v2.asCell());
break;
case '>':
result = more(v1, v2);
break;
case T_IS_GREATER_OR_EQUAL:
result = cellGreaterOrEqual(*v1.asCell(), *v2.asCell());
break;
case '+':
*result.asCell() = cellAdd(*v1.asCell(), *v2.asCell());
break;
case '-':
*result.asCell() = cellSub(*v1.asCell(), *v2.asCell());
break;
case '*':
*result.asCell() = cellMul(*v1.asCell(), *v2.asCell());
break;
case '/':
if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
return ExpressionPtr();
}
*result.asCell() = cellDiv(*v1.asCell(), *v2.asCell());
break;
case '%':
if ((v2.isIntVal() && v2.toInt64() == 0) || v2.toDouble() == 0.0) {
return ExpressionPtr();
}
*result.asCell() = cellMod(*v1.asCell(), *v2.asCell());
break;
case T_SL:
result = v1.toInt64() << v2.toInt64();
break;
case T_SR:
result = v1.toInt64() >> v2.toInt64();
break;
case T_BOOLEAN_OR:
result = v1.toBoolean() || v2.toBoolean(); break;
case T_BOOLEAN_AND:
result = v1.toBoolean() && v2.toBoolean(); break;
case T_LOGICAL_OR:
result = v1.toBoolean() || v2.toBoolean(); break;
case T_LOGICAL_AND:
result = v1.toBoolean() && v2.toBoolean(); break;
case T_INSTANCEOF: {
if (v1.isArray() && v2.isString() &&
interface_supports_array(v2.getStringData())) {
result = true;
break;
}
result = false;
break;
}
default:
return ExpressionPtr();
}
return makeScalarExpression(ar, result);
} catch (...) {
}
} else if (ar->getPhase() != AnalysisResult::ParseAllFiles) {
switch (m_op) {
case T_LOGICAL_AND:
case T_BOOLEAN_AND:
case T_LOGICAL_OR:
case T_BOOLEAN_OR: {
bool useFirst = v2.toBoolean() == (m_op == T_LOGICAL_AND ||
m_op == T_BOOLEAN_AND);
ExpressionPtr rep = useFirst ? m_exp1 : m_exp2;
rep = ExpressionPtr(
new UnaryOpExpression(
getScope(), getLocation(),
rep, T_BOOL_CAST, true));
rep->setActualType(Type::Boolean);
if (!useFirst) {
ExpressionListPtr l(
new ExpressionList(
getScope(), getLocation(),
ExpressionList::ListKindComma));
l->addElement(m_exp1);
l->addElement(rep);
l->setActualType(Type::Boolean);
rep = l;
}
rep->setExpectedType(getExpectedType());
return replaceValue(rep);
}
case T_LOGICAL_XOR:
case '|':
case '&':
case '^':
case '.':
case '+':
case '*':
optExp = foldRightAssoc(ar);
if (optExp) return optExp;
break;
case T_IS_IDENTICAL:
case T_IS_NOT_IDENTICAL:
if (v2.isNull()) {
return makeIsNull(ar, getLocation(), m_exp1,
m_op == T_IS_NOT_IDENTICAL);
}
break;
default:
break;
}
}
return ExpressionPtr();
}
ExpressionPtr
BinaryOpExpression::foldRightAssoc(AnalysisResultConstPtr ar) {
ExpressionPtr optExp1;
switch (m_op) {
case '.':
case '+':
case '*':
if (m_exp1->is(Expression::KindOfBinaryOpExpression)) {
BinaryOpExpressionPtr binOpExp =
dynamic_pointer_cast<BinaryOpExpression>(m_exp1);
if (binOpExp->m_op == m_op) {
// turn a Op b Op c, namely (a Op b) Op c into a Op (b Op c)
ExpressionPtr aExp = binOpExp->m_exp1;
ExpressionPtr bExp = binOpExp->m_exp2;
ExpressionPtr cExp = m_exp2;
m_exp1 = aExp;
m_exp2 = binOpExp = Clone(binOpExp);
binOpExp->m_exp1 = bExp;
binOpExp->m_exp2 = cExp;
if (ExpressionPtr optExp = binOpExp->foldConst(ar)) {
m_exp2 = optExp;
}
return static_pointer_cast<Expression>(shared_from_this());
}
}
break;
default:
break;
}
return ExpressionPtr();
}
TypePtr BinaryOpExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
TypePtr et1; // expected m_exp1's type
bool coerce1 = false; // whether m_exp1 needs to coerce to et1
TypePtr et2; // expected m_exp2's type
bool coerce2 = false; // whether m_exp2 needs to coerce to et2
TypePtr rt; // return type
switch (m_op) {
case '+':
case T_PLUS_EQUAL:
if (coerce && Type::SameType(type, Type::Array)) {
et1 = et2 = Type::Array;
coerce1 = coerce2 = true;
rt = Type::Array;
} else {
et1 = Type::PlusOperand;
et2 = Type::PlusOperand;
rt = Type::PlusOperand;
}
break;
case '-':
case '*':
case T_MINUS_EQUAL:
case T_MUL_EQUAL:
case '/':
case T_DIV_EQUAL:
et1 = Type::Numeric;
et2 = Type::Numeric;
rt = Type::Numeric;
break;
case '.':
et1 = et2 = rt = Type::String;
break;
case T_CONCAT_EQUAL:
et1 = et2 = Type::String;
rt = Type::Variant;
break;
case '%':
et1 = et2 = Type::Int64;
rt = Type::Numeric;
break;
case T_MOD_EQUAL:
et1 = Type::Numeric;
et2 = Type::Int64;
rt = Type::Numeric;
break;
case '|':
case '&':
case '^':
case T_AND_EQUAL:
case T_OR_EQUAL:
case T_XOR_EQUAL:
et1 = Type::Primitive;
et2 = Type::Primitive;
rt = Type::Primitive;
break;
case T_SL:
case T_SR:
case T_SL_EQUAL:
case T_SR_EQUAL:
et1 = et2 = rt = Type::Int64;
break;
case T_BOOLEAN_OR:
case T_BOOLEAN_AND:
case T_LOGICAL_OR:
case T_LOGICAL_AND:
case T_LOGICAL_XOR:
et1 = et2 = rt = Type::Boolean;
break;
case '<':
case T_IS_SMALLER_OR_EQUAL:
case '>':
case T_IS_GREATER_OR_EQUAL:
case T_IS_IDENTICAL:
case T_IS_NOT_IDENTICAL:
case T_IS_EQUAL:
case T_IS_NOT_EQUAL:
et1 = Type::Some;
et2 = Type::Some;
rt = Type::Boolean;
break;
case T_INSTANCEOF:
et1 = Type::Any;
et2 = Type::String;
rt = Type::Boolean;
break;
case T_COLLECTION:
et1 = Type::Any;
et2 = Type::Any;
rt = Type::Object;
break;
default:
assert(false);
}
switch (m_op) {
case T_PLUS_EQUAL:
{
TypePtr rhs = m_exp2->inferAndCheck(ar, et2, coerce2);
TypePtr lhs = m_exp1->inferAndCheck(ar, Type::Any, true);
if (lhs) {
if (lhs->mustBe(Type::KindOfArray)) {
TypePtr a2(m_exp2->getActualType());
if (a2 && a2->is(Type::KindOfArray)) {
m_exp2->setExpectedType(a2);
}
rt = Type::Array;
break;
}
if (lhs->mustBe(Type::KindOfNumeric)) {
if (!rhs->mustBe(lhs->getKindOf())) {
rhs = Type::combinedArithmeticType(lhs, rhs);
if (!rhs) rhs = Type::Numeric;
m_exp1->inferAndCheck(ar, rhs, true);
}
TypePtr a1(m_exp1->getCPPType());
TypePtr a2(m_exp2->getActualType());
if (a1 && a1->mustBe(Type::KindOfNumeric) &&
a2 && a2->mustBe(Type::KindOfNumeric)) {
// both LHS and RHS are numeric.
// Set the expected type of RHS to be
// the stronger type
TypePtr t = a1->getKindOf() > a2->getKindOf() ? a1 : a2;
m_exp2->setExpectedType(t);
}
rt = Type::Numeric;
break;
}
}
m_exp1->inferAndCheck(ar, rhs, true);
}
break;
case T_MINUS_EQUAL:
case T_MUL_EQUAL:
case T_DIV_EQUAL:
case T_MOD_EQUAL:
case T_AND_EQUAL:
case T_OR_EQUAL:
case T_XOR_EQUAL:
case T_SL_EQUAL:
case T_SR_EQUAL:
{
TypePtr ret = m_exp2->inferAndCheck(ar, et2, coerce2);
m_exp1->inferAndCheck(ar, ret, true);
}
break;
case T_CONCAT_EQUAL:
{
TypePtr ret = m_exp2->inferAndCheck(ar, et2, coerce2);
m_exp1->inferAndCheck(ar, Type::String, true);
TypePtr act1 = m_exp1->getActualType();
if (act1 && act1->is(Type::KindOfString)) rt = Type::String;
}
break;
case '+':
case '-':
case '*':
{
m_exp1->inferAndCheck(ar, et1, coerce1);
m_exp2->inferAndCheck(ar, et2, coerce2);
TypePtr act1 = m_exp1->getActualType();
TypePtr act2 = m_exp2->getActualType();
TypePtr combined = Type::combinedArithmeticType(act1, act2);
if (combined && combined->isSubsetOf(rt)) {
if (act1) m_exp1->setExpectedType(act1);
if (act2) m_exp2->setExpectedType(act2);
rt = combined;
} else if (m_op == '+') {
bool a1 = act1 && act1->is(Type::KindOfArray);
bool a2 = act2 && act2->is(Type::KindOfArray);
if (a1 || a2) {
m_implementedType.reset();
if (!a1) {
m_implementedType = Type::Variant;
} else if (!a2) {
m_exp1->setExpectedType(Type::Array);
// in this case, the implemented type will
// actually be Type::Array (since Array::operator+
// returns an Array)
} else {
m_exp1->setExpectedType(Type::Array);
m_exp2->setExpectedType(Type::Array);
}
rt = Type::Array;
}
}
}
break;
default:
m_exp1->inferAndCheck(ar, et1, coerce1);
m_exp2->inferAndCheck(ar, et2, coerce2);
break;
}
return rt;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void BinaryOpExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_exp1->outputPHP(cg, ar);
switch (m_op) {
case T_PLUS_EQUAL: cg_printf(" += "); break;
case T_MINUS_EQUAL: cg_printf(" -= "); break;
case T_MUL_EQUAL: cg_printf(" *= "); break;
case T_DIV_EQUAL: cg_printf(" /= "); break;
case T_CONCAT_EQUAL: cg_printf(" .= "); break;
case T_MOD_EQUAL: cg_printf(" %%= "); break;
case T_AND_EQUAL: cg_printf(" &= "); break;
case T_OR_EQUAL: cg_printf(" |= "); break;
case T_XOR_EQUAL: cg_printf(" ^= "); break;
case T_SL_EQUAL: cg_printf(" <<= "); break;
case T_SR_EQUAL: cg_printf(" >>= "); break;
case T_BOOLEAN_OR: cg_printf(" || "); break;
case T_BOOLEAN_AND: cg_printf(" && "); break;
case T_LOGICAL_OR: cg_printf(" or "); break;
case T_LOGICAL_AND: cg_printf(" and "); break;
case T_LOGICAL_XOR: cg_printf(" xor "); break;
case '|': cg_printf(" | "); break;
case '&': cg_printf(" & "); break;
case '^': cg_printf(" ^ "); break;
case '.': cg_printf(" . "); break;
case '+': cg_printf(" + "); break;
case '-': cg_printf(" - "); break;
case '*': cg_printf(" * "); break;
case '/': cg_printf(" / "); break;
case '%': cg_printf(" %% "); break;
case T_SL: cg_printf(" << "); break;
case T_SR: cg_printf(" >> "); break;
case T_IS_IDENTICAL: cg_printf(" === "); break;
case T_IS_NOT_IDENTICAL: cg_printf(" !== "); break;
case T_IS_EQUAL: cg_printf(" == "); break;
case T_IS_NOT_EQUAL: cg_printf(" != "); break;
case '<': cg_printf(" < "); break;
case T_IS_SMALLER_OR_EQUAL: cg_printf(" <= "); break;
case '>': cg_printf(" > "); break;
case T_IS_GREATER_OR_EQUAL: cg_printf(" >= "); break;
case T_INSTANCEOF: cg_printf(" instanceof "); break;
case T_COLLECTION: {
ExpressionListPtr el = static_pointer_cast<ExpressionList>(m_exp2);
if (el->getCount() == 0) {
cg_printf(" {}");
} else {
cg_printf(" { ");
el->outputPHP(cg, ar);
cg_printf(" }");
}
return;
}
default:
assert(false);
}
m_exp2->outputPHP(cg, ar);
}
bool BinaryOpExpression::isOpEqual() {
switch (m_op) {
case T_CONCAT_EQUAL:
case T_PLUS_EQUAL:
case T_MINUS_EQUAL:
case T_MUL_EQUAL:
case T_DIV_EQUAL:
case T_MOD_EQUAL:
case T_AND_EQUAL:
case T_OR_EQUAL:
case T_XOR_EQUAL:
case T_SL_EQUAL:
case T_SR_EQUAL:
return true;
default:
break;
}
return false;
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __BINARY_OP_EXPRESSION_H__
#define __BINARY_OP_EXPRESSION_H__
#ifndef incl_HPHP_BINARY_OP_EXPRESSION_H_
#define incl_HPHP_BINARY_OP_EXPRESSION_H_
#include <compiler/expression/expression_list.h>
#include "hphp/compiler/expression/expression_list.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -41,6 +41,7 @@ public:
virtual bool isRefable(bool checkError = false) const;
bool isShortCircuitOperator() const;
bool isLogicalOrOperator() const;
ExpressionPtr getStoreVariable() const { return m_exp1;}
ExpressionPtr getExp1() { return m_exp1;}
ExpressionPtr getExp2() { return m_exp2;}
int getOp() const { return m_op;}
@@ -51,13 +52,6 @@ public:
virtual ExpressionPtr unneededHelper();
virtual bool canonCompare(ExpressionPtr e) const;
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool outputCPPImplOpEqual(CodeGenerator &cg, AnalysisResultPtr ar);
static int getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp,
bool &hasVoid);
bool isAssignmentOp() const { return m_assign; }
@@ -77,4 +71,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __BINARY_OP_EXPRESSION_H__
#endif // incl_HPHP_BINARY_OP_EXPRESSION_H_
@@ -0,0 +1,237 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/class_constant_expression.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/constant_table.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/util/hash.h"
#include "hphp/util/util.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/expression/constant_expression.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
ClassConstantExpression::ClassConstantExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionPtr classExp, const std::string &varName)
: Expression(
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClassConstantExpression)),
StaticClassName(classExp), m_varName(varName), m_defScope(nullptr),
m_valid(false), m_depsSet(false) {
}
ExpressionPtr ClassConstantExpression::clone() {
ClassConstantExpressionPtr exp(new ClassConstantExpression(*this));
Expression::deepCopy(exp);
exp->m_class = Clone(m_class);
exp->m_depsSet = false;
return exp;
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
bool ClassConstantExpression::containsDynamicConstant(AnalysisResultPtr ar)
const {
if (m_class) return true;
ClassScopePtr cls = ar->findClass(m_className);
return !cls || cls->isVolatile() ||
!cls->getConstants()->isRecursivelyDeclared(ar, m_varName);
}
void ClassConstantExpression::analyzeProgram(AnalysisResultPtr ar) {
if (m_class) {
m_class->analyzeProgram(ar);
} else if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
if (ClassScopePtr cls = resolveClass()) {
ConstructPtr decl = cls->getConstants()->
getValueRecur(ar, m_varName, cls);
cls->addUse(getScope(), BlockScope::UseKindConstRef);
m_depsSet = true;
if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
if (!isPresent()) {
getScope()->getVariables()->
setAttribute(VariableTable::NeedGlobalPointer);
}
}
}
addUserClass(ar, m_className);
}
}
string ClassConstantExpression::getActualClassName() const {
if (m_defScope) {
return static_cast<ClassScope*>(m_defScope)->getId();
}
return m_className;
}
ConstructPtr ClassConstantExpression::getNthKid(int n) const {
switch (n) {
case 0:
return m_class;
default:
assert(false);
break;
}
return ConstructPtr();
}
int ClassConstantExpression::getKidCount() const {
return 1;
}
void ClassConstantExpression::setNthKid(int n, ConstructPtr cp) {
switch (n) {
case 0:
m_class = boost::dynamic_pointer_cast<Expression>(cp);
break;
default:
assert(false);
break;
}
}
ExpressionPtr ClassConstantExpression::preOptimize(AnalysisResultConstPtr ar) {
if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
return ExpressionPtr();
}
if (m_class) {
updateClassName();
if (m_class) {
return ExpressionPtr();
}
}
ClassScopePtr cls = resolveClass();
if (!cls || (cls->isVolatile() && !isPresent())) {
if (cls && !m_depsSet) {
cls->addUse(getScope(), BlockScope::UseKindConstRef);
m_depsSet = true;
}
return ExpressionPtr();
}
ConstantTablePtr constants = cls->getConstants();
ClassScopePtr defClass = cls;
ConstructPtr decl = constants->getValueRecur(ar, m_varName, defClass);
if (decl) {
BlockScope::s_constMutex.lock();
ExpressionPtr value = dynamic_pointer_cast<Expression>(decl);
BlockScope::s_constMutex.unlock();
if (!value->isScalar() &&
(value->is(KindOfClassConstantExpression) ||
value->is(KindOfConstantExpression))) {
std::set<ExpressionPtr> seen;
do {
if (!seen.insert(value).second) return ExpressionPtr();
value = value->preOptimize(ar);
if (!value) return ExpressionPtr();
} while (!value->isScalar() &&
(value->is(KindOfClassConstantExpression) ||
value->is(KindOfConstantExpression)));
}
ExpressionPtr rep = Clone(value, getScope());
rep->setComment(getText());
rep->setLocation(getLocation());
return replaceValue(rep);
}
return ExpressionPtr();
}
TypePtr ClassConstantExpression::inferTypes(AnalysisResultPtr ar,
TypePtr type, bool coerce) {
m_valid = false;
ConstructPtr self = shared_from_this();
if (m_class) {
m_class->inferAndCheck(ar, Type::Any, false);
return Type::Variant;
}
ClassScopePtr cls = resolveClassWithChecks();
if (!cls) {
return Type::Variant;
}
ClassScopePtr defClass = cls;
ConstructPtr decl =
cls->getConstants()->getDeclarationRecur(ar, m_varName, defClass);
if (decl) { // No decl means an extension class or derived from redeclaring
cls = defClass;
m_valid = true;
if (cls->isUserClass()) {
cls->addUse(getScope(), BlockScope::UseKindConstRef);
}
}
BlockScope *defScope;
// checkConst grabs locks for us
TypePtr t = cls->checkConst(getScope(), m_varName, type,
coerce, ar,
shared_from_this(),
cls->getBases(), defScope);
if (defScope) {
m_valid = true;
m_defScope = defScope;
} else if (cls->derivesFromRedeclaring()) {
m_defScope = cls.get();
}
return t;
}
unsigned ClassConstantExpression::getCanonHash() const {
int64_t val =
hash_string(Util::toLower(m_varName).c_str(), m_varName.size()) -
hash_string(Util::toLower(m_className).c_str(), m_className.size());
return ~unsigned(val) ^ unsigned(val >> 32);
}
bool ClassConstantExpression::canonCompare(ExpressionPtr e) const {
return Expression::canonCompare(e) &&
m_varName == static_cast<ClassConstantExpression*>(e.get())->m_varName &&
m_className == static_cast<ClassConstantExpression*>(e.get())->m_className;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void ClassConstantExpression::outputPHP(CodeGenerator &cg,
AnalysisResultPtr ar) {
StaticClassName::outputPHP(cg, ar);
cg_printf("::%s", m_varName.c_str());
}
bool ClassConstantExpression::isDynamic() const {
if (!m_valid) return true;
return m_defScope->getConstants()->isDynamic(m_varName);
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,11 +14,11 @@
+----------------------------------------------------------------------+
*/
#ifndef __CLASS_CONSTANT_EXPRESSION_H__
#define __CLASS_CONSTANT_EXPRESSION_H__
#ifndef incl_HPHP_CLASS_CONSTANT_EXPRESSION_H_
#define incl_HPHP_CLASS_CONSTANT_EXPRESSION_H_
#include <compiler/expression/static_class_name.h>
#include <compiler/analysis/block_scope.h>
#include "hphp/compiler/expression/static_class_name.h"
#include "hphp/compiler/analysis/block_scope.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -55,4 +55,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __CLASS_CONSTANT_EXPRESSION_H__
#endif // incl_HPHP_CLASS_CONSTANT_EXPRESSION_H_
@@ -0,0 +1,298 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/closure_expression.h"
#include "hphp/compiler/expression/parameter_expression.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/statement/function_statement.h"
#include "hphp/compiler/statement/static_statement.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/file_scope.h"
using namespace HPHP;
TypePtr ClosureExpression::s_ClosureType =
Type::CreateObjectType("closure"); // needs lower case
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
ClosureExpression::ClosureExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, FunctionStatementPtr func,
ExpressionListPtr vars)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClosureExpression)),
m_func(func) {
if (vars) {
m_vars = ExpressionListPtr
(new ExpressionList(vars->getScope(), vars->getLocation()));
// push the vars in reverse order, not retaining duplicates
std::set<string> seenBefore;
// Because PHP is insane you can have a use variable with the same
// name as a param name.
// In that case, params win (which is different than zend but much easier)
ExpressionListPtr bodyParams = m_func->getParams();
if (bodyParams) {
int nParams = bodyParams->getCount();
for (int i = 0; i < nParams; i++) {
ParameterExpressionPtr par(
static_pointer_cast<ParameterExpression>((*bodyParams)[i]));
seenBefore.insert(par->getName());
}
}
for (int i = vars->getCount() - 1; i >= 0; i--) {
ParameterExpressionPtr param(
dynamic_pointer_cast<ParameterExpression>((*vars)[i]));
assert(param);
if (param->getName() == "this") {
// "this" is automatically included.
// Once we get rid of all the callsites, make this an error
continue;
}
if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) {
seenBefore.insert(param->getName().c_str());
m_vars->insertElement(param);
}
}
if (m_vars) {
m_values = ExpressionListPtr
(new ExpressionList(m_vars->getScope(), m_vars->getLocation()));
for (int i = 0; i < m_vars->getCount(); i++) {
ParameterExpressionPtr param =
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
const string &name = param->getName();
SimpleVariablePtr var(new SimpleVariable(param->getScope(),
param->getLocation(),
name));
if (param->isRef()) {
var->setContext(RefValue);
}
m_values->addElement(var);
}
assert(m_vars->getCount() == m_values->getCount());
}
}
}
ExpressionPtr ClosureExpression::clone() {
ClosureExpressionPtr exp(new ClosureExpression(*this));
Expression::deepCopy(exp);
// don't clone the function statement or the vars, since
// they are shared with the function scope
exp->m_func = m_func;
exp->m_vars = m_vars;
exp->m_values = Clone(m_values);
return exp;
}
ConstructPtr ClosureExpression::getNthKid(int n) const {
switch (n) {
case 0:
return m_values;
default:
assert(false);
break;
}
return ConstructPtr();
}
int ClosureExpression::getKidCount() const {
return 1;
}
void ClosureExpression::setNthKid(int n, ConstructPtr cp) {
switch (n) {
case 0:
m_values = boost::dynamic_pointer_cast<ExpressionList>(cp);
break;
default:
assert(false);
break;
}
}
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
void ClosureExpression::analyzeProgram(AnalysisResultPtr ar) {
m_func->analyzeProgram(ar);
if (m_vars) {
m_values->analyzeProgram(ar);
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
getFunctionScope()->addUse(m_func->getFunctionScope(),
BlockScope::UseKindClosure);
m_func->getFunctionScope()->setClosureVars(m_vars);
// closure function's variable table (not containing function's)
VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
VariableTablePtr containing = getFunctionScope()->getVariables();
for (int i = 0; i < m_vars->getCount(); i++) {
ParameterExpressionPtr param =
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
const string &name = param->getName();
{
Symbol *containingSym = containing->addDeclaredSymbol(name, param);
containingSym->setPassClosureVar();
Symbol *sym = variables->addDeclaredSymbol(name, param);
sym->setClosureVar();
sym->setDeclaration(ConstructPtr());
if (param->isRef()) {
sym->setRefClosureVar();
sym->setUsed();
} else {
sym->clearRefClosureVar();
sym->clearUsed();
}
}
}
return;
}
if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
// closure function's variable table (not containing function's)
VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
for (int i = 0; i < m_vars->getCount(); i++) {
ParameterExpressionPtr param =
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
const string &name = param->getName();
// so we can assign values to them, instead of seeing CVarRef
Symbol *sym = variables->getSymbol(name);
if (sym && sym->isParameter()) {
sym->setLvalParam();
}
}
}
}
FunctionScopeRawPtr container =
getFunctionScope()->getContainingNonClosureFunction();
if (container && container->isStatic()) {
m_func->getModifiers()->add(T_STATIC);
}
}
TypePtr ClosureExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
if (m_vars) {
assert(m_values && m_values->getCount() == m_vars->getCount());
// containing function's variable table (not closure function's)
VariableTablePtr variables = getScope()->getVariables();
// closure function's variable table
VariableTablePtr cvariables = m_func->getFunctionScope()->getVariables();
// force all reference use vars into variant for this function scope
for (int i = 0; i < m_vars->getCount(); i++) {
ParameterExpressionPtr param =
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
const string &name = param->getName();
if (param->isRef()) {
variables->forceVariant(ar, name, VariableTable::AnyVars);
}
}
// infer the types of the values
m_values->inferAndCheck(ar, Type::Some, false);
// coerce the types inferred from m_values into m_vars
for (int i = 0; i < m_vars->getCount(); i++) {
ExpressionPtr value = (*m_values)[i];
ParameterExpressionPtr var =
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
assert(!var->getExpectedType());
assert(!var->getImplementedType());
if (var->isRef()) {
var->setActualType(Type::Variant);
} else {
TypePtr origVarType(var->getActualType() ?
var->getActualType() : Type::Some);
var->setActualType(Type::Coerce(ar, origVarType, value->getType()));
}
}
{
// this lock isn't technically needed for thread-safety, since
// the dependencies are all set up. however, the lock assertions
// will fail if we don't acquire it.
GET_LOCK(m_func->getFunctionScope());
// bootstrap the closure function's variable table with
// the types from m_vars
for (int i = 0; i < m_vars->getCount(); i++) {
ParameterExpressionPtr param =
dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]);
const string &name = param->getName();
cvariables->addParamLike(name, param->getType(), ar,
shared_from_this(),
getScope()->isFirstPass());
}
}
}
return s_ClosureType;
}
bool ClosureExpression::hasStaticLocals() {
ConstructPtr cons(m_func);
return hasStaticLocalsImpl(cons);
}
bool ClosureExpression::hasStaticLocalsImpl(ConstructPtr root) {
if (!root) {
return false;
}
if (root->getFunctionScope() != m_func->getFunctionScope()) {
// new scope, new statics
return false;
}
for (int i = 0; i < root->getKidCount(); i++) {
ConstructPtr cons = root->getNthKid(i);
if (StatementPtr s = dynamic_pointer_cast<Statement>(cons)) {
if (s->is(Statement::KindOfStaticStatement)) {
return true;
}
}
if (hasStaticLocalsImpl(cons)) {
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void ClosureExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_func->outputPHPHeader(cg, ar);
if (m_vars && m_vars->getCount()) {
cg_printf(" use (");
m_vars->outputPHP(cg, ar);
cg_printf(")");
}
m_func->outputPHPBody(cg, ar);
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __CLOSURE_EXPRESSION_H__
#define __CLOSURE_EXPRESSION_H__
#ifndef incl_HPHP_CLOSURE_EXPRESSION_H_
#define incl_HPHP_CLOSURE_EXPRESSION_H_
#include <compiler/expression/expression.h>
#include "hphp/compiler/expression/expression.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -32,7 +32,6 @@ public:
FunctionStatementPtr func, ExpressionListPtr vars);
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
virtual bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
virtual ConstructPtr getNthKid(int n) const;
virtual void setNthKid(int n, ConstructPtr cp);
@@ -41,14 +40,18 @@ public:
FunctionStatementPtr getClosureFunction() { return m_func; }
ExpressionListPtr getClosureVariables() { return m_vars; }
ExpressionListPtr getClosureValues() { return m_values; }
bool hasStaticLocals();
private:
FunctionStatementPtr m_func;
ExpressionListPtr m_vars;
ExpressionListPtr m_values;
static TypePtr s_ClosureType;
bool hasStaticLocalsImpl(ConstructPtr root);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // __CLOSURE_EXPRESSION_H__
#endif // incl_HPHP_CLOSURE_EXPRESSION_H_
@@ -0,0 +1,281 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/constant_expression.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/block_scope.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/constant_table.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/util/hash.h"
#include "hphp/util/util.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/parser/parser.h"
#include "hphp/util/parser/hphp.tab.hpp"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/runtime/ext/ext_misc.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
ConstantExpression::ConstantExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
const string &name, bool hadBackslash, const string &docComment)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ConstantExpression)),
m_name(name), m_origName(name), m_hadBackslash(hadBackslash),
m_docComment(docComment), m_valid(false), m_dynamic(false),
m_visited(false), m_depsSet(false) {
}
void ConstantExpression::onParse(AnalysisResultConstPtr ar,
FileScopePtr scope) {
ar->parseOnDemandByConstant(m_name);
}
ExpressionPtr ConstantExpression::clone() {
ConstantExpressionPtr exp(new ConstantExpression(*this));
Expression::deepCopy(exp);
m_depsSet = false;
return exp;
}
bool ConstantExpression::isScalar() const {
if (m_name == "INF" || m_name == "NAN") return true;
string lower = Util::toLower(m_name);
return lower == "true" || lower == "false" || lower == "null";
}
bool ConstantExpression::isLiteralNull() const {
return isNull();
}
bool ConstantExpression::isNull() const {
string lower = Util::toLower(m_name);
return (lower == "null");
}
bool ConstantExpression::isBoolean() const {
string lower = Util::toLower(m_name);
return (lower == "true" || lower == "false");
}
bool ConstantExpression::isDouble() const {
return (m_name == "INF" || m_name == "NAN");
}
bool ConstantExpression::getBooleanValue() const {
string lower = Util::toLower(m_name);
assert(lower == "true" || lower == "false");
return lower == "true";
}
bool ConstantExpression::getScalarValue(Variant &value) {
if (!isScalar()) return false;
if (isBoolean()) {
value = getBooleanValue();
} else if (m_name == "INF") {
value = k_INF;
} else if (m_name == "NAN") {
value = k_NAN;
} else {
value.unset();
}
return true;
}
unsigned ConstantExpression::getCanonHash() const {
int64_t val = hash_string(Util::toLower(m_name).c_str(), m_name.size());
return ~unsigned(val) ^ unsigned(val >> 32);
}
bool ConstantExpression::canonCompare(ExpressionPtr e) const {
return Expression::canonCompare(e) &&
m_name == static_cast<ConstantExpression*>(e.get())->m_name;
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
Symbol *ConstantExpression::resolveNS(AnalysisResultConstPtr ar) {
BlockScopeConstPtr block = ar->findConstantDeclarer(m_name);
if (!block) {
if (!hadBackslash() && Option::WholeProgram) {
int pos = m_name.rfind('\\');
m_name = m_name.substr(pos + 1);
block = ar->findConstantDeclarer(m_name);
}
if (!block) return 0;
}
Symbol *sym = const_cast<Symbol*>(block->getConstants()->getSymbol(m_name));
always_assert(sym);
return sym;
}
void ConstantExpression::analyzeProgram(AnalysisResultPtr ar) {
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
Symbol *sym = resolveNS(ar);
if (!(m_context & LValue) && !m_dynamic) {
if (sym && !sym->isSystem()) {
if (sym->isDynamic()) {
m_dynamic = true;
} else {
ConstructPtr decl = sym->getDeclaration();
if (decl) {
decl->getScope()->addUse(
getScope(), BlockScope::UseKindConstRef);
m_depsSet = true;
}
}
}
}
} else if (ar->getPhase() == AnalysisResult::AnalyzeFinal && m_dynamic) {
getFileScope()->addConstantDependency(ar, m_name);
}
}
ExpressionPtr ConstantExpression::preOptimize(AnalysisResultConstPtr ar) {
if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
return ExpressionPtr();
}
ConstructPtr decl;
while (!isScalar() && !m_dynamic && !(m_context & LValue)) {
const Symbol *sym = resolveNS(ar);
if (sym &&
(!const_cast<Symbol*>(sym)->checkDefined() || sym->isDynamic())) {
sym = 0;
m_dynamic = true;
}
if (!sym) break;
if (!sym->isSystem()) BlockScope::s_constMutex.lock();
ExpressionPtr value = dynamic_pointer_cast<Expression>(sym->getValue());
if (!sym->isSystem()) BlockScope::s_constMutex.unlock();
if (!value || !value->isScalar()) {
if (!m_depsSet && sym->getDeclaration()) {
sym->getDeclaration()->getScope()->addUse(
getScope(), BlockScope::UseKindConstRef);
m_depsSet = true;
}
break;
}
Variant scalarValue;
if (value->getScalarValue(scalarValue) &&
!scalarValue.isAllowedAsConstantValue()) {
// block further optimization
const_cast<Symbol*>(sym)->setDynamic();
m_dynamic = true;
break;
}
if (sym->isSystem() && !value->is(KindOfScalarExpression)) {
if (ExpressionPtr opt = value->preOptimize(ar)) {
value = opt;
}
}
ExpressionPtr rep = Clone(value, getScope());
rep->setComment(getText());
rep->setLocation(getLocation());
return replaceValue(rep);
}
return ExpressionPtr();
}
TypePtr ConstantExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
if (m_context & LValue) return type; // ClassConstantExpression statement
// special cases: STDIN, STDOUT, STDERR
if (m_name == "STDIN" || m_name == "STDOUT" || m_name == "STDERR") {
m_valid = true;
return Type::Variant;
}
if (m_name == "INF" || m_name == "NAN") {
m_valid = true;
return Type::Double;
}
string lower = Util::toLower(m_name);
TypePtr actualType;
ConstructPtr self = shared_from_this();
if (lower == "true" || lower == "false") {
m_valid = true;
actualType = Type::Boolean;
} else if (lower == "null") {
actualType = Type::Variant;
m_valid = true;
} else {
BlockScopePtr scope;
{
Lock lock(ar->getMutex());
scope = ar->findConstantDeclarer(m_name);
if (!scope) {
scope = getFileScope();
// guarded by ar lock
getFileScope()->declareConstant(ar, m_name);
}
}
assert(scope);
assert(scope->is(BlockScope::ProgramScope) ||
scope->is(BlockScope::FileScope));
ConstantTablePtr constants = scope->getConstants();
ConstructPtr value;
bool isDynamic;
{
Lock lock(scope->getMutex()); // since not class/function scope
// read value and dynamic-ness together + check() atomically
value = constants->getValue(m_name);
isDynamic = constants->isDynamic(m_name);
BlockScope *defScope = nullptr;
std::vector<std::string> bases;
actualType = constants->check(getScope(), m_name, type, coerce,
ar, self, bases, defScope);
}
if (!m_valid) {
if (ar->isSystemConstant(m_name) || value) {
m_valid = true;
}
}
if (!m_dynamic && isDynamic) {
m_dynamic = true;
actualType = Type::Variant;
}
if (m_dynamic) {
getScope()->getVariables()->
setAttribute(VariableTable::NeedGlobalPointer);
}
}
return actualType;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void ConstantExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf("%s", getNonNSOriginalName().c_str());
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __CONSTANT_EXPRESSION_H__
#define __CONSTANT_EXPRESSION_H__
#ifndef incl_HPHP_CONSTANT_EXPRESSION_H_
#define incl_HPHP_CONSTANT_EXPRESSION_H_
#include <compiler/expression/expression.h>
#include "hphp/compiler/expression/expression.h"
#define CONSTANT(value) makeConstant(ar, value)
@@ -30,6 +30,7 @@ class ConstantExpression : public Expression, IParseHandler {
public:
ConstantExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
const std::string &name,
bool hadBackslash,
const std::string &docComment = "");
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
@@ -50,9 +51,18 @@ public:
virtual bool canonCompare(ExpressionPtr e) const;
const std::string &getName() const { return m_name;}
const std::string &getOriginalName() const { return m_origName;}
const std::string getNonNSOriginalName() const {
auto nsPos = m_origName.rfind('\\');
if (nsPos == string::npos) {
return m_origName;
}
return m_origName.substr(nsPos + 1);
}
const std::string &getDocComment() const {
return m_docComment;
}
bool isNull() const;
bool isBoolean() const;
bool isDouble() const;
@@ -60,13 +70,16 @@ public:
void pushConst(const std::string &name);
void popConst();
void setComment(const std::string &comment) { m_comment = comment;}
const std::string getComment() { return m_comment;}
std::string getComment() { return m_comment;}
bool isValid() const { return m_valid; }
bool isDynamic() const { return m_dynamic; }
bool hadBackslash() const { return m_hadBackslash; }
private:
Symbol *resolveNS(AnalysisResultConstPtr ar);
std::string m_name;
std::string m_origName;
bool m_hadBackslash;
std::string m_docComment;
std::string m_comment; // for inlined constant name
bool m_valid;
@@ -78,4 +91,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __CONSTANT_EXPRESSION_H__
#endif // incl_HPHP_CONSTANT_EXPRESSION_H_
@@ -0,0 +1,140 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/dynamic_function_call.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/expression/simple_function_call.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/util/util.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/analysis/variable_table.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
DynamicFunctionCall::DynamicFunctionCall
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionPtr name, ExpressionListPtr params, ExpressionPtr cls)
: FunctionCall(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(DynamicFunctionCall),
name, "", false, params, cls) {
}
ExpressionPtr DynamicFunctionCall::clone() {
DynamicFunctionCallPtr exp(new DynamicFunctionCall(*this));
FunctionCall::deepCopy(exp);
return exp;
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
void DynamicFunctionCall::analyzeProgram(AnalysisResultPtr ar) {
FunctionCall::analyzeProgram(ar);
if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
if (!m_className.empty()) {
resolveClass();
}
if (!m_class) {
addUserClass(ar, m_className);
}
if (m_params) {
m_params->markParams(canInvokeFewArgs());
}
if (!m_class && m_className.empty()) {
FunctionScopePtr fs = getFunctionScope();
VariableTablePtr vt = fs->getVariables();
vt->setAttribute(VariableTable::ContainsDynamicFunctionCall);
}
}
}
ExpressionPtr DynamicFunctionCall::preOptimize(AnalysisResultConstPtr ar) {
if (ExpressionPtr rep = FunctionCall::preOptimize(ar)) return rep;
if (m_nameExp->isScalar()) {
Variant v;
if (m_nameExp->getScalarValue(v) &&
v.isString()) {
string name = v.toString().c_str();
ExpressionPtr cls = m_class;
if (!cls && !m_className.empty()) {
cls = makeScalarExpression(ar, m_className);
}
return ExpressionPtr(NewSimpleFunctionCall(
getScope(), getLocation(),
name, false, m_params, cls));
}
}
return ExpressionPtr();
}
TypePtr DynamicFunctionCall::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
reset();
ConstructPtr self = shared_from_this();
if (m_class) {
m_class->inferAndCheck(ar, Type::Any, false);
} else if (!m_className.empty()) {
ClassScopePtr cls = resolveClassWithChecks();
if (cls) {
m_classScope = cls;
}
}
m_nameExp->inferAndCheck(ar, Type::Some, false);
if (m_params) {
for (int i = 0; i < m_params->getCount(); i++) {
(*m_params)[i]->inferAndCheck(ar, Type::Variant, true);
}
}
return Type::Variant;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void DynamicFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_class || !m_className.empty()) {
StaticClassName::outputPHP(cg, ar);
cg_printf("::");
m_nameExp->outputPHP(cg, ar);
} else {
const char *prefix = Option::IdPrefix.c_str();
if (cg.getOutput() == CodeGenerator::TrimmedPHP &&
cg.usingStream(CodeGenerator::PrimaryStream) &&
!m_nameExp->is(Expression::KindOfScalarExpression)) {
cg_printf("${%sdynamic_load($%stmp = (", prefix, prefix);
m_nameExp->outputPHP(cg, ar);
cg_printf("), '%stmp'", prefix);
cg_printf(")}");
} else {
m_nameExp->outputPHP(cg, ar);
}
}
cg_printf("(");
if (m_params) m_params->outputPHP(cg, ar);
cg_printf(")");
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __DYNAMIC_FUNCTION_CALL_H__
#define __DYNAMIC_FUNCTION_CALL_H__
#ifndef incl_HPHP_DYNAMIC_FUNCTION_CALL_H_
#define incl_HPHP_DYNAMIC_FUNCTION_CALL_H_
#include <compiler/expression/function_call.h>
#include "hphp/compiler/expression/function_call.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -32,10 +32,9 @@ public:
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
ExpressionPtr preOptimize(AnalysisResultConstPtr ar);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // __DYNAMIC_FUNCTION_CALL_H__
#endif // incl_HPHP_DYNAMIC_FUNCTION_CALL_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,11 +14,11 @@
+----------------------------------------------------------------------+
*/
#include <compiler/expression/dynamic_variable.h>
#include <compiler/analysis/block_scope.h>
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/variable_table.h>
#include <compiler/analysis/file_scope.h>
#include "hphp/compiler/expression/dynamic_variable.h"
#include "hphp/compiler/analysis/block_scope.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/analysis/file_scope.h"
using namespace HPHP;
@@ -95,9 +95,3 @@ void DynamicVariable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_exp->outputPHP(cg, ar);
cg_printf("}");
}
void DynamicVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf("variables->get(");
m_exp->outputCPP(cg, ar);
cg_printf(")");
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __DYNAMIC_VARIABLE_H__
#define __DYNAMIC_VARIABLE_H__
#ifndef incl_HPHP_DYNAMIC_VARIABLE_H_
#define incl_HPHP_DYNAMIC_VARIABLE_H_
#include <compiler/expression/expression.h>
#include "hphp/compiler/expression/expression.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -40,4 +40,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __DYNAMIC_VARIABLE_H__
#endif // incl_HPHP_DYNAMIC_VARIABLE_H_
@@ -0,0 +1,138 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/encaps_list_expression.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/binary_op_expression.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/runtime/base/builtin_functions.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
EncapsListExpression::EncapsListExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, int type, ExpressionListPtr expList)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(EncapsListExpression)),
m_type(type), m_exps(expList) {
}
ExpressionPtr EncapsListExpression::clone() {
EncapsListExpressionPtr exp(new EncapsListExpression(*this));
Expression::deepCopy(exp);
exp->m_exps = Clone(m_exps);
return exp;
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
void EncapsListExpression::analyzeProgram(AnalysisResultPtr ar) {
if (m_exps) {
for (int i = 0; i < m_exps->getCount(); i++) {
(*m_exps)[i]->analyzeProgram(ar);
}
}
}
ConstructPtr EncapsListExpression::getNthKid(int n) const {
switch (n) {
case 0:
return m_exps;
default:
assert(false);
break;
}
return ConstructPtr();
}
int EncapsListExpression::getKidCount() const {
return 1;
}
void EncapsListExpression::setNthKid(int n, ConstructPtr cp) {
switch (n) {
case 0:
m_exps = boost::dynamic_pointer_cast<ExpressionList>(cp);
break;
default:
assert(false);
break;
}
}
void EncapsListExpression::stripConcat() {
m_exps->stripConcat();
}
ExpressionPtr EncapsListExpression::preOptimize(AnalysisResultConstPtr ar) {
if (m_type != '`' && m_type != '\'' && m_exps) {
int count = m_exps->getCount();
// turn into cascaded concat
if (count > 1) {
ExpressionPtr exp =
BinaryOpExpressionPtr(new BinaryOpExpression(
getScope(), getLocation(),
(*m_exps)[0], (*m_exps)[1], '.'));
for (int i = 2; i < count; i++) {
exp =
BinaryOpExpressionPtr(new BinaryOpExpression(
getScope(), getLocation(),
exp, (*m_exps)[i], '.'));
}
return exp;
}
}
return ExpressionPtr();
}
TypePtr EncapsListExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
if (m_exps) {
for (int i = 0; i < m_exps->getCount(); i++) {
(*m_exps)[i]->inferAndCheck(ar, Type::String, false);
}
}
return Type::String;
}
bool EncapsListExpression::canonCompare(ExpressionPtr e) const {
if (!Expression::canonCompare(e)) return false;
EncapsListExpressionPtr el = static_pointer_cast<EncapsListExpression>(e);
return m_type == el->m_type;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void EncapsListExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_type == '`') cg_printf("shell_exec(");
if (m_exps) {
for (int i = 0; i < m_exps->getCount(); i++) {
if (i > 0) cg_printf(" . ");
(*m_exps)[i]->outputPHP(cg, ar);
}
} else {
cg_printf("''");
}
if (m_type == '`') cg_printf(")");
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,11 +14,11 @@
+----------------------------------------------------------------------+
*/
#ifndef __ENCAPS_LIST_EXPRESSION_H__
#define __ENCAPS_LIST_EXPRESSION_H__
#ifndef incl_HPHP_ENCAPS_LIST_EXPRESSION_H_
#define incl_HPHP_ENCAPS_LIST_EXPRESSION_H_
#include <compiler/expression/expression.h>
#include <compiler/analysis/analysis_result.h>
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/analysis/analysis_result.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -46,4 +46,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __ENCAPS_LIST_EXPRESSION_H__
#endif // incl_HPHP_ENCAPS_LIST_EXPRESSION_H_
+860
Ver Arquivo
@@ -0,0 +1,860 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/parser/parser.h"
#include "hphp/util/parser/hphp.tab.hpp"
#include "hphp/util/util.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/expression/constant_expression.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/expression/assignment_expression.h"
#include "hphp/compiler/expression/array_pair_expression.h"
#include "hphp/compiler/expression/array_element_expression.h"
#include "hphp/compiler/expression/object_property_expression.h"
#include "hphp/compiler/expression/unary_op_expression.h"
#include "hphp/compiler/analysis/constant_table.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/expression/function_call.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/util/hash.h"
#include "hphp/runtime/base/array/array_iterator.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
#define DEC_EXPR_NAMES(x,t) #x
const char *Expression::Names[] = {
DECLARE_EXPRESSION_TYPES(DEC_EXPR_NAMES)
};
#define DEC_EXPR_CLASSES(x,t) Expression::t
Expression::ExprClass Expression::Classes[] = {
DECLARE_EXPRESSION_TYPES(DEC_EXPR_CLASSES)
};
Expression::Expression(EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS)
: Construct(scope, loc), m_context(RValue), m_kindOf(kindOf),
m_originalScopeSet(false), m_unused(false), m_canon_id(0), m_error(0),
m_canonPtr() {
}
ExpressionPtr Expression::replaceValue(ExpressionPtr rep) {
if (hasContext(Expression::RefValue) &&
isRefable(true) && !rep->isRefable(true)) {
/*
An assignment isRefable, but the rhs may not be. Need this to
prevent "bad pass by reference" errors.
*/
ExpressionListPtr el(new ExpressionList(getScope(), getLocation(),
ExpressionList::ListKindWrapped));
el->addElement(rep);
rep->clearContext(AssignmentRHS);
rep = el;
}
if (rep->is(KindOfSimpleVariable) && !is(KindOfSimpleVariable)) {
static_pointer_cast<SimpleVariable>(rep)->setAlwaysStash();
}
rep->copyContext(m_context & ~(DeadStore|AccessContext));
if (TypePtr t1 = getType()) {
if (TypePtr t2 = rep->getType()) {
if (!Type::SameType(t1, t2)) {
rep->setExpectedType(t1);
}
}
}
if (rep->getScope() != getScope()) {
rep->resetScope(getScope());
}
return rep;
}
void Expression::copyContext(int contexts) {
unsigned val = contexts;
while (val) {
unsigned next = val & (val - 1);
unsigned low = val ^ next; // lowest set bit
setContext((Context)low);
val = next;
}
}
void Expression::clearContext() {
unsigned val = m_context;
while (val) {
unsigned next = val & (val - 1);
unsigned low = val ^ next; // lowest set bit
clearContext((Context)low);
val = next;
}
}
void Expression::setArgNum(int n) {
m_argNum = n;
int kc = getKidCount();
for (int i=0; i < kc; i++) {
ExpressionPtr kid = getNthExpr(i);
if (kid) {
kid->setArgNum(n);
}
}
}
void Expression::deepCopy(ExpressionPtr exp) {
exp->m_actualType = m_actualType;
exp->m_expectedType = m_expectedType;
exp->m_implementedType = m_implementedType;
exp->m_assertedType = m_assertedType;
exp->m_canon_id = 0;
exp->m_unused = false;
exp->m_canonPtr.reset();
exp->m_replacement.reset();
exp->clearVisited();
};
bool Expression::hasSubExpr(ExpressionPtr sub) const {
if (this == sub.get()) return true;
for (int i = getKidCount(); i--; ) {
ExpressionPtr kid = getNthExpr(i);
if (kid && kid->hasSubExpr(sub)) return true;
}
return false;
}
Expression::ExprClass Expression::getExprClass() const {
ExprClass cls = Classes[m_kindOf];
if (cls == Update) {
ExpressionPtr k = getStoreVariable();
if (!k || !(k->hasContext(OprLValue))) cls = Expression::None;
}
return cls;
}
FileScopeRawPtr Expression::getUsedScalarScope(CodeGenerator& cg) {
return cg.getLiteralScope() ?
cg.getLiteralScope() : getFileScope();
}
bool Expression::getEffectiveScalar(Variant &v) {
if (is(KindOfExpressionList)) {
ExpressionRawPtr sub = static_cast<ExpressionList*>(this)->listValue();
if (!sub) return false;
return sub->getEffectiveScalar(v);
}
return getScalarValue(v);
}
void Expression::addElement(ExpressionPtr exp) {
assert(false);
}
void Expression::insertElement(ExpressionPtr exp, int index /* = 0 */) {
assert(false);
}
ExpressionPtr Expression::unneededHelper() {
ExpressionListPtr elist = ExpressionListPtr
(new ExpressionList(getScope(), getLocation(),
ExpressionList::ListKindWrapped));
bool change = false;
for (int i=0, n = getKidCount(); i < n; i++) {
ExpressionPtr kid = getNthExpr(i);
if (kid && kid->getContainedEffects()) {
ExpressionPtr rep = kid->unneeded();
if (rep != kid) change = true;
if (rep->is(Expression::KindOfExpressionList)) {
for (int j=0, m = rep->getKidCount(); j < m; j++) {
elist->addElement(rep->getNthExpr(j));
}
} else {
elist->addElement(rep);
}
}
}
if (change) {
getScope()->addUpdates(BlockScope::UseKindCaller);
}
int n = elist->getCount();
assert(n);
if (n == 1) {
return elist->getNthExpr(0);
} else {
return elist;
}
}
ExpressionPtr Expression::unneeded() {
if (getLocalEffects() || is(KindOfScalarExpression) || isNoRemove()) {
return static_pointer_cast<Expression>(shared_from_this());
}
if (!getContainedEffects()) {
getScope()->addUpdates(BlockScope::UseKindCaller);
return ScalarExpressionPtr
(new ScalarExpression(getScope(), getLocation(),
T_LNUMBER, string("0")));
}
return unneededHelper();
}
///////////////////////////////////////////////////////////////////////////////
bool Expression::IsIdentifier(const string &value) {
if (value.empty()) {
return false;
}
unsigned char ch = value[0];
if ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') &&
ch < '\x7f' && ch != '_') {
return false;
}
for (unsigned int i = 1; i < value.size(); i++) {
unsigned char ch = value[i];
if (((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') &&
(ch < '0' || ch > '9') && ch < '\x7f' && ch != '_')) {
if (ch == '\\' && i < value.size() - 1 && value[i+1] != '\\') {
continue;
}
return false;
}
}
return true;
}
TypePtr Expression::getType() {
if (m_expectedType) return m_expectedType;
if (m_actualType) return m_actualType;
return Type::Any;
}
TypePtr Expression::getGenType() {
if (m_expectedType) return m_expectedType;
if (m_implementedType) return m_implementedType;
if (m_actualType) return m_actualType;
return Type::Any;
}
TypePtr Expression::getCPPType() {
if (m_implementedType) return m_implementedType;
if (m_actualType) return m_actualType;
return Type::Variant;
}
TypePtr Expression::propagateTypes(AnalysisResultConstPtr ar, TypePtr inType) {
ExpressionPtr e = getCanonTypeInfPtr();
TypePtr ret = inType;
while (e) {
if (e->getAssertedType() && !getAssertedType()) {
setAssertedType(e->getAssertedType());
}
TypePtr inferred = Type::Inferred(ar, ret, e->m_actualType);
if (!inferred) {
break;
}
ret = inferred;
e = e->getCanonTypeInfPtr();
}
return ret;
}
void Expression::analyzeProgram(AnalysisResultPtr ar) {
}
BlockScopeRawPtr Expression::getOriginalScope() {
if (!m_originalScopeSet) {
m_originalScopeSet = true;
m_originalScope = getScope();
}
return m_originalScope;
}
void Expression::setOriginalScope(BlockScopeRawPtr scope) {
m_originalScope = scope;
m_originalScopeSet = true;
}
ClassScopeRawPtr Expression::getOriginalClass() {
BlockScopeRawPtr scope = getOriginalScope();
return scope ? scope->getContainingClass() : ClassScopeRawPtr();
}
FunctionScopeRawPtr Expression::getOriginalFunction() {
BlockScopeRawPtr scope = getOriginalScope();
return scope ? scope->getContainingFunction() : FunctionScopeRawPtr();
}
void Expression::resetTypes() {
m_actualType .reset();
m_expectedType .reset();
m_implementedType.reset();
}
TypePtr Expression::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
assert(type);
resetTypes();
TypePtr actualType = inferTypes(ar, type, coerce);
if (type->is(Type::KindOfSome) || type->is(Type::KindOfAny)) {
m_actualType = actualType;
m_expectedType.reset();
return actualType;
}
return checkTypesImpl(ar, type, actualType, coerce);
}
TypePtr Expression::checkTypesImpl(AnalysisResultConstPtr ar,
TypePtr expectedType,
TypePtr actualType, bool coerce) {
TypePtr ret;
actualType = propagateTypes(ar, actualType);
assert(actualType);
if (coerce) {
ret = Type::Coerce(ar, expectedType, actualType);
setTypes(ar, actualType, expectedType);
} else {
ret = Type::Intersection(ar, actualType, expectedType);
setTypes(ar, actualType, ret);
}
assert(ret);
return ret;
}
void Expression::setTypes(AnalysisResultConstPtr ar, TypePtr actualType,
TypePtr expectedType) {
assert(actualType);
assert(expectedType);
m_actualType = actualType;
if (!expectedType->is(Type::KindOfAny) &&
!expectedType->is(Type::KindOfSome)) {
// store the expected type if it is not Any nor Some,
// regardless of the actual type
m_expectedType = expectedType;
} else {
m_expectedType.reset();
}
// This is a special case where Type::KindOfObject means any object.
if (m_expectedType && m_expectedType->is(Type::KindOfObject) &&
!m_expectedType->isSpecificObject() &&
m_actualType->isSpecificObject()) {
m_expectedType.reset();
}
if (m_actualType->isSpecificObject()) {
boost::const_pointer_cast<AnalysisResult>(ar)->
addClassDependency(getFileScope(), m_actualType->getName());
}
}
void Expression::setDynamicByIdentifier(AnalysisResultPtr ar,
const std::string &value) {
string id = Util::toLower(value);
size_t c = id.find("::");
FunctionScopePtr fi;
ClassScopePtr ci;
if (c != 0 && c != string::npos && c+2 < id.size()) {
string cl = id.substr(0, c);
string fn = id.substr(c+2);
if (IsIdentifier(cl) && IsIdentifier(fn)) {
ci = ar->findClass(cl);
if (ci) {
fi = ci->findFunction(ar, fn, false);
if (fi) fi->setDynamic();
}
}
} else if (IsIdentifier(id)) {
fi = ar->findFunction(id);
if (fi) fi->setDynamic();
ClassScopePtr ci = ar->findClass(id, AnalysisResult::MethodName);
if (ci) {
fi = ci->findFunction(ar, id, false);
if (fi) fi->setDynamic();
}
}
}
bool Expression::CheckNeededRHS(ExpressionPtr value) {
bool needed = true;
always_assert(value);
while (value->is(KindOfAssignmentExpression)) {
value = dynamic_pointer_cast<AssignmentExpression>(value)->getValue();
}
if (value->isScalar()) {
needed = false;
} else {
TypePtr type = value->getType();
if (type && (type->is(Type::KindOfSome) || type->is(Type::KindOfAny))) {
type = value->getActualType();
}
if (type && type->isNoObjectInvolved()) needed = false;
}
return needed;
}
bool Expression::CheckNeeded(ExpressionPtr variable, ExpressionPtr value) {
// if the value may involve object, consider the variable as "needed"
// so that objects are not destructed prematurely.
bool needed = true;
if (value) needed = CheckNeededRHS(value);
if (variable->is(Expression::KindOfSimpleVariable)) {
SimpleVariablePtr var =
dynamic_pointer_cast<SimpleVariable>(variable);
const std::string &name = var->getName();
VariableTablePtr variables = var->getScope()->getVariables();
if (needed) {
variables->addNeeded(name);
} else {
needed = variables->isNeeded(name);
}
}
return needed;
}
bool Expression::CheckVarNR(ExpressionPtr value,
TypePtr expectedType /* = TypePtr */) {
if (!expectedType) expectedType = value->getExpectedType();
return (!value->hasContext(Expression::RefValue) &&
expectedType && expectedType->is(Type::KindOfVariant) &&
(value->getCPPType()->is(Type::KindOfArray) ||
value->getCPPType()->is(Type::KindOfString) ||
value->getCPPType()->is(Type::KindOfObject) ||
value->getCPPType()->isPrimitive() ||
value->isScalar()));
}
TypePtr Expression::inferAssignmentTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce, ExpressionPtr variable,
ExpressionPtr
value /* =ExpressionPtr() */) {
assert(type);
TypePtr ret = type;
if (value) {
ret = value->inferAndCheck(ar, Type::Some, false);
if (value->isLiteralNull()) {
ret = Type::Null;
}
assert(ret);
}
BlockScopePtr scope = getScope();
if (variable->is(Expression::KindOfConstantExpression)) {
// ...as in ClassConstant statement
ConstantExpressionPtr exp =
dynamic_pointer_cast<ConstantExpression>(variable);
BlockScope *defScope = nullptr;
std::vector<std::string> bases;
scope->getConstants()->check(getScope(), exp->getName(), ret,
true, ar, variable,
bases, defScope);
}
m_implementedType.reset();
TypePtr vt = variable->inferAndCheck(ar, ret, true);
if (!coerce && type->is(Type::KindOfAny)) {
ret = vt;
} else {
TypePtr it = variable->getCPPType();
if (!Type::SameType(it, ret)) {
m_implementedType = it;
}
}
if (value) {
TypePtr vat(value->getActualType());
TypePtr vet(value->getExpectedType());
TypePtr vit(value->getImplementedType());
if (vat && !vet && vit &&
Type::IsMappedToVariant(vit) &&
Type::HasFastCastMethod(vat)) {
value->setExpectedType(vat);
}
}
return ret;
}
ExpressionPtr Expression::MakeConstant(AnalysisResultConstPtr ar,
BlockScopePtr scope,
LocationPtr loc,
const std::string &value) {
ConstantExpressionPtr exp(new ConstantExpression(
scope, loc,
value, false));
if (value == "true" || value == "false") {
if (ar->getPhase() >= AnalysisResult::PostOptimize) {
exp->m_actualType = Type::Boolean;
}
} else if (value == "null") {
if (ar->getPhase() >= AnalysisResult::PostOptimize) {
exp->m_actualType = Type::Variant;
}
} else {
assert(false);
}
return exp;
}
void Expression::CheckPassByReference(AnalysisResultPtr ar,
ExpressionPtr param) {
if (param->hasContext(Expression::RefValue) &&
!param->isRefable(true)) {
param->setError(Expression::BadPassByRef);
Compiler::Error(Compiler::BadPassByReference, param);
}
}
unsigned Expression::getCanonHash() const {
int64_t val = hash_int64(getKindOf());
for (int i = getKidCount(); i--; ) {
ExpressionPtr k = getNthExpr(i);
if (k) {
val = hash_int64(val ^ (((int64_t)k->getKindOf()<<32)+k->getCanonID()));
}
}
return (unsigned)val ^ (unsigned)(val >> 32);
}
bool Expression::canonCompare(ExpressionPtr e) const {
if (e->getKindOf() != getKindOf()) {
return false;
}
int kk = getKidCount();
if (kk != e->getKidCount()) {
return false;
}
for (int i = kk; i--; ) {
ExpressionPtr k1 = getNthExpr(i);
ExpressionPtr k2 = e->getNthExpr(i);
if (k1 != k2) {
if (!k1 || !k2) {
return false;
}
if (k1->getCanonID() != k2->getCanonID()) {
return false;
}
}
}
return true;
}
bool Expression::equals(ExpressionPtr other) {
if (!other) return false;
// So that we can leverage canonCompare()
setCanonID(0);
other->setCanonID(0);
if (other->getKindOf() != getKindOf()) {
return false;
}
int nKids = getKidCount();
if (nKids != other->getKidCount()) {
return false;
}
for (int i = 0; i < nKids; i++) {
ExpressionPtr thisKid = getNthExpr(i);
ExpressionPtr otherKid = other->getNthExpr(i);
if (!thisKid || !otherKid) {
if (thisKid == otherKid) continue;
return false;
}
if (!thisKid->equals(otherKid)) {
return false;
}
}
return canonCompare(other);
}
ExpressionPtr Expression::getCanonTypeInfPtr() const {
if (!m_canonPtr) return ExpressionPtr();
if (!(m_context & (LValue|RefValue|UnsetContext|DeepReference))) {
return m_canonPtr;
}
if (!hasAnyContext(AccessContext|ObjectContext) ||
!m_canonPtr->getActualType()) {
return ExpressionPtr();
}
switch (m_canonPtr->getActualType()->getKindOf()) {
case Type::KindOfArray:
{
if (!hasContext(AccessContext)) break;
if (m_canonPtr->getAssertedType()) return m_canonPtr;
if (!is(Expression::KindOfSimpleVariable)) break;
SimpleVariableConstPtr sv(
static_pointer_cast<const SimpleVariable>(shared_from_this()));
if (sv->couldBeAliased()) return ExpressionPtr();
if (hasContext(LValue) &&
!(m_context & (RefValue | UnsetContext | DeepReference))) {
return m_canonPtr;
}
}
break;
case Type::KindOfObject:
{
if (!hasContext(ObjectContext)) break;
if (m_canonPtr->getAssertedType()) return m_canonPtr;
if (!is(Expression::KindOfSimpleVariable)) break;
SimpleVariableConstPtr sv(
static_pointer_cast<const SimpleVariable>(shared_from_this()));
if (sv->couldBeAliased()) return ExpressionPtr();
if (hasContext(LValue) &&
!(m_context & (RefValue | UnsetContext | DeepReference))) {
return m_canonPtr;
}
}
default:
break;
}
return ExpressionPtr();
}
ExpressionPtr Expression::fetchReplacement() {
ExpressionPtr t = m_replacement;
m_replacement.reset();
return t;
}
void Expression::computeLocalExprAltered() {
// if no kids, do nothing
if (getKidCount() == 0) return;
bool res = false;
for (int i = 0; i < getKidCount(); i++) {
ExpressionPtr k = getNthExpr(i);
if (k) {
k->computeLocalExprAltered();
res |= k->isLocalExprAltered();
}
}
if (res) {
setLocalExprAltered();
}
}
bool Expression::isArray() const {
if (is(KindOfUnaryOpExpression)) {
return static_cast<const UnaryOpExpression*>(this)->getOp() == T_ARRAY;
}
return false;
}
bool Expression::isUnquotedScalar() const {
if (!is(KindOfScalarExpression)) return false;
return !((ScalarExpression*)this)->isQuoted();
}
ExpressionPtr Expression::MakeScalarExpression(AnalysisResultConstPtr ar,
BlockScopePtr scope,
LocationPtr loc,
CVarRef value) {
if (value.isArray()) {
ExpressionListPtr el(new ExpressionList(scope, loc,
ExpressionList::ListKindParam));
for (ArrayIter iter(value.toArray()); iter; ++iter) {
ExpressionPtr k(MakeScalarExpression(ar, scope, loc, iter.first()));
ExpressionPtr v(MakeScalarExpression(ar, scope, loc, iter.second()));
if (!k || !v) return ExpressionPtr();
ArrayPairExpressionPtr ap(
new ArrayPairExpression(scope, loc, k, v, false));
el->addElement(ap);
}
if (!el->getCount()) el.reset();
return ExpressionPtr(
new UnaryOpExpression(scope, loc, el, T_ARRAY, true));
} else if (value.isNull()) {
return MakeConstant(ar, scope, loc, "null");
} else if (value.isBoolean()) {
return MakeConstant(ar, scope, loc, value.toBoolean() ? "true" : "false");
} else {
return ScalarExpressionPtr
(new ScalarExpression(scope, loc, value));
}
}
///////////////////////////////////////////////////////////////////////////////
void Expression::collectCPPTemps(ExpressionPtrVec &collection) {
if (isChainRoot()) {
collection.push_back(static_pointer_cast<Expression>(shared_from_this()));
} else {
for (int i = 0; i < getKidCount(); i++) {
ExpressionPtr kid = getNthExpr(i);
if (kid) kid->collectCPPTemps(collection);
}
}
}
void Expression::disableCSE() {
ExpressionPtrVec v;
collectCPPTemps(v);
ExpressionPtrVec::iterator it(v.begin());
for (; it != v.end(); ++it) {
ExpressionPtr p(*it);
p->clearChainRoot();
}
}
bool Expression::hasChainRoots() {
ExpressionPtrVec v;
collectCPPTemps(v);
return !v.empty();
}
bool Expression::GetCseTempInfo(
AnalysisResultPtr ar,
ExpressionPtr p,
TypePtr &t) {
assert(p);
switch (p->getKindOf()) {
case Expression::KindOfArrayElementExpression:
{
ArrayElementExpressionPtr ap(
static_pointer_cast<ArrayElementExpression>(p));
ExpressionPtr var(ap->getVariable());
TypePtr srcType, dstType;
bool needsCast =
var->getTypeCastPtrs(ar, srcType, dstType);
TypePtr testType(needsCast ? dstType : srcType);
if (testType) {
t = testType;
return !testType->is(Type::KindOfArray);
}
return true;
}
break;
default:
break;
}
return true;
}
ExpressionPtr Expression::getNextCanonCsePtr() const {
bool dAccessCtx =
hasContext(AccessContext);
bool dLval =
hasContext(LValue);
bool dExistCtx =
hasContext(ExistContext);
bool dUnsetCtx =
hasContext(UnsetContext);
bool dGlobals = false;
if (is(KindOfArrayElementExpression)) {
ArrayElementExpressionConstPtr a(
static_pointer_cast<const ArrayElementExpression>(
shared_from_this()));
dGlobals = a->isSuperGlobal() || a->isDynamicGlobal();
}
// see rules below - no hope to find CSE candidate
if (dExistCtx || dUnsetCtx || dGlobals || (!dAccessCtx && dLval)) {
return ExpressionPtr();
}
KindOf dKindOf = getKindOf();
ExpressionPtr match;
ExpressionPtr p(getCanonLVal());
for (; p; p = p->getCanonLVal()) {
// check if p is a suitable candidate for CSE of
// downstream. the rules are:
// A) rvals can always be CSE-ed regardless of access context,
// except for unset context, which it never can be CSE-ed for
// B) lvals can only be CSE-ed if in AccessContext
// C) rvals and lvals cannot be CSE-ed for each other
// D) for now, ExistContext is not optimized
// E) no CSE for $GLOBALS[...]
// F) node types need to match
bool pLval = p->hasContext(LValue);
KindOf pKindOf = p->getKindOf();
if (dKindOf != pKindOf) continue;
if (dLval) {
assert(dAccessCtx);
bool pAccessCtx = p->hasContext(AccessContext);
if (pLval && pAccessCtx) {
// match found
match = p;
break;
}
} else {
bool pExistCtx = p->hasContext(ExistContext);
bool pUnsetCtx = p->hasContext(UnsetContext);
if (!pLval && !pExistCtx && !pUnsetCtx) {
// match found
match = p;
break;
}
}
}
return match;
}
ExpressionPtr Expression::getCanonCsePtr() const {
ExpressionPtr next(getNextCanonCsePtr());
if (next) {
if (next->isChainRoot()) return next;
return next->getCanonCsePtr();
}
return ExpressionPtr();
}
bool Expression::getTypeCastPtrs(
AnalysisResultPtr ar, TypePtr &srcType, TypePtr &dstType) {
srcType = m_actualType;
dstType = m_expectedType;
if (m_implementedType && srcType &&
!Type::SameType(m_implementedType, srcType)) {
srcType = m_implementedType;
}
if (!srcType && dstType && Type::IsCastNeeded(ar, Type::Variant, dstType)) {
srcType = Type::Variant;
return true;
}
return dstType && srcType && ((m_context & LValue) == 0) &&
Type::IsCastNeeded(ar, srcType, dstType);
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,12 +14,12 @@
+----------------------------------------------------------------------+
*/
#ifndef __EXPRESSION_H__
#define __EXPRESSION_H__
#ifndef incl_HPHP_EXPRESSION_H_
#define incl_HPHP_EXPRESSION_H_
#include <compiler/construct.h>
#include <compiler/analysis/type.h>
#include <compiler/analysis/analysis_result.h>
#include "hphp/compiler/construct.h"
#include "hphp/compiler/analysis/type.h"
#include "hphp/compiler/analysis/analysis_result.h"
#define EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS \
BlockScopePtr scope, LocationPtr loc, Expression::KindOf kindOf
@@ -36,8 +36,7 @@
virtual ExpressionPtr clone(); \
virtual TypePtr inferTypes(AnalysisResultPtr ar, TypePtr type, \
bool coerce); \
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar); \
virtual void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar)
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
#define DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS \
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS; \
virtual ConstructPtr getNthKid(int n) const; \
@@ -76,6 +75,7 @@ class Variant;
x(ConstantExpression, Const), \
x(EncapsListExpression, None), \
x(ClosureExpression, None), \
x(YieldExpression, None), \
x(UserAttribute, None)
class Expression : public Construct {
@@ -172,6 +172,7 @@ public:
}
bool hasSubExpr(ExpressionPtr sub) const;
virtual void setComment(const std::string &) {}
virtual std::string getComment() { return ""; }
/**
* Set this expression's error flags.
*/
@@ -181,42 +182,20 @@ public:
bool hasError(Error error) const { return m_error & error; }
ExprClass getExprClass() const;
virtual ExpressionPtr getStoreVariable() const { return ExpressionPtr(); }
void setArgNum(int n);
/**
* Implementing Construct.
*/
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
void outputCPPCast(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void outputCPPDecl(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
int op);
virtual void outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
virtual bool outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar);
bool outputCPPBegin(CodeGenerator &cg, AnalysisResultPtr ar);
bool outputCPPEnd(CodeGenerator &cg, AnalysisResultPtr ar);
void collectCPPTemps(ExpressionPtrVec &collection);
void disableCSE();
bool hasChainRoots();
bool preOutputCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar,
bool emitTemps);
virtual bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool preOutputOffsetLHS(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool hasCPPTemp() const { return !m_cppTemp.empty(); }
const std::string &cppTemp() const { return m_cppTemp; }
std::string genCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar);
void setCPPTemp(const std::string &s) { m_cppTemp = s; }
BlockScopeRawPtr getOriginalScope();
void setOriginalScope(BlockScopeRawPtr scope);
ClassScopeRawPtr getOriginalClass();
FunctionScopeRawPtr getOriginalFunction();
std::string originalClassName(CodeGenerator &cg, bool withComma);
/**
* For generic walks
@@ -243,10 +222,6 @@ public:
}
ExpressionPtr getNextCanonCsePtr() const;
ExpressionPtr getCanonCsePtr() const;
bool needsCSE() const {
ExpressionPtr p(getCanonCsePtr());
return p && p->hasCPPCseTemp();
}
ExpressionPtr getCanonTypeInfPtr() const;
/**
@@ -390,7 +365,6 @@ public:
static bool GetCseTempInfo(
AnalysisResultPtr ar, ExpressionPtr p, TypePtr &t);
bool outputCPPArithArg(CodeGenerator &cg, AnalysisResultPtr ar, bool arrayOk);
bool isUnused() const { return m_unused; }
void setUnused(bool u) { m_unused = u; }
ExpressionPtr fetchReplacement();
@@ -400,8 +374,6 @@ public:
* Correctly compute the local expression altered bit
*/
void computeLocalExprAltered();
bool outputCPPGuardedObjectPtr(CodeGenerator &cg);
protected:
static bool IsIdentifier(const std::string &value);
@@ -420,10 +392,6 @@ protected:
TypePtr m_expectedType; // null if the same as m_actualType
TypePtr m_implementedType; // null if the same as m_actualType
TypePtr m_assertedType;
std::string m_cppTemp;
std::string m_cppCseTemp;
bool hasCPPCseTemp() const { return !m_cppCseTemp.empty(); }
TypePtr inferAssignmentTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce, ExpressionPtr variable,
@@ -432,13 +400,9 @@ protected:
TypePtr expectedType);
void setDynamicByIdentifier(AnalysisResultPtr ar,
const std::string &value);
bool outputLineMap(CodeGenerator &cg, AnalysisResultPtr ar,
bool force = false);
void resetTypes();
private:
static ExprClass Classes[];
void outputCPPInternal(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* Returns true if a type cast is needed, and sets src/dst type
@@ -446,10 +410,6 @@ protected:
bool getTypeCastPtrs(
AnalysisResultPtr ar, TypePtr &srcType, TypePtr &dstType);
bool couldCppTypeBeReferenced();
bool needsFastCastTemp(AnalysisResultPtr ar);
bool canUseFastCast(AnalysisResultPtr ar);
BlockScopeRawPtr m_originalScope;
ExpressionPtr m_canonPtr;
ExpressionPtr m_replacement;
@@ -458,4 +418,4 @@ protected:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __EXPRESSION_H__
#endif // incl_HPHP_EXPRESSION_H_
+516
Ver Arquivo
@@ -0,0 +1,516 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/expression/unary_op_expression.h"
#include "hphp/compiler/expression/binary_op_expression.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/expression/array_pair_expression.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/runtime/base/array/array_init.h"
#include "hphp/compiler/parser/parser.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
ExpressionList::ExpressionList(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ListKind kind)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ExpressionList)),
m_outputCount(-1),
m_arrayElements(false), m_collectionType(0), m_kind(kind) {
}
ExpressionPtr ExpressionList::clone() {
ExpressionListPtr exp(new ExpressionList(*this));
Expression::deepCopy(exp);
exp->m_exps.clear();
for (unsigned int i = 0; i < m_exps.size(); i++) {
exp->m_exps.push_back(Clone(m_exps[i]));
}
return exp;
}
void ExpressionList::toLower() {
for (unsigned int i = 0; i < m_exps.size(); i++) {
ScalarExpressionPtr s = dynamic_pointer_cast<ScalarExpression>(m_exps[i]);
s->toLower();
}
}
void ExpressionList::setContext(Context context) {
Expression::setContext(context);
if (m_kind == ListKindParam && context & UnsetContext) {
for (unsigned int i = m_exps.size(); i--; ) {
if (m_exps[i]) {
m_exps[i]->setContext(UnsetContext);
m_exps[i]->setContext(LValue);
m_exps[i]->setContext(NoLValueWrapper);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
void ExpressionList::addElement(ExpressionPtr exp) {
ArrayPairExpressionPtr ap = dynamic_pointer_cast<ArrayPairExpression>(exp);
if (ap) {
m_arrayElements = true;
} else {
assert(!m_arrayElements);
}
m_exps.push_back(exp);
}
void ExpressionList::insertElement(ExpressionPtr exp, int index /* = 0 */) {
m_exps.insert(m_exps.begin() + index, exp);
}
void ExpressionList::removeElement(int index) {
m_exps.erase(m_exps.begin() + index, m_exps.begin() + index + 1);
}
void ExpressionList::clearElements() {
m_exps.clear();
}
bool ExpressionList::isRefable(bool checkError /* = false */) const {
if (m_kind == ListKindWrapped || m_kind == ListKindLeft) {
// Its legal to ref a list...
if (checkError) return true;
// ...but we shouldnt apply ref() to it unless the corresponding
// arg is refable
int ix = m_kind == ListKindLeft ? 0 : m_exps.size() - 1;
return m_exps[ix]->isRefable(false);
}
return false;
}
bool ExpressionList::isScalar() const {
if (m_arrayElements) {
return isScalarArrayPairs();
}
if (m_kind == ListKindParam) {
for (unsigned int i = m_exps.size(); i--; ) {
if (m_exps[i] && !m_exps[i]->isScalar()) return false;
}
return true;
} else if (!hasEffect()) {
ExpressionPtr v(listValue());
return v ? v->isScalar() : false;
}
return false;
}
bool ExpressionList::isNoObjectInvolved() const {
for (unsigned int i = 0; i < m_exps.size(); i++) {
TypePtr t = m_exps[i]->getActualType();
if (t == nullptr || !t->isNoObjectInvolved())
return false;
}
return true;
}
bool ExpressionList::containsDynamicConstant(AnalysisResultPtr ar) const {
for (unsigned int i = 0; i < m_exps.size(); i++) {
if (m_exps[i]->containsDynamicConstant(ar)) return true;
}
return false;
}
bool ExpressionList::isScalarArrayPairs() const {
if (!m_arrayElements || m_collectionType) return false;
for (unsigned int i = 0; i < m_exps.size(); i++) {
ArrayPairExpressionPtr exp =
dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
if (!exp || !exp->isScalarArrayPair()) {
return false;
}
}
return true;
}
void ExpressionList::getStrings(std::vector<std::string> &strings) {
for (unsigned int i = 0; i < m_exps.size(); i++) {
ScalarExpressionPtr s = dynamic_pointer_cast<ScalarExpression>(m_exps[i]);
strings.push_back(s->getString());
}
}
void ExpressionList::getOriginalStrings(std::vector<std::string> &strings) {
for (unsigned int i = 0; i < m_exps.size(); i++) {
ScalarExpressionPtr s = dynamic_pointer_cast<ScalarExpression>(m_exps[i]);
strings.push_back(s->getOriginalString());
}
}
bool
ExpressionList::flattenLiteralStrings(vector<ExpressionPtr> &literals) const {
for (unsigned i = 0; i < m_exps.size(); i++) {
ExpressionPtr e = m_exps[i];
if (e->is(Expression::KindOfArrayPairExpression)) {
ArrayPairExpressionPtr ap = dynamic_pointer_cast<ArrayPairExpression>(e);
if (ap->getName()) return false;
e = ap->getValue();
}
if (e->is(Expression::KindOfUnaryOpExpression)) {
UnaryOpExpressionPtr unary = dynamic_pointer_cast<UnaryOpExpression>(e);
if (unary->getOp() == T_ARRAY) {
ExpressionListPtr el =
dynamic_pointer_cast<ExpressionList>(unary->getExpression());
if (!el->flattenLiteralStrings(literals)) {
return false;
}
}
}
else if (e->isLiteralString()) {
literals.push_back(e);
} else {
return false;
}
}
return true;
}
bool ExpressionList::getScalarValue(Variant &value) {
if (m_arrayElements) {
if (isScalarArrayPairs()) {
ArrayInit init(m_exps.size());
for (unsigned int i = 0; i < m_exps.size(); i++) {
ArrayPairExpressionPtr exp =
dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
ExpressionPtr name = exp->getName();
ExpressionPtr val = exp->getValue();
if (!name) {
Variant v;
bool ret = val->getScalarValue(v);
if (!ret) assert(false);
init.set(v);
} else {
Variant n;
Variant v;
bool ret1 = name->getScalarValue(n);
bool ret2 = val->getScalarValue(v);
if (!(ret1 && ret2)) return false;
init.set(n, v);
}
}
value = Array(init.create());
return true;
}
return false;
}
if (m_kind != ListKindParam && !hasEffect()) {
ExpressionPtr v(listValue());
return v ? v->getScalarValue(value) : false;
}
return false;
}
void ExpressionList::stripConcat() {
ExpressionList &el = *this;
for (int i = 0; i < el.getCount(); ) {
ExpressionPtr &e = el[i];
if (e->is(Expression::KindOfUnaryOpExpression)) {
UnaryOpExpressionPtr u(boost::static_pointer_cast<UnaryOpExpression>(e));
if (u->getOp() == '(') {
e = u->getExpression();
}
}
if (e->is(Expression::KindOfBinaryOpExpression)) {
BinaryOpExpressionPtr b
(boost::static_pointer_cast<BinaryOpExpression>(e));
if (b->getOp() == '.') {
e = b->getExp1();
el.insertElement(b->getExp2(), i + 1);
continue;
}
}
i++;
}
}
void ExpressionList::setOutputCount(int count) {
assert(count >= 0 && count <= (int)m_exps.size());
m_outputCount = count;
}
int ExpressionList::getOutputCount() const {
return m_outputCount < 0 ? m_exps.size() : m_outputCount;
}
void ExpressionList::resetOutputCount() {
m_outputCount = -1;
}
void ExpressionList::markParam(int p, bool noRefWrapper) {
ExpressionPtr param = (*this)[p];
if (param->hasContext(Expression::InvokeArgument)) {
if (noRefWrapper) {
param->setContext(Expression::NoRefWrapper);
} else {
param->clearContext(Expression::NoRefWrapper);
}
} else if (!param->hasContext(Expression::RefParameter)) {
param->setContext(Expression::InvokeArgument);
param->setContext(Expression::RefValue);
if (noRefWrapper) {
param->setContext(Expression::NoRefWrapper);
}
}
param->setArgNum(p);
}
void ExpressionList::markParams(bool noRefWrapper) {
for (int i = 0; i < getCount(); i++) {
markParam(i, noRefWrapper);
}
}
void ExpressionList::setCollectionType(int cType) {
m_arrayElements = true;
m_collectionType = cType;
}
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
ExpressionPtr &ExpressionList::operator[](int index) {
assert(index >= 0 && index < getCount());
return m_exps[index];
}
void ExpressionList::analyzeProgram(AnalysisResultPtr ar) {
for (unsigned int i = 0; i < m_exps.size(); i++) {
if (m_exps[i]) m_exps[i]->analyzeProgram(ar);
}
}
bool ExpressionList::kidUnused(int i) const {
if (m_kind == ListKindParam) {
return false;
}
if (isUnused()) return true;
if (m_kind == ListKindLeft) {
return i != 0;
}
return (i + 1u) != m_exps.size();
}
ConstructPtr ExpressionList::getNthKid(int n) const {
if (n < (int)m_exps.size()) {
return m_exps[n];
}
return ConstructPtr();
}
int ExpressionList::getKidCount() const {
return m_exps.size();
}
void ExpressionList::setNthKid(int n, ConstructPtr cp) {
int m = m_exps.size();
if (n >= m) {
assert(false);
} else {
m_exps[n] = boost::dynamic_pointer_cast<Expression>(cp);
}
}
ExpressionPtr ExpressionList::listValue() const {
if (size_t i = m_exps.size()) {
if (m_kind == ListKindComma || m_kind == ListKindWrapped) {
return m_exps[i-1];
} else if (m_kind == ListKindLeft) {
return m_exps[0];
}
}
return ExpressionPtr();
}
bool ExpressionList::isLiteralString() const {
ExpressionPtr v(listValue());
return v ? v->isLiteralString() : false;
}
string ExpressionList::getLiteralString() const {
ExpressionPtr v(listValue());
return v ? v->getLiteralString() : string("");
}
void ExpressionList::optimize(AnalysisResultConstPtr ar) {
bool changed = false;
size_t i = m_exps.size();
if (m_kind != ListKindParam) {
size_t skip = m_kind == ListKindLeft ? 0 : i - 1;
while (i--) {
if (i != skip) {
ExpressionPtr &e = m_exps[i];
if (!e || (e->getContainedEffects() == NoEffect && !e->isNoRemove())) {
removeElement(i);
changed = true;
} else if (e->is(KindOfExpressionList)) {
ExpressionListPtr el(static_pointer_cast<ExpressionList>(e));
removeElement(i);
for (size_t j = el->getCount(); j--; ) {
insertElement((*el)[j], i);
}
changed = true;
} else if (e->getLocalEffects() == NoEffect) {
e = e->unneeded();
// changed already handled by unneeded
}
}
}
if (m_exps.size() == 1) {
// don't convert an exp-list with type assertions to
// a ListKindWrapped
if (!isNoRemove()) {
m_kind = ListKindWrapped;
}
} else if (m_kind == ListKindLeft && m_exps[0]->isScalar()) {
ExpressionPtr e = m_exps[0];
removeElement(0);
addElement(e);
m_kind = ListKindWrapped;
}
} else {
bool isUnset = hasContext(UnsetContext) &&
ar->getPhase() >= AnalysisResult::PostOptimize;
int isGlobal = -1;
while (i--) {
ExpressionPtr &e = m_exps[i];
if (isUnset) {
if (e->is(Expression::KindOfSimpleVariable)) {
SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(e);
if (var->checkUnused()) {
const std::string &name = var->getName();
VariableTablePtr variables = getScope()->getVariables();
if (!variables->isNeeded(name)) {
removeElement(i);
changed = true;
}
}
}
} else {
bool global = e && (e->getContext() & Declaration) == Declaration;
if (isGlobal < 0) {
isGlobal = global;
} else {
always_assert(isGlobal == global);
}
if (isGlobal && e->isScalar()) {
removeElement(i);
changed = true;
}
}
}
}
if (changed) {
getScope()->addUpdates(BlockScope::UseKindCaller);
}
}
ExpressionPtr ExpressionList::preOptimize(AnalysisResultConstPtr ar) {
optimize(ar);
return ExpressionPtr();
}
ExpressionPtr ExpressionList::postOptimize(AnalysisResultConstPtr ar) {
optimize(ar);
return ExpressionPtr();
}
TypePtr ExpressionList::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
size_t size = m_exps.size();
bool commaList = size && (m_kind != ListKindParam);
size_t ix = m_kind == ListKindLeft ? 0 : size - 1;
TypePtr tmp = commaList ? Type::Some : type;
TypePtr ret = type;
for (size_t i = 0; i < size; i++) {
TypePtr t = i != ix ? tmp : type;
bool c = coerce && (!commaList || i == ix);
if (ExpressionPtr e = m_exps[i]) {
e->inferAndCheck(ar, t, c);
if (commaList && i == ix) {
e->setExpectedType(TypePtr());
ret = e->getActualType();
if (e->getImplementedType()) {
m_implementedType = e->getImplementedType();
}
if (!ret) ret = Type::Variant;
}
}
}
return ret;
}
bool ExpressionList::canonCompare(ExpressionPtr e) const {
if (!Expression::canonCompare(e)) return false;
ExpressionListPtr l =
static_pointer_cast<ExpressionList>(e);
return m_arrayElements == l->m_arrayElements &&
m_collectionType == l->m_collectionType &&
m_kind == l->m_kind;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void ExpressionList::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
for (unsigned int i = 0; i < m_exps.size(); i++) {
if (i > 0) cg_printf(", ");
ExpressionPtr exp = m_exps[i];
if (exp) {
if (exp->hasContext(RefParameter)) {
cg_printf("&");
}
exp->outputPHP(cg, ar);
}
}
}
unsigned int ExpressionList::checkLitstrKeys() const {
assert(m_arrayElements && !m_collectionType);
std::set<string> keys;
for (unsigned int i = 0; i < m_exps.size(); i++) {
ArrayPairExpressionPtr ap =
dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
ExpressionPtr name = ap->getName();
if (!name) return 0;
Variant value;
bool ret = name->getScalarValue(value);
if (!ret) return 0;
if (!value.isString()) return 0;
String str = value.toString();
if (str->isInteger()) return 0;
string s(str.data(), str.size());
keys.insert(s);
}
return keys.size();
}
+108
Ver Arquivo
@@ -0,0 +1,108 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_EXPRESSION_LIST_H_
#define incl_HPHP_EXPRESSION_LIST_H_
#include "hphp/compiler/expression/expression.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
DECLARE_BOOST_TYPES(ExpressionList);
class ExpressionList : public Expression {
public:
enum ListKind {
ListKindParam,
ListKindComma,
ListKindWrapped,
ListKindLeft
};
explicit ExpressionList(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ListKind kind = ListKindParam);
// change case to lower so to make it case insensitive
void toLower();
DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS;
ExpressionPtr preOptimize(AnalysisResultConstPtr ar);
ExpressionPtr postOptimize(AnalysisResultConstPtr ar);
virtual void setContext(Context context);
void setListKind(ListKind kind) { m_kind = kind; }
ListKind getListKind() const { return m_kind; }
virtual void addElement(ExpressionPtr exp);
virtual void insertElement(ExpressionPtr exp, int index = 0);
virtual bool isScalar() const;
virtual int getLocalEffects() const { return NoEffect; }
bool isNoObjectInvolved() const;
virtual bool containsDynamicConstant(AnalysisResultPtr ar) const;
void removeElement(int index);
void clearElements();
virtual bool getScalarValue(Variant &value);
virtual bool isRefable(bool checkError = false) const;
virtual bool kidUnused(int i) const;
ExpressionPtr listValue() const;
virtual bool isLiteralString() const;
virtual std::string getLiteralString() const;
bool isScalarArrayPairs() const;
int getCount() const { return m_exps.size();}
ExpressionPtr &operator[](int index);
void getStrings(std::vector<std::string> &strings);
void getOriginalStrings(std::vector<std::string> &strings);
void stripConcat();
void markParam(int p, bool noRefWrapper);
void markParams(bool noRefWrapper);
void setCollectionType(int cType);
/**
* When a function call has too many arguments, we only want to output
* max number of arguments, by limiting output count of subexpressions.
*/
void setOutputCount(int count);
int getOutputCount() const;
void resetOutputCount();
virtual bool canonCompare(ExpressionPtr e) const;
/**
* Checks whether the expression list contains only literal strings and
* (recursive) arrays of literal strings. Also returns the list of strings
* if so.
*/
bool flattenLiteralStrings(std::vector<ExpressionPtr> &literals) const;
private:
void optimize(AnalysisResultConstPtr ar);
unsigned int checkLitstrKeys() const;
ExpressionPtrVec m_exps;
int m_outputCount;
bool m_arrayElements;
int m_collectionType;
ListKind m_kind;
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_EXPRESSION_LIST_H_
+585
Ver Arquivo
@@ -0,0 +1,585 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/function_call.h"
#include "hphp/util/util.h"
#include "hphp/util/logger.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/statement/statement.h"
#include "hphp/compiler/statement/method_statement.h"
#include "hphp/compiler/statement/exp_statement.h"
#include "hphp/compiler/statement/return_statement.h"
#include "hphp/compiler/statement/statement_list.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/array_pair_expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/expression/simple_function_call.h"
#include "hphp/compiler/expression/parameter_expression.h"
#include "hphp/compiler/expression/assignment_expression.h"
#include "hphp/compiler/expression/unary_op_expression.h"
#include "hphp/util/parser/hphp.tab.hpp"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
FunctionCall::FunctionCall
(EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS,
ExpressionPtr nameExp, const std::string &name, bool hadBackslash,
ExpressionListPtr params, ExpressionPtr classExp)
: Expression(EXPRESSION_CONSTRUCTOR_BASE_PARAMETER_VALUES),
StaticClassName(classExp), m_nameExp(nameExp),
m_ciTemp(-1), m_params(params), m_valid(false),
m_extraArg(0), m_variableArgument(false), m_voidReturn(false),
m_voidWrapper(false), m_redeclared(false),
m_noStatic(false), m_noInline(false), m_invokeFewArgsDecision(true),
m_arrayParams(false), m_hadBackslash(hadBackslash),
m_argArrayId(-1), m_argArrayHash(-1), m_argArrayIndex(-1) {
if (m_nameExp &&
m_nameExp->getKindOf() == Expression::KindOfScalarExpression) {
assert(m_name.empty());
ScalarExpressionPtr c = dynamic_pointer_cast<ScalarExpression>(m_nameExp);
m_origName = c->getOriginalLiteralString();
c->toLower(true /* func call*/);
m_name = c->getLiteralString();
} else {
m_origName = name;
m_name = Util::toLower(name);
}
m_clsNameTemp = -1;
}
void FunctionCall::reset() {
m_valid = false;
m_extraArg = 0;
m_variableArgument = false;
m_voidWrapper = false;
}
bool FunctionCall::isTemporary() const {
return m_funcScope && !m_funcScope->isRefReturn();
}
void FunctionCall::deepCopy(FunctionCallPtr exp) {
Expression::deepCopy(exp);
exp->m_class = Clone(m_class);
exp->m_params = Clone(m_params);
exp->m_nameExp = Clone(m_nameExp);
}
bool FunctionCall::canInvokeFewArgs() {
// We can always change out minds about saying yes, but once we say
// no, it sticks.
if (m_invokeFewArgsDecision &&
((m_params && m_params->getCount() > Option::InvokeFewArgsCount) ||
m_arrayParams)) {
m_invokeFewArgsDecision = false;
}
return m_invokeFewArgsDecision;
}
ConstructPtr FunctionCall::getNthKid(int n) const {
switch (n) {
case 0:
return m_class;
case 1:
return m_nameExp;
case 2:
return m_params;
default:
assert(false);
break;
}
return ConstructPtr();
}
int FunctionCall::getKidCount() const {
return 3;
}
void FunctionCall::setNthKid(int n, ConstructPtr cp) {
switch (n) {
case 0:
m_class = boost::dynamic_pointer_cast<Expression>(cp);
break;
case 1:
m_nameExp = boost::dynamic_pointer_cast<Expression>(cp);
break;
case 2:
m_params = boost::dynamic_pointer_cast<ExpressionList>(cp);
break;
default:
assert(false);
break;
}
}
void FunctionCall::markRefParams(FunctionScopePtr func,
const std::string &name,
bool canInvokeFewArgs) {
ExpressionList &params = *m_params;
if (func) {
int mpc = func->getMaxParamCount();
for (int i = params.getCount(); i--; ) {
ExpressionPtr p = params[i];
if (i < mpc ? func->isRefParam(i) :
func->isReferenceVariableArgument()) {
p->setContext(Expression::RefValue);
} else if (i < mpc && p->hasContext(RefParameter)) {
Symbol *sym = func->getVariables()->addSymbol(func->getParamName(i));
sym->setLvalParam();
sym->setCallTimeRef();
}
}
} else if (Option::WholeProgram && !m_name.empty()) {
FunctionScope::FunctionInfoPtr info =
FunctionScope::GetFunctionInfo(m_name);
if (info) {
for (int i = params.getCount(); i--; ) {
if (info->isRefParam(i)) {
m_params->markParam(i, canInvokeFewArgs);
}
}
}
// If we cannot find information of the so-named function, it might not
// exist, or it might go through __call(), either of which cannot have
// reference parameters.
} else {
for (int i = params.getCount(); i--; ) {
m_params->markParam(i, canInvokeFewArgs);
}
}
}
void FunctionCall::analyzeProgram(AnalysisResultPtr ar) {
if (m_class) m_class->analyzeProgram(ar);
if (m_nameExp) m_nameExp->analyzeProgram(ar);
if (m_params) m_params->analyzeProgram(ar);
if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
if (m_funcScope && !m_arrayParams) {
for (int i = 0, n = m_funcScope->getMaxParamCount(); i < n; ++i) {
if (TypePtr specType = m_funcScope->getParamTypeSpec(i)) {
const char *fmt = 0;
string ptype;
if (!m_params || m_params->getCount() <= i) {
if (i >= m_funcScope->getMinParamCount()) break;
fmt = "parameter %d of %s() requires %s, none given";
} else {
ExpressionPtr param = (*m_params)[i];
if (!Type::Inferred(ar, param->getType(), specType)) {
fmt = "parameter %d of %s() requires %s, called with %s";
}
ptype = param->getType()->toString();
}
if (fmt) {
string msg;
Util::string_printf
(msg, fmt,
i + 1,
Util::escapeStringForCPP(m_funcScope->getOriginalName()).c_str(),
specType->toString().c_str(), ptype.c_str());
Compiler::Error(Compiler::BadArgumentType,
shared_from_this(), msg);
}
}
}
}
}
}
struct InlineCloneInfo {
explicit InlineCloneInfo(FunctionScopePtr fs)
: func(fs)
, callWithThis(false)
{}
FunctionScopePtr func;
StringToExpressionPtrMap sepm;
ExpressionListPtr elist;
bool callWithThis;
string localThis;
string staticClass;
};
//typedef std::map<std::string, ExpressionPtr> StringToExpressionPtrMap;
static ExpressionPtr cloneForInlineRecur(InlineCloneInfo &info,
ExpressionPtr exp,
const std::string &prefix,
AnalysisResultConstPtr ar,
FunctionScopePtr scope) {
exp->getOriginalScope(); // make sure to cache the original scope
exp->setBlockScope(scope);
for (int i = 0, n = exp->getKidCount(); i < n; i++) {
if (ExpressionPtr k = exp->getNthExpr(i)) {
exp->setNthKid(i, cloneForInlineRecur(info, k, prefix, ar, scope));
}
}
StaticClassName *scn = dynamic_cast<StaticClassName*>(exp.get());
if (scn && scn->isStatic() && !info.staticClass.empty()) {
scn->resolveStatic(info.staticClass);
}
switch (exp->getKindOf()) {
case Expression::KindOfSimpleVariable:
{
SimpleVariablePtr sv(dynamic_pointer_cast<SimpleVariable>(exp));
if (sv->isSuperGlobal()) break;
string name;
if (sv->isThis()) {
if (!info.callWithThis) {
if (!sv->hasContext(Expression::ObjectContext)) {
exp = sv->makeConstant(ar, "null");
} else {
// This will produce the wrong error
// we really want a "throw_fatal" ast node.
exp = sv->makeConstant(ar, "null");
}
break;
}
if (info.localThis.empty()) break;
name = info.localThis;
} else {
name = prefix + sv->getName();
}
SimpleVariablePtr rep(new SimpleVariable(
exp->getScope(), exp->getLocation(), name));
rep->copyContext(sv);
rep->updateSymbol(SimpleVariablePtr());
rep->getSymbol()->setHidden();
// Conservatively set flags to prevent
// the alias manager from getting confused.
// On the next pass, it will correct the values,
// and optimize appropriately.
rep->getSymbol()->setUsed();
rep->getSymbol()->setReferenced();
if (exp->getContext() & (Expression::LValue|
Expression::RefValue|
Expression::RefParameter)) {
info.sepm[name] = rep;
}
exp = rep;
}
break;
case Expression::KindOfObjectMethodExpression:
{
FunctionCallPtr call(
static_pointer_cast<FunctionCall>(exp));
if (call->getFuncScope() == info.func) {
call->setNoInline();
}
break;
}
case Expression::KindOfSimpleFunctionCall:
{
SimpleFunctionCallPtr call(static_pointer_cast<SimpleFunctionCall>(exp));
call->addLateDependencies(ar);
call->setLocalThis(info.localThis);
if (call->getFuncScope() == info.func) {
call->setNoInline();
}
}
default:
break;
}
return exp;
}
static ExpressionPtr cloneForInline(InlineCloneInfo &info,
ExpressionPtr exp,
const std::string &prefix,
AnalysisResultConstPtr ar,
FunctionScopePtr scope) {
return cloneForInlineRecur(info, exp->clone(), prefix, ar, scope);
}
static int cloneStmtsForInline(InlineCloneInfo &info, StatementPtr s,
const std::string &prefix,
AnalysisResultConstPtr ar,
FunctionScopePtr scope) {
switch (s->getKindOf()) {
case Statement::KindOfStatementList:
{
for (int i = 0, n = s->getKidCount(); i < n; ++i) {
if (int ret = cloneStmtsForInline(info, s->getNthStmt(i),
prefix, ar, scope)) {
return ret;
}
}
return 0;
}
case Statement::KindOfExpStatement:
info.elist->addElement(cloneForInline(
info, dynamic_pointer_cast<ExpStatement>(s)->
getExpression(), prefix, ar, scope));
return 0;
case Statement::KindOfReturnStatement:
{
ExpressionPtr exp =
dynamic_pointer_cast<ReturnStatement>(s)->getRetExp();
if (exp) {
exp = cloneForInline(info, exp, prefix, ar, scope);
if (exp->hasContext(Expression::RefValue)) {
exp->clearContext(Expression::RefValue);
if (exp->isRefable()) exp->setContext(Expression::LValue);
}
info.elist->addElement(exp);
return 1;
}
return -1;
}
default:
not_reached();
}
return 1;
}
ExpressionPtr FunctionCall::inliner(AnalysisResultConstPtr ar,
ExpressionPtr obj, std::string localThis) {
FunctionScopePtr fs = getFunctionScope();
if (m_noInline || !fs || fs == m_funcScope || !m_funcScope->getStmt()) {
return ExpressionPtr();
}
BlockScope::s_jobStateMutex.lock();
if (m_funcScope->getMark() == BlockScope::MarkProcessing) {
fs->setForceRerun(true);
BlockScope::s_jobStateMutex.unlock();
return ExpressionPtr();
}
ReadLock lock(m_funcScope->getInlineMutex());
BlockScope::s_jobStateMutex.unlock();
if (!m_funcScope->getInlineAsExpr()) {
return ExpressionPtr();
}
if (m_funcScope->getInlineSameContext() &&
m_funcScope->getContainingClass() &&
m_funcScope->getContainingClass() != getClassScope()) {
/*
The function contains a context sensitive construct such as
call_user_func (context sensitive because it could call
array('parent', 'foo')) so its not safe to inline it
into a different context.
*/
return ExpressionPtr();
}
MethodStatementPtr m
(dynamic_pointer_cast<MethodStatement>(m_funcScope->getStmt()));
VariableTablePtr vt = fs->getVariables();
int nAct = m_params ? m_params->getCount() : 0;
int nMax = m_funcScope->getMaxParamCount();
if (nAct < m_funcScope->getMinParamCount() || !m->getStmts()) {
return ExpressionPtr();
}
InlineCloneInfo info(m_funcScope);
info.elist = ExpressionListPtr(new ExpressionList(
getScope(), getLocation(),
ExpressionList::ListKindWrapped));
std::ostringstream oss;
oss << fs->nextInlineIndex() << "_" << m_name << "_";
std::string prefix = oss.str();
if (obj) {
info.callWithThis = true;
if (!obj->isThis()) {
SimpleVariablePtr var
(new SimpleVariable(getScope(),
obj->getLocation(),
prefix + "this"));
var->updateSymbol(SimpleVariablePtr());
var->getSymbol()->setHidden();
var->getSymbol()->setUsed();
var->getSymbol()->setReferenced();
AssignmentExpressionPtr ae
(new AssignmentExpression(getScope(),
obj->getLocation(),
var, obj, false));
info.elist->addElement(ae);
info.sepm[var->getName()] = var;
info.localThis = var->getName();
}
} else {
if (m_classScope) {
if (!m_funcScope->isStatic()) {
ClassScopeRawPtr oCls = getOriginalClass();
FunctionScopeRawPtr oFunc = getOriginalFunction();
if (oCls && !oFunc->isStatic() &&
(oCls == m_classScope ||
oCls->derivesFrom(ar, m_className, true, false))) {
info.callWithThis = true;
info.localThis = localThis;
}
}
if (!isSelf() && !isParent() && !isStatic()) {
info.staticClass = m_className;
}
}
}
ExpressionListPtr plist = m->getParams();
int i;
for (i = 0; i < nMax || i < nAct; i++) {
ParameterExpressionPtr param
(i < nMax ?
dynamic_pointer_cast<ParameterExpression>((*plist)[i]) :
ParameterExpressionPtr());
ExpressionPtr arg = i < nAct ? (*m_params)[i] :
Clone(param->defaultValue(), getScope());
SimpleVariablePtr var
(new SimpleVariable(getScope(),
(i < nAct ? arg.get() : this)->getLocation(),
prefix + (param ?
param->getName() :
lexical_cast<string>(i))));
var->updateSymbol(SimpleVariablePtr());
var->getSymbol()->setHidden();
var->getSymbol()->setUsed();
var->getSymbol()->setReferenced();
bool ref =
(i < nMax && m_funcScope->isRefParam(i)) ||
arg->hasContext(RefParameter);
arg->clearContext(RefParameter);
AssignmentExpressionPtr ae
(new AssignmentExpression(getScope(),
arg->getLocation(),
var, arg, ref));
info.elist->addElement(ae);
if (i < nAct && (ref || !arg->isScalar())) {
info.sepm[var->getName()] = var;
}
}
if (cloneStmtsForInline(info, m->getStmts(), prefix, ar,
getFunctionScope()) <= 0) {
info.elist->addElement(makeConstant(ar, "null"));
}
if (info.sepm.size()) {
ExpressionListPtr unset_list
(new ExpressionList(getScope(), getLocation()));
for (StringToExpressionPtrMap::iterator it = info.sepm.begin(),
end = info.sepm.end(); it != end; ++it) {
ExpressionPtr var = it->second->clone();
var->clearContext((Context)(unsigned)-1);
unset_list->addElement(var);
}
ExpressionPtr unset(
new UnaryOpExpression(getScope(), getLocation(),
unset_list, T_UNSET, true));
i = info.elist->getCount();
ExpressionPtr ret = (*info.elist)[--i];
if (ret->isScalar()) {
info.elist->insertElement(unset, i);
} else {
ExpressionListPtr result_list
(new ExpressionList(getScope(), getLocation(),
ExpressionList::ListKindLeft));
if (ret->hasContext(LValue)) {
result_list->setContext(LValue);
result_list->setContext(ReturnContext);
}
result_list->addElement(ret);
result_list->addElement(unset);
(*info.elist)[i] = result_list;
}
}
recomputeEffects();
return replaceValue(info.elist);
}
ExpressionPtr FunctionCall::preOptimize(AnalysisResultConstPtr ar) {
if (m_class) updateClassName();
return ExpressionPtr();
}
ExpressionPtr FunctionCall::postOptimize(AnalysisResultConstPtr ar) {
if (m_class) updateClassName();
return ExpressionPtr();
}
///////////////////////////////////////////////////////////////////////////////
TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar,
TypePtr type, bool coerce,
FunctionScopePtr func,
bool arrayParams) {
#ifdef HPHP_DETAILED_TYPE_INF_ASSERT
assert(func->hasUser(getScope(), BlockScope::UseKindCaller));
#endif /* HPHP_DETAILED_TYPE_INF_ASSERT */
ConstructPtr self = shared_from_this();
TypePtr frt;
{
TRY_LOCK(func);
func->getInferTypesMutex().assertOwnedBySelf();
assert(!func->inVisitScopes() || getScope() == func);
frt = func->getReturnType();
}
if (!frt) {
m_voidReturn = true;
setActualType(TypePtr());
if (!isUnused() && !type->is(Type::KindOfAny)) {
if (!hasContext(ReturnContext) &&
!func->isFirstPass() && !func->isAbstract()) {
if (Option::WholeProgram || !func->getContainingClass() ||
func->isStatic() || func->isFinal() || func->isPrivate()) {
Compiler::Error(Compiler::UseVoidReturn, self);
}
}
if (!Type::IsMappedToVariant(type)) {
setExpectedType(type);
}
m_voidWrapper = true;
}
} else {
m_voidReturn = false;
m_voidWrapper = false;
type = checkTypesImpl(ar, type, frt, coerce);
assert(m_actualType);
}
if (arrayParams) {
m_extraArg = 0;
(*m_params)[0]->inferAndCheck(ar, Type::Array, false);
} else {
m_extraArg = func->inferParamTypes(ar, self, m_params, m_valid);
}
m_variableArgument = func->isVariableArgument();
if (m_valid) {
m_implementedType.reset();
} else {
m_implementedType = Type::Variant;
}
assert(type);
return type;
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,11 +14,11 @@
+----------------------------------------------------------------------+
*/
#ifndef __FUNCTION_CALL_H__
#define __FUNCTION_CALL_H__
#ifndef incl_HPHP_FUNCTION_CALL_H_
#define incl_HPHP_FUNCTION_CALL_H_
#include <compiler/analysis/function_scope.h>
#include <compiler/expression/static_class_name.h>
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/expression/static_class_name.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -30,13 +30,11 @@ DECLARE_BOOST_TYPES(FunctionCall);
class FunctionCall : public Expression, public StaticClassName {
protected:
FunctionCall(EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS, ExpressionPtr nameExp,
const std::string &name, ExpressionListPtr params,
ExpressionPtr classExp);
const std::string &name, bool hadBackslash,
ExpressionListPtr params, ExpressionPtr classExp);
public:
void analyzeProgram(AnalysisResultPtr ar);
// overriding Expression::outputCPP to implement void wrapper
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual bool isRefable(bool checkError = false) const { return true;}
virtual bool isTemporary() const;
@@ -49,21 +47,25 @@ public:
const std::string &getName() const { return m_name; }
const std::string &getOriginalName() const { return m_origName; }
const std::string getNonNSOriginalName() const {
auto nsPos = m_origName.rfind('\\');
if (nsPos == string::npos) {
return m_origName;
}
return m_origName.substr(nsPos + 1);
}
ExpressionPtr getNameExp() const { return m_nameExp; }
const ExpressionListPtr& getParams() const { return m_params; }
void setNoInline() { m_noInline = true; }
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
void deepCopy(FunctionCallPtr exp);
FunctionScopeRawPtr getFuncScope() const { return m_funcScope; }
bool canInvokeFewArgs();
void setArrayParams() { m_arrayParams = true; }
bool isValid() const { return m_valid; }
bool hadBackslash() const { return m_hadBackslash; }
protected:
void outputDynamicCall(CodeGenerator &cg,
AnalysisResultPtr ar, bool method);
ExpressionPtr m_nameExp;
std::string m_name;
std::string m_origName;
@@ -87,6 +89,7 @@ protected:
unsigned m_noInline : 1;
unsigned m_invokeFewArgsDecision : 1;
unsigned m_arrayParams : 1;
bool m_hadBackslash;
// Extra arguments form an array, to which the scalar array optimization
// should also apply.
@@ -114,4 +117,4 @@ protected:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __FUNCTION_CALL_H__
#endif // incl_HPHP_FUNCTION_CALL_H_
@@ -0,0 +1,291 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/include_expression.h"
#include "hphp/util/parser/hphp.tab.hpp"
#include "hphp/compiler/analysis/code_error.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/statement/statement_list.h"
#include "hphp/compiler/option.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/expression/binary_op_expression.h"
#include "hphp/compiler/analysis/class_scope.h"
#include "hphp/compiler/parser/parser.h"
#include "hphp/compiler/analysis/variable_table.h"
#include "hphp/compiler/expression/scalar_expression.h"
#include "hphp/util/util.h"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
IncludeExpression::IncludeExpression
(EXPRESSION_CONSTRUCTOR_PARAMETERS, ExpressionPtr exp, int op)
: UnaryOpExpression(
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(IncludeExpression),
exp, op, true),
m_documentRoot(false), m_depsSet(false) {
}
ExpressionPtr IncludeExpression::clone() {
IncludeExpressionPtr exp(new IncludeExpression(*this));
Expression::deepCopy(exp);
exp->m_exp = Clone(m_exp);
exp->m_depsSet = false;
return exp;
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
static string get_include_file_path(const string &source,
const string &var, const string &lit,
bool documentRoot) {
if (var.empty()) {
// absolute path
if (!lit.empty() && lit[0] == '/') {
return lit;
}
// relative path to document root
if (documentRoot) {
return lit;
}
struct stat sb;
// relative path to containing file's directory
if (source.empty() && (stat(lit.c_str(), &sb) == 0)) {
return lit;
}
size_t pos = source.rfind('/');
string resolved;
if (pos != string::npos) {
resolved = source.substr(0, pos + 1) + lit;
if (stat(resolved.c_str(), &sb) == 0) {
return resolved;
}
}
// if file cannot be found, resolve it using search paths
for (unsigned int i = 0; i < Option::IncludeSearchPaths.size(); i++) {
string filename = Option::IncludeSearchPaths[i] + "/" + lit;
struct stat sb;
if (stat(filename.c_str(), &sb) == 0) {
return filename;
}
}
// try still use relative path to containing file's directory
if (!resolved.empty()) {
return resolved;
}
return lit;
}
// [IncludeRoot] . 'string'
std::map<string, string>::const_iterator iter =
Option::IncludeRoots.find(var);
if (iter != Option::IncludeRoots.end()) {
string includeRoot = iter->second;
if (!includeRoot.empty()) {
if (includeRoot[0] == '/') includeRoot = includeRoot.substr(1);
if (includeRoot.empty() ||
includeRoot[includeRoot.size()-1] != '/') {
includeRoot += "/";
}
}
if (!lit.empty() && lit[0] == '/') {
includeRoot += lit.substr(1);
} else {
includeRoot += lit;
}
return includeRoot;
}
return "";
}
static void parse_string_arg(ExpressionPtr exp, string &var, string &lit) {
if (exp->is(Expression::KindOfUnaryOpExpression)) {
UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(exp));
if (u->getOp() == '(') {
parse_string_arg(u->getExpression(), var, lit);
return;
}
} else if (exp->is(Expression::KindOfBinaryOpExpression)) {
BinaryOpExpressionPtr b(static_pointer_cast<BinaryOpExpression>(exp));
if (b->getOp() == '.') {
string v, l;
parse_string_arg(b->getExp2(), v, l);
if (v.empty()) {
parse_string_arg(b->getExp1(), var, lit);
lit += l;
return;
}
}
}
if (exp->isLiteralString()) {
var = "";
lit = exp->getLiteralString();
return;
}
var = exp->getText();
lit = "";
return;
}
string IncludeExpression::CheckInclude(ConstructPtr includeExp,
ExpressionPtr fileExp,
bool &documentRoot) {
string container = includeExp->getLocation()->file;
string var, lit;
parse_string_arg(fileExp, var, lit);
if (lit.empty()) return lit;
if (var == "__DIR__") {
var = "";
// get_include_file_path will check relative to the current file's dir
// as long as the first char isn't a /
if (lit[0] == '/') {
lit = lit.substr(1);
}
}
string included = get_include_file_path(container, var, lit, documentRoot);
if (!included.empty()) {
if (included == container) {
Compiler::Error(Compiler::BadPHPIncludeFile, includeExp);
}
included = Util::canonicalize(included);
if (!var.empty()) documentRoot = true;
}
return included;
}
void IncludeExpression::onParse(AnalysisResultConstPtr ar, FileScopePtr scope) {
/* m_documentRoot is a bitfield */
bool dr = m_documentRoot;
m_include = CheckInclude(shared_from_this(), m_exp, dr);
m_documentRoot = dr;
if (!m_include.empty()) ar->parseOnDemand(m_include);
}
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
FileScopeRawPtr IncludeExpression::getIncludedFile(
AnalysisResultConstPtr ar) const {
if (m_include.empty()) return FileScopeRawPtr();
return ar->findFileScope(m_include);
}
std::string IncludeExpression::includePath() const {
return m_include;
}
bool IncludeExpression::isReqLit() const {
return !m_include.empty() &&
m_op == T_REQUIRE_ONCE && isDocumentRoot();
}
bool IncludeExpression::analyzeInclude(AnalysisResultConstPtr ar,
const std::string &include) {
ConstructPtr self = shared_from_this();
FileScopePtr file = ar->findFileScope(include);
if (!file) {
Compiler::Error(Compiler::PHPIncludeFileNotFound, self);
return false;
}
FunctionScopePtr func = getFunctionScope();
if (func && file->getPseudoMain()) {
file->getPseudoMain()->addUse(func, BlockScope::UseKindInclude);
}
return true;
}
void IncludeExpression::analyzeProgram(AnalysisResultPtr ar) {
if (!m_include.empty()) {
if (ar->getPhase() == AnalysisResult::AnalyzeAll ||
ar->getPhase() == AnalysisResult::AnalyzeFinal) {
if (analyzeInclude(ar, m_include)) {
FunctionScopePtr func = getFunctionScope();
getFileScope()->addIncludeDependency(ar, m_include,
func && func->isInlined());
}
}
}
VariableTablePtr var = getScope()->getVariables();
var->setAttribute(VariableTable::ContainsLDynamicVariable);
var->forceVariants(ar, VariableTable::AnyVars);
UnaryOpExpression::analyzeProgram(ar);
}
ExpressionPtr IncludeExpression::preOptimize(AnalysisResultConstPtr ar) {
if (ar->getPhase() >= AnalysisResult::FirstPreOptimize) {
if (m_include.empty()) {
bool dr = m_documentRoot;
m_include = CheckInclude(shared_from_this(), m_exp, dr);
m_documentRoot = dr;
m_depsSet = false;
}
if (!m_depsSet && !m_include.empty()) {
analyzeInclude(ar, m_include);
m_depsSet = true;
}
}
return ExpressionPtr();
}
ExpressionPtr IncludeExpression::postOptimize(AnalysisResultConstPtr ar) {
if (!m_include.empty()) {
if (!m_depsSet) {
analyzeInclude(ar, m_include);
m_depsSet = true;
}
FileScopePtr fs = ar->findFileScope(m_include);
if (fs && fs->getPseudoMain()) {
if (!Option::KeepStatementsWithNoEffect) {
if (ExpressionPtr rep = fs->getEffectiveImpl(ar)) {
recomputeEffects();
return replaceValue(rep->clone());
}
}
} else {
m_include = "";
}
}
return ExpressionPtr();
}
TypePtr IncludeExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
return UnaryOpExpression::inferTypes(ar, type, coerce);
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void IncludeExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
UnaryOpExpression::outputPHP(cg, ar);
}
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,10 +14,10 @@
+----------------------------------------------------------------------+
*/
#ifndef __INCLUDE_EXPRESSION_H__
#define __INCLUDE_EXPRESSION_H__
#ifndef incl_HPHP_INCLUDE_EXPRESSION_H_
#define incl_HPHP_INCLUDE_EXPRESSION_H_
#include <compiler/expression/unary_op_expression.h>
#include "hphp/compiler/expression/unary_op_expression.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -28,7 +28,7 @@ class IncludeExpression : public UnaryOpExpression, public IParseHandler {
public:
static std::string CheckInclude(ConstructPtr includeExp,
ExpressionPtr fileExp,
bool &documentRoot, bool relative);
bool &documentRoot);
public:
IncludeExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
@@ -44,12 +44,6 @@ public:
bool isReqLit() const;
void setDocumentRoot() { m_documentRoot = true;}
bool isDocumentRoot() const { return m_documentRoot;}
void setPrivateScope() { m_privateScope = true; }
bool isPrivateScope() const { return m_privateScope; }
void setPrivateInclude() { m_privateInclude = true; }
bool isPrivateInclude() const { return m_privateInclude; }
void setModule() { m_module = 1; }
bool isModule() const { return m_module; }
std::string includePath() const;
FileScopeRawPtr getIncludedFile(AnalysisResultConstPtr) const;
private:
@@ -64,9 +58,6 @@ private:
* privateInclude means this is the *only* reference to the included file
*/
unsigned m_documentRoot : 1;
unsigned m_privateScope : 1;
unsigned m_privateInclude : 1;
unsigned m_module : 1;
unsigned m_depsSet : 1;
std::string m_include;
@@ -75,4 +66,4 @@ private:
///////////////////////////////////////////////////////////////////////////////
}
#endif // __INCLUDE_EXPRESSION_H__
#endif // incl_HPHP_INCLUDE_EXPRESSION_H_
+283
Ver Arquivo
@@ -0,0 +1,283 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/compiler/expression/list_assignment.h"
#include "hphp/compiler/expression/assignment_expression.h"
#include "hphp/compiler/expression/expression_list.h"
#include "hphp/compiler/analysis/file_scope.h"
#include "hphp/compiler/analysis/function_scope.h"
#include "hphp/compiler/expression/array_element_expression.h"
#include "hphp/compiler/expression/object_property_expression.h"
#include "hphp/compiler/expression/unary_op_expression.h"
#include "hphp/compiler/expression/binary_op_expression.h"
#include "hphp/util/parser/hphp.tab.hpp"
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
/*
Determine whether the rhs behaves normall, or abnormally.
1) If the expression is the silence operator, recurse on the inner expression.
2) If the expression is a list assignment expression, recurse on the
RHS of the expression.
3) If the expression is one of the following, then E behaves normally:
Simple/Dynamic variable (including $this and superglobals)
Array element expression
Property expression
Static variable expression
Function call expression
Preinc/predec expression (but not postinc/postdec)
Assignment expression
Assignment op expression
Binding assignment expression
Include/require expression
Eval expression
Array expression
Array cast expression
4) For all other expressions, E behaves abnormally. This includes:
All binary operator expressions
All unary operator expressions except silence and preinc/predec
Scalar expression of type null, bool, int, double, or string
Qop expression (?:)
Constant expression
Class constant expression
Isset or empty expression
Exit expression
Instanceof expression
*/
static ListAssignment::RHSKind GetRHSKind(ExpressionPtr rhs) {
switch (rhs->getKindOf()) {
case Expression::KindOfSimpleVariable:
case Expression::KindOfDynamicVariable:
case Expression::KindOfArrayElementExpression:
case Expression::KindOfObjectPropertyExpression:
case Expression::KindOfStaticMemberExpression:
case Expression::KindOfSimpleFunctionCall:
case Expression::KindOfDynamicFunctionCall:
case Expression::KindOfObjectMethodExpression:
case Expression::KindOfNewObjectExpression:
case Expression::KindOfAssignmentExpression:
case Expression::KindOfExpressionList:
case Expression::KindOfIncludeExpression:
case Expression::KindOfYieldExpression:
return ListAssignment::Regular;
case Expression::KindOfListAssignment:
return GetRHSKind(static_pointer_cast<ListAssignment>(rhs)->getArray());
case Expression::KindOfUnaryOpExpression: {
UnaryOpExpressionPtr u(static_pointer_cast<UnaryOpExpression>(rhs));
switch (u->getOp()) {
case '@':
return GetRHSKind(u->getExpression());
case T_INC:
case T_DEC:
return u->getFront() ?
ListAssignment::Regular : ListAssignment::Checked;
case T_EVAL:
case T_ARRAY:
case T_ARRAY_CAST:
return ListAssignment::Regular;
default:
return ListAssignment::Null;
}
break;
}
case Expression::KindOfBinaryOpExpression: {
BinaryOpExpressionPtr b(static_pointer_cast<BinaryOpExpression>(rhs));
return b->isAssignmentOp() || b->getOp() == '+' ?
ListAssignment::Regular : ListAssignment::Null;
}
case Expression::KindOfQOpExpression:
return ListAssignment::Checked;
// invalid context
case Expression::KindOfArrayPairExpression:
case Expression::KindOfParameterExpression:
case Expression::KindOfModifierExpression:
case Expression::KindOfUserAttribute:
always_assert(false);
// non-arrays
case Expression::KindOfScalarExpression:
case Expression::KindOfConstantExpression:
case Expression::KindOfClassConstantExpression:
case Expression::KindOfEncapsListExpression:
case Expression::KindOfClosureExpression:
return ListAssignment::Null;
}
// unreachable for known expression kinds
always_assert(false);
}
static bool AssignmentCouldSet(ExpressionListPtr vars, ExpressionPtr var) {
for (int i = 0; i < vars->getCount(); i++) {
ExpressionPtr v = (*vars)[i];
if (!v) continue;
if (v->is(Expression::KindOfSimpleVariable) &&
v->canonCompare(var)) {
return true;
}
if (v->is(Expression::KindOfDynamicVariable)) return true;
if (v->is(Expression::KindOfListAssignment) &&
AssignmentCouldSet(static_pointer_cast<ListAssignment>(v)->
getVariables(), var)) {
return true;
}
}
return false;
}
ListAssignment::ListAssignment
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionListPtr variables, ExpressionPtr array, bool rhsFirst /* = false */)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ListAssignment)),
m_variables(variables), m_array(array), m_rhsKind(Regular),
m_rhsFirst(rhsFirst) {
setLValue();
if (m_array) {
m_rhsKind = GetRHSKind(m_array);
if (m_array->is(KindOfSimpleVariable)) {
if (AssignmentCouldSet(m_variables, m_array)) {
m_array->setContext(LValue);
}
}
}
}
ExpressionPtr ListAssignment::clone() {
ListAssignmentPtr exp(new ListAssignment(*this));
Expression::deepCopy(exp);
exp->m_variables = Clone(m_variables);
exp->m_array = Clone(m_array);
return exp;
}
void ListAssignment::setLValue() {
if (m_variables) {
for (int i = 0; i < m_variables->getCount(); i++) {
ExpressionPtr exp = (*m_variables)[i];
if (exp) {
if (exp->is(Expression::KindOfListAssignment)) {
ListAssignmentPtr sublist =
dynamic_pointer_cast<ListAssignment>(exp);
sublist->setLValue();
} else {
// Magic contexts I took from assignment expression
exp->setContext(Expression::DeepAssignmentLHS);
exp->setContext(Expression::AssignmentLHS);
exp->setContext(Expression::LValue);
exp->setContext(Expression::NoLValueWrapper);
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
void ListAssignment::analyzeProgram(AnalysisResultPtr ar) {
if (m_variables) m_variables->analyzeProgram(ar);
if (m_array) m_array->analyzeProgram(ar);
FunctionScopePtr func = getFunctionScope();
if (func) func->disableInline();
if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
if (m_variables) {
for (int i = 0; i < m_variables->getCount(); i++) {
ExpressionPtr exp = (*m_variables)[i];
if (exp) {
if (!exp->is(Expression::KindOfListAssignment)) {
CheckNeeded(exp, ExpressionPtr());
}
}
}
}
}
}
ConstructPtr ListAssignment::getNthKid(int n) const {
switch (m_rhsFirst ? 1 - n : n) {
case 0:
return m_variables;
case 1:
return m_array;
default:
assert(false);
break;
}
return ConstructPtr();
}
int ListAssignment::getKidCount() const {
return 2;
}
void ListAssignment::setNthKid(int n, ConstructPtr cp) {
switch (m_rhsFirst ? 1 - n : n) {
case 0:
m_variables = boost::dynamic_pointer_cast<ExpressionList>(cp);
break;
case 1:
m_array = boost::dynamic_pointer_cast<Expression>(cp);
break;
default:
assert(false);
break;
}
}
TypePtr ListAssignment::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
if (m_variables) {
for (int i = m_variables->getCount(); i--; ) {
ExpressionPtr exp = (*m_variables)[i];
if (exp) {
if (exp->is(Expression::KindOfListAssignment)) {
exp->inferAndCheck(ar, Type::Any, false);
} else {
inferAssignmentTypes(ar, Type::Variant, true, exp);
}
}
}
}
if (!m_array) return TypePtr();
return m_array->inferAndCheck(ar, Type::Variant, false);
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void ListAssignment::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf("list(");
if (m_variables) m_variables->outputPHP(cg, ar);
if (m_array) {
cg_printf(") = ");
m_array->outputPHP(cg, ar);
} else {
cg_printf(")");
}
}
+60
Ver Arquivo
@@ -0,0 +1,60 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_LIST_ASSIGNMENT_H_
#define incl_HPHP_LIST_ASSIGNMENT_H_
#include "hphp/compiler/expression/expression.h"
#include "hphp/compiler/expression/simple_variable.h"
#include "hphp/compiler/analysis/variable_table.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
DECLARE_BOOST_TYPES(ExpressionList);
DECLARE_BOOST_TYPES(ListAssignment);
class ListAssignment : public Expression {
public:
enum RHSKind {
Regular,
Checked,
Null
};
ListAssignment(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionListPtr variables, ExpressionPtr array,
bool rhsFirst = false);
DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS;
RHSKind getRHSKind() const { return m_rhsKind; }
ExpressionListPtr getVariables() const { return m_variables; }
ExpressionPtr getArray() const { return m_array; }
bool isRhsFirst() { return m_rhsFirst; }
private:
ExpressionListPtr m_variables;
ExpressionPtr m_array;
RHSKind m_rhsKind;
bool m_rhsFirst;
void setLValue();
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // incl_HPHP_LIST_ASSIGNMENT_H_
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -14,8 +14,8 @@
+----------------------------------------------------------------------+
*/
#include <compiler/expression/modifier_expression.h>
#include <util/parser/hphp.tab.hpp>
#include "hphp/compiler/expression/modifier_expression.h"
#include "hphp/util/parser/hphp.tab.hpp"
using namespace HPHP;
@@ -134,20 +134,3 @@ void ModifierExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
}
}
void ModifierExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
/**
* Not sure if we can bar access coding errors...
if (isPublic()) {
cg_printf("public: ");
} else if (isProtected()) {
cg_printf("protected: ");
} else {
cg_printf("private: ");
}
*/
cg_printf("public: ");
if (isStatic()) cg_printf("static ");
}

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais