1327 Commits

Autor SHA1 Mensagem Data
Sara Golemon a3803ffa8a HPHP-2.0.2 2013-04-23 10:29:42 -07:00
Jordan DeLong a85369c7ce Fix some mismatched include guards 2013-04-22 23:34:10 -07:00
Edwin Smith 1cea03f3f7 hphp/src is now hphp/hphp
That's it
2013-04-22 23:32:31 -07:00
Mark Williams 52db7956bb 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 23:31:09 -07:00
Mark Williams f6f1655ca5 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 23:30:52 -07:00
Mark Williams 3fa077dd6f Free the VarEnv the correct way
detach, rather than destroy.
2013-04-22 23:30:12 -07:00
mwilliams 4caa51283a 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-22 23:29:21 -07:00
aravind 4f70af91f7 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-22 23:29:10 -07:00
mwilliams 8a0dd4fae4 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-22 23:10:28 -07:00
mwilliams afd5f72964 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-22 23:10:28 -07:00
mikemag ec6617f6bd 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-22 23:10:28 -07:00
jdelong 964de35b10 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-22 23:10:27 -07:00
mwilliams 819058d081 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-22 23:10:27 -07:00
ptarjan e6542d070a stop segfaulting in propery_exists 2013-04-22 22:25:54 -07:00
mwilliams 83bd8ff445 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-22 21:55:22 -07:00
jdelong cf10678119 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-22 18:19:58 -07:00
mwilliams 5226f80d05 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-22 18:19:45 -07:00
jdelong a2ffdae2cf 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-22 18:18:59 -07:00
mikemag 785cf27e00 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-22 18:17:18 -07:00
bsimmers b32b2ec879 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-22 17:28:03 -07:00
mwilliams 1f638e631c 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-22 17:27:47 -07:00
mwilliams 1ab14f87af 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-22 17:27:32 -07:00
mwilliams fefd56e9d7 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-22 17:27:16 -07:00
mwilliams 17049b3a42 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-22 17:25:04 -07:00
Sara Golemon be4c7698eb 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:47:16 -07:00
Sara Golemon 0dcbc83f74 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 18:04:52 -07:00
Sara Golemon d660972153 HPHP 2.0.1 2013-03-22 19:14:35 -07:00
ptarjan ca437add64 fix this callsite incase someone ever does the TODO for setting valueClass() 2013-03-25 13:59:21 -07:00
mwilliams 3611bf3d58 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:59:02 -07:00
jan 565c8477f8 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 13:57:25 -07:00
mwilliams 8f3512f6d3 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 13:57:18 -07:00
ottoni 7241c247dd Disable spilling into MMX registers 2013-03-22 13:57:06 -07:00
jan f06575d4e2 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 20:41:02 -07:00
Owen Yamauchi cc897749f8 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 20:41:02 -07:00
ptarjan b597e3a753 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 20:41:02 -07:00
mwilliams 8ec621676d 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 20:41:02 -07:00
mwilliams a134b25671 Fix nemo warnings about undefined $this
The fix for the crash caused us to take a different path
when checking locals.
2013-03-21 20:41:01 -07:00
mwilliams 15fa1ebfde Fix StringBuffer::resize()
capacity doesnt include the terminating null, so len is
allowed to grow to capacity (not capacity - 1).
2013-03-19 14:47:25 -07:00
mwilliams ce75713972 Fix assertion when target==analyze
Option::OutputHHBC should always be true.
2013-03-19 14:47:15 -07:00
Owen Yamauchi adc56c6d8c 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 14:47:06 -07:00
Sara Golemon 3fb0fe8a6a SSL_OP_NO_TLSv1_2 is not supported by all openssl versions 2013-03-18 18:38:47 -07:00
ottoni 38306b527f SIMPLIFY_COMMUTATIVE only handles Type::Int
So check that the inputs are really Ints.
2013-03-18 18:38:37 -07:00
aravind e4e3bee5d3 Don't simplify Same to Eq to arrays 2013-03-18 18:38:29 -07:00
michalburger1 d25adc550b 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 16:20:44 -07:00
Sara Golemon 8b23419a37 HPHP version 2.0.0 2013-03-14 16:00:42 -07:00
ottoni af5623b4fc 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 15:45:51 -07:00
ptarjan b51003b5aa 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 15:45:40 -07:00
mwilliams 5f019f5b43 Fix CodeGenerator::cgNInstanceOf
It assumed the result would be in rax, but it isnt always.
Use the correct register.
2013-03-13 10:16:23 -07:00
bertrand 35e347efa5 Fixed ContNext by writing InitNull rather than Uninit.
Apparently, m_received needs to be InitNull, rather than
Uninit.
2013-03-13 10:16:14 -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
jdelong ffb22ee35d Rename getConstValAsFoo to getValFoo
I spent some time trying to simplify ConstInstruction, but it
turns out this is all I really want right now.
2013-02-06 03:46:18 -08:00
jdelong b23389cc0a Do a small IR TODO for NamedEntity
Instead of passing them through as uintptr_t, add a type and
ConstInstruction support.
2013-02-06 03:46:17 -08:00
ptarjan aed6237347 remove iop Raise 2013-02-06 03:46:17 -08:00
ptarjan fb56b082df change abstract function check to be a real method instead of a check at the caller
Instead of checking at every single callsite if a function is abstract, instead lets write out a method that just immediately fatals. I added an immediate to the Fatal opcode to say if the stack should be popped or not.

The hardest part of this diff was threading the `skipFrame` through everything. I ran into an ambiguous method issue and had to solve it with an Enum. I chose to create a new method instead of adding a boolean to `raise_errror` because I don't like boolean params.
2013-02-06 03:46:17 -08:00
smith 7e66f951f2 Add a const instruction id field we can use for array indexing.
Currently, IRInstruction has no id field that is stable between
passes, and the existing id field is used for transient analyzer
state.  This adds a new IId (instruction id) id field and changes
memelim to use a side bitset for liveness.
2013-02-06 03:46:17 -08:00
jdelong 7f5b94d1de Lambda fix missed in review
Minor change for portability.  (gcc is technically violating
the standard compiling this lambda as is.)
2013-02-06 03:46:17 -08:00
jdelong f8199d472e Fix a bug in exception handling (relating to fault regions)
When we resume after executing a fault handler via the Unwind
opcode, we were rethrowing as if the exception came from the PC
immediately following the protected region for that handler.  If that
offset was protected by a non-overlapping user catch handler, user
catch handlers (or other fault handlers) could be invoked even though
the original exception didn't come from their region.  This changes it
to track the number of nested handlers we've hit and rethrow from the
same PC that originally raised it.
2013-02-06 03:46:17 -08:00
andrewparoski 2562487ecd Fix bug with token_get_all() and the T_XHP_TAG_LT token
The text returned for T_XHP_TAG_LT tokens was incorrect. This diff fixes
the lexer appropriately. I also touched up a few parts of the lexer where
"STEPPOS" was missing, and removed the hack for the T_FINALLY token as it
is no longer needed.
2013-02-06 03:46:16 -08:00
bsimmers f539a1f21e Add RuntimeOption::EvalJitCompareHHIR
This is meant to help compare code quality between hhir and
tx64. If hhir successfully translates a tracelet, it will be
retranslated with tx64. If the code from hhir is larger than the code
from tx64, the bytecode and disassembly for both translations will be
logged. Only the hhir tracelet is put in the SrcDB, and the cursors of
a and astubs are rewound to reuse the space from the tx64 translation.
2013-02-06 03:46:16 -08:00
Sara Golemon 6d2baf8151 Pull xed disassembling logic out into a class
Right now it's just used as a special case in ir.cpp
2013-02-06 03:46:08 -08:00
bertrand 584aa27f5d Warn when trying to index a scalar as if it were an array
We want to produce a warning when someone tries to access a scalar as if it were an array.  So, for example:
$x = 5;
$x[0];  // Bad.
This warning should be suppressed for list assignments where the RHS is false, though, because it's common to return FALSE in place of a list when there are no more values (e.g., mysql_fetch_array).  So:
$x = FALSE;
$foo = $x[0];  // warning
list($foo) = $x;  // no warning.

To support this behavior I've introduced a new member operation to the bytecode, EQ, which is exactly like EI but is quiet about warnings.  List assignment is then translated using EQ.
2013-02-04 16:12:52 -08:00
je@fb.com 549bcec0a3 Prohibit pcntl_exec() in multi-threaded mode.
Prohibit pcntl_exec() in multi-threaded mode, because otherwise file
handles related to repos can survive across exec with file locks held,
resulting in effective deadlock.
2013-02-04 16:12:52 -08:00
ptc f22a207836 Fix onAssignNew to do proper ref handling
Fix for the following code snippet:

<?php
function f() {
  $y = 123;
  $x =& $y;
  $x =& new stdclass;
  // Zend outputs false, HPHP outputs true
  var_dump(is_object($y));
}
f();
2013-02-04 15:49:04 -08:00
alia 166c5aca41 Cleanups to tracebuilder, irfactory and simplifier.
Cleaned up tracebuilder and simplifier. Moved simplifications
from tracebuilder to simplifier. Collected all the state tracking code
in one place in tracebuilder. Added runtime options flags to control
CSE and simplification during parsing, to disable parse-time
optimizations and to enable running them as a separate pass. Cleaned
up irfactory.
2013-02-04 15:49:04 -08:00
jdelong 7adb4ba3ff Support for InstanceOfD translations
Implement InstanceOfD for HHIR, with most of the tx64
optimizations to it.  Currently leaves branch fusion disabled since it
appears to be too aggressive in some grepping of DumpIR on a repo
sandbox.
2013-02-04 15:49:03 -08:00
bsimmers 520a0010ba Beginnings of a generic vector translator for hhir
This diff includes the basic outline for an IR vector
translator, as well as some minor changes to the rest of the system to
support it. Only a limited number of CGetMs are actually supported
right now; more complete support will come in diffs to follow.
2013-02-04 15:49:03 -08:00
smith 75f2e27a22 Fix memory error in ConstInstruction constructor
We're creating a corrupt IRInstruction by saving a pointer to an
argument that's only valid for the lifetime of the ConstInstruction
constructor, rather than the lifetime of the ConstInstruction itself.
2013-02-04 15:49:03 -08:00
Owen Yamauchi df45c04bb7 Delete atomic_cas
Relatively easy, and I didn't come across any suspicious activity while I was at
it.

There are two forms of CAS in the library: weak and strong. The difference is
that the weak version is allowed to spuriously fail; i.e. not do the CAS even
though the atomic variable has the expected value.

On x64 there is no difference in the underlying implementation, but on ARM there
is, because ARM has no atomic-CAS instruction. So the distinction now matters to
us. I've followed the guidance from the docs, which is: "When a
compare-and-exchange is in a loop, the weak version will yield better
performance on some platforms. When a weak compare-and-exchange would require a
loop and a strong one would not, the strong one is preferable." (The ARM
implementation of strong-CAS actually has a loop in it, is why.)
2013-02-04 15:49:03 -08:00
bsimmers 3dca014590 Add Trace::punt
Running a debug build with TRACE=punt:1 will dump stats at
the end of each request about which punts are dynamically important.
2013-02-04 15:49:03 -08:00
Owen Yamauchi 40e5406ca6 Delete atomic_add
Instead of rolling our own atomic operations, we should use the C++11 ones. I'm
planning to get the other ones too (inc, dec, cas), but I'm doing them in
separate diffs to keep the diffs manageable-sized, and bisectable in case
something breaks.

The C++11 atomic ops let you specify the memory ordering semantics you want. Our
implementation of atomic_add was equivalent to memory_order_relaxed (i.e. no
memory barriers of any kind), so I stayed with that, for the most part, when
converting. I think this is OK: a lot of the usages are manipulating counters,
and aren't used to synchronize threads. The one exception is
PhpFile::m_refCount, for which I added acquire/release barriers as appropriate.

Also, ARM has a different definition of what's atomically accessible.
2013-02-04 15:49:03 -08:00
mwilliams 19275ea368 Fix sticky eof on PlainFile
Once a PlainFile hit eof, we would never clear it - even though
we could be writing to it through a different file handle (or
another process could be writing to it).

This clears the eof flag on every read (it will immediately get
set again if the file didnt grow).
2013-02-04 15:49:02 -08:00
mwilliams 6e72e7c76e Fix writes to aliased files
Before each write we would seek to the current position,
as maintained by the File itself. But another File could
be open on the same stream, and could have moved the
current position. Make the seeks relative to the stream's
own pointer.
2013-02-04 15:49:02 -08:00
Sara Golemon abfed3ea68 Update generated_files.sh to use new --hphp mode hhvm 2013-02-04 15:48:53 -08:00
jan 106321ec17 ext_asio extension
This adds ext_asio extension that reimplements Preparer in C++. The
semantics are preserved as much as possible.

Known changes in semantics:
- cycle detection was improved: once cycle is detected, C++ preparer
  does not fail the whole prep() call, but removes one edge of the cycle
  and injects an exception
- context tracking was improved: C++ preparer maintains stack of entered
  contexts and once context is exited, it is actively eliminated; as a
  result, invariant is maintained that if wait handle A is blocked by
  wait handle B, the context of B must be at least as specific as the
  context of A (i.e. if you prep(A), all dependencies are guaranteed to
  be imported into the context; if that context dies, all remaining wait
  handles are moved to the parent context); this was not always the case
  in a rare situations in PHP preparer

Implementation improvements:
- PHP preparer had only ResultToken (now StaticResultWaitHandle) and
  AsyncContinuation (now ContinuationWaitHandle); a new types of wait
  handles were introduced:
- GenArrayWaitHandle abstracts away the functionality of waiting for an
  array of dependencies previously implemented as part of
  AsyncContinuation
- SetResultToRefWaitHandle separates functionality of multiple result
  destinations, previously part of AsyncContinuation
- StaticExceptionWaitHandle was introduced
- wait handles are now structured in a tree that implements various
  abstract concepts (WaitableWaitHandle, BlockableWaitHandle, etc.),
  useful for later introduction of wait handles that can wait for I/O
  operations

Not implemented:
- Teak profiling is currently incompatible
- we plan to introduce better profiling support that will combine sync
  and async stack traces
- before improved profiling is available, we plan to collect Teak
  samples using PHP preparer
2013-02-04 15:04:00 -08:00
mwilliams 059d53dda4 Include systemlib.php in repo-authoritative repos
his makes the embedded-repo binaries completely standalone
2013-02-04 10:33:04 -08:00
mwilliams 2cf507e566 Make hphp work without HPHP_HOME/src/system
hphp used to parse the php files under src/system/classes, and
src/system/global.

  - use systemlib.php instead of src/system/classes (when it exists).
  - explicitly generate the contents of s_variables, since we already
    had assertions about exactly what was supposed to be there
  - build s_constants from g_class_map (this is ok, because when we're
    building the system files, we bypass this code altogether).
2013-02-04 10:33:04 -08:00
jdelong 655215155a Move hphpc compilation files to src/legacy 2013-02-04 10:14:59 -08:00
jdelong 37c7ebdbeb Add Type::subtypeOf and SSATmp::isA()
Smith has been pointing out that most places where we do
exact type equality comparisons should probably go away.  We'd like to
be able to have types like Obj(Foo*) as a subtype of Obj (if we have
traces with known instance types), and think of ConstInt(1) as a
subtype of Int.  The intention is we'll start using isA() or
Type::subtypeOf() in most places that currently are using
Tag::operator==.  Putting this up as its own diff (pieces taken from
pending diffs by @smith and @bsimmers) since I want it in InstanceOfD.
2013-02-04 10:10:49 -08:00
jdelong f6617b221a Clean up some TODOs in hhbctranslator 2013-01-30 12:43:14 -08:00
Sara Golemon 80dd2ff723 Expose response headers in http:// wrapper meta data 2013-01-30 12:20:49 -08:00
jdelong c38bd9da55 Remove disabled SpillStack optimization
I think this isn't necessary now because we use GuardStk and
AssertStk to get type information into the stack.  Unless I'm missing
something, I think we shouldn't be generating any cases where we spill
something back to right where we loaded it from anymore.  (If it turns
out we are, we implement this then.)
2013-01-30 12:20:49 -08:00
jan 1dd1ce6c05 Optimized way to call $cont->{next,send,raise}()
Caching pointers to HPHP::VM::Func improved overall CPU time by about
2%, simplifying invokefunc() by another 1.5%.

Once asynchronous functions are natively implemented, we will be able to
eliminate >95% of these VM reenters.
2013-01-30 12:20:49 -08:00
jdelong dc416fafe4 Move/delete various files from hphp/bin, change tools to a link 2013-01-30 12:19:04 -08:00
bsimmers 89dc02e618 Remove unused ArgDesc::genCode 2013-01-30 11:40:32 -08:00
ptarjan 455e809b50 Allow traits to be created in extensions
It seems like it should exist for completness.
I needed this for adding a trait to the fb extension but I'm
breaking it out because I'm going a different direction with
that diff but it seems generally useful.
2013-01-30 11:40:32 -08:00
bsimmers 92de073468 Fix an assert in non-debug builds
This assert assumes that it will only be enabled if
isTransDBEnabled == true.
2013-01-30 11:40:32 -08:00
smith bb0f825533 More uses of range-for, and a couple other things.
Used range-for in more places.  A few places were accidentally
making copies of the list before iterating over them (value assignment).
Created an enum for DEAD, LIVE, etc.
2013-01-30 11:40:32 -08:00
Sara Golemon 038a395ae5 Fix building HPHPc targets
Add pathing properties for folly and double-conversion
2013-01-30 09:19:09 -08:00
Owen Yamauchi bef75046c9 Get rid of some easy inline assembly
build successfully on x64. Building hhvm on ARMv8 no longer trips
over these things. (It still doesn't complete.) I've manuall tested the inline
asm to get the stack pointer, and it works.
2013-01-29 20:32:20 -08:00
kma 7122dfd4e9 Support FP arithmetic.
Relatively short drive to FP arithmetic. Const-ify a few things en route.
2013-01-29 20:32:20 -08:00
kma 94843c636f Missed a few fixes from Jordan. 2013-01-29 20:32:20 -08:00
Sara Golemon 308ddf6806 Combine hphp and hhvm into one executable
Move hphp/main.cpp to compiler/compiler.cpp, and rename
a few things to make it possible to link with hhvm.

Modify hhvm startup to run as hphp if
the first argument is --hphp.
2013-01-29 20:31:06 -08:00
kma 33157853a7 Getting started on HHIR FP support: OpEq.
While comparisons aren't very dynamically frequent, they're an
easy place to get started on implementing FP support. Like tx64, I haven't
bothered to teach the register allocator anything about the xmm regs; I
just move operands from gprs to xmm0 and xmm1, and evaluate the expression.

I was worried about interfering with spilling to these same registers, but
we spill to mmx registers, which alias the legacy floating point stack.
The XMM regs are physically distinct.
2013-01-29 12:23:55 -08:00
bsimmers b4082a896c Add pseudo-counters for tx64 vs. hhir instructions
The new runtime option (Eval.EnableInstructionCounts)
combined with the new pseudo-counters instr_hhir and instr_tx64 will
let us track how many executed hhbc instructions were translated by
tx64 vs. hhir.
2013-01-29 12:23:55 -08:00
mwilliams 5242e45dc7 Add support for embedding the repo
Modify hphpc so that if format contains "exe" it uses objcopy
to put the generated repo into the hhvm binary, in a section
named "repo".

Write an sqlite vfs wrapper that allows us to open a range
of bytes in a file as a read-only sqlite database (using the
filename to encode the range: file:<start>:<length>).

Use libelf at startup to see if there is a repo section, and
if so enable the vfs wrapper, and add appropriate
repo-authoritative options to the command line to use the
repo section as the repo.
2013-01-29 12:23:46 -08:00
jdelong cf3f5a6c70 Some assertions for invalid registers
Sometimes we have PhysRegs that are InvalidReg and try to use
them anyway.  Right now, there's some cases where this ends up passing
reg::noreg to an emitC* function that treats that as a special
meaning, and you can emit machine code that didn't have the type of
memory operand you wanted.  Assert here because PhysReg stuff is
constexpr (cannot assert there).  Ideally it wouldn't implicitly
convert to Reg64 and this would all be impossible, but oh well.
2013-01-29 10:43:51 -08:00
jdelong 8335085928 Move jump simplifications to the Simplifier
It looks like these were implemented before simplifyCmp, so
it duplicated some of the abiltiy to simplify comparisons with certain
types of constant arguments.  This code can be simpler and in the
simplifier.
2013-01-29 10:43:51 -08:00
jdelong ff330e3d85 Minor tweak so genDefConst works with all ints
Right now it gets confused if you don't give an explicit
argument list on many ints, if they are 32 bit or unsigned or int64_t
vs int64, etc.
2013-01-29 10:43:51 -08:00
jdelong 55ea24d6e4 Move hphp/doc -> hphp/src/doc
Needed for FB internal restructure.
2013-01-29 10:43:28 -08:00
smith 9d18df997d Add a runtime switch to disable dead code elimination
This fixes a few problems when DCE is disabled, however some
tests still fail.  Fixed:
 * register allocator assigns registers to unused destination tmps
 * fixed LiveOutRegs calculation with unused results
 * removed assert from cgJmp_
 * support immediate constants in cgMov
2013-01-29 10:43:15 -08:00
mwilliams c8e148c12c Fix an assert on syntax errors
When using hphp to compile a repo, a syntax error in an input
file would cause an assertion to fail (DEBUG only).

When I tried to add a testcase, I found that we didnt quite support
this. We have a mode that ignores errors; but that also ignored crashes,
so I fixed test.mk to differentiate.

That revealed that hphp didnt pass through the result of invoking
hhvm, and that hhvm returned -1 for normal exits where the
php code had fataled.

When running the tests I found that it took over an hour to run
TestCodeRunRepoJit-Compilation, vs 4 minutes for the whole of
TestCodeRunRepoJit a couple of weeks ago (and my machines was
unusable for most of that hour). I dropped the parallelism
to "number of cores" from "number of cores * 2" and the time
dropped to a couple of seconds.
2013-01-28 11:44:10 -08:00
jdelong 9b413838bb Fix a bug for HHIR Print of Type::Bool, add some random byte things
Replace ands with movzbl.  Calling C++ for print_boolean was
wrong because it took an int64 but we don't know that the bool was
zero-extended yet.  Added two boolean instructions to the assembler
(with unit tests) that I didn't ever use.
2013-01-28 11:44:10 -08:00
mwilliams 861c1c99c5 Couple of small fixes 2013-01-28 11:44:10 -08:00
mwilliams 6d52d30da6 AllowedDirectories overwrites should append
VirtualHost.*.overwrites.AllowedDirectories would replace the
default AllowedDirectories list, rather than of adding to it,
while Tiers.*.overwrites.AllowedDirectories would append to the
default AllowedDirectories list. This caused confusion, and
errors.

This makes both cases append, and also sorts and uniquifies the
list to make checking it O(log N) rather than O(N).
2013-01-28 11:44:10 -08:00
mwilliams d7034097b9 Fix buffer overrun, and add a check
We wrote 49 chars to a 48 char buffer. Under gcc-4.7.1,
RELEASE build, this corrupted a variable in the caller, resulting
in a crash.
2013-01-28 11:44:09 -08:00
jdelong a24fd950f8 Rename jumps.cpp to jumpopts.cpp 2013-01-28 11:44:09 -08:00
kma 786b32d9c1 Fall back to interp from the IR.
Introduce a runtime option to allow falling back to the
interpreter, rather than to tx64. Once this is faster, we know we're
ready to ditch tx64.

Cleanups along the way:

  - Start macro-izing the runtime options. For tractability, I only did
    the Eval* runtime options, but the same pattern should work for other
    parts of the hdf namespace.

  - const SrcKey& -> SrcKey in a lot of places.

  - slightly iron out the handshaking between translate and
    translateTracelet.
2013-01-28 11:44:09 -08:00
alia 2b0b8c8c25 Cleaned up some load operations and added a label to LdClsCns.
Added a label to LdClsCns so that we generate better code for
it if guardStackType refines its type.

Cleaned up some of the load instructions: Removed the NR suffix from
LdMemNR, LdPropNR, and LdRefNR. Removed unused offset parameter from
LdMem. Improved docmentation of load instructions and described
rationale for having labels on some of them.

Renamed CheckUninit to CheckInit to make it consistent with CheckType
(i.e., branch to label if type is not init).
2013-01-28 11:44:09 -08:00
smith 4e1db91ff7 Check probe limit in HphpArray
Honor the MaxArrayChain runtime option by raising an error when
HphpArray probes get too long.  Since HphpArray uses open hashing
with quadratic probing, we use double the configured threshold,
which is arbitrary, but based on testing, to reduce false positives.
2013-01-28 11:44:09 -08:00
jdelong fcbf989675 Make the fixup map unit test use gunit
Even before libhphp_runtime is split up it seems like we
should at least have some kind of way to write some unit tests, when
appropriate.
2013-01-28 11:43:59 -08:00
Sara Golemon 7a59019a12 Allow double-conversion in third-party to build for ARMv8 64 2013-01-25 15:20:22 -08:00
Sara Golemon cfb30f7319 Update round() to match PHP 5.3.0 - Add mode parameter
Adds third parameter to round() function
for alternate rounding.
2013-01-25 09:32:45 -08:00
jdelong ae28626b39 Minor cleanup, mostly in codegen (macro removal) 2013-01-24 13:14:14 -08:00
mwilliams aee5129926 Fix order of command line options vs Tiers overwrites
Command line config options were applied after the Tiers
overwrites were applied - allowing the command line options
to take precedence over the Tiers overwrites. But they're applied
too late to affect which machines a tier overwrite applies to,
or to modify the values of Tiers.*.overwrites before they're
applied. So instead we apply them both before and after, allowing
you to set eg -vTier.devweb.machine=// to make your dev server
get the same settings as devweb, but still ensuring that command
line options take precedence over everything else.
2013-01-24 13:14:13 -08:00
jdelong cf5b8c0abf Fix a type error in CGetL2
It should be popping the top of the stack as a gen.
2013-01-24 13:14:13 -08:00
ptarjan b8dc84463b add isGenerator to ReflectionFunction 2013-01-24 13:14:13 -08:00
andrewparoski 179fd16266 Print out 'not supported' message when '--parse' option is used
The '--parse' option has never been supported for HHVM, and we silently
fail when this option is used. Let's at least give a more friendly 'not
supported' error message.
2013-01-24 12:50:26 -08:00
mwilliams fdbe3cb3b8 Fix Hdf::exists
While looking at a task I discovered that Hdf::exists(const char*)
was broken in some cases, because it created the node, and then
tested to see if it existed.

I rewrote it to lookup the node without creating it.
2013-01-24 12:50:26 -08:00
jdelong b73364129b Remove the SpillStack vs. SpillStackAllocAR distinction
Changes guard instructions to modify the stack by returning a
new StkPtr, so we don't have to load all guarded locations with
extendStack.  This means SpillStackAllocAR doesn't ever have to do
anything differently from SpillStack (it only differs in a case where
we are spilling locations above an act rec that we loaded only as a
side-effect of guarding).  After that, move the the responsibility of
logically popping the ActRec to the Call instruction (and account for
pushing ActRecs for NewObj in getStackValue).
2013-01-24 12:50:26 -08:00
jdelong 1ea405e13c Delay writing ActRecs to the stack until the next SpillStack
In the immediate term, this lets us consolidate some
adjustments to rbx, but the motivation here is to make it easier to
omit spilling ActRecs for inlined functions.  When we begin the
inlined function, we'll only have done a DefActRec in the FPush*,
instead of an AllocActRec, so if no SpillStack was needed before the
inlined function returns we can just pop it from m_evalStack.  If an
exit trace in the inlined code needs to spill, its SpillStack will
spill the ActRec.
2013-01-24 12:50:26 -08:00
jdelong 7824e7f894 Move jump-related optimizations out of dce
They seem logically unrelated to DCE, and apparently we may
want to do them after regalloc at some point (but this doesn't make
that change).
2013-01-24 12:50:26 -08:00
jdelong ad8d79e3f7 Punt on AllocSpill/FreeSpill for now
These aren't quite working right, so we're disabling for now.
2013-01-24 12:50:25 -08:00
mwilliams de10025e31 Fix some valgrind issues
While trying to debug a g++4.7.1 crash I came across
some valgrind warnings.

One issue was that AsyncFunc was trying to construct
an Exception, which tried to build a backtrace before
things were properly setup. Its also pretty inefficient
to generate a backtrace for every AsyncFunc which is
never used (if an exception is thrown, the backtrace
is overwritten from the thrown exception anyway).
This changes it to use an Exception* instead.
2013-01-24 12:50:25 -08:00
smith 70db8d4c31 Use range-for in more places, rename SlotInfo fields for clarity. 2013-01-24 12:50:25 -08:00
ottoni b70e90fbb7 Get rid of some "slow" exits, plus some cleanups
A slow exit requests the code to be executed without HHIR (currently
via Tx64, and possibly the interpreter).  These exits should be used
when a runtime condition determines that HHIR is currently incapable
of producing valid code for that tracelet.

Inspecting the code, I found out that a number of places were using
slow traces incorrectly, i.e. for cases where HHIR would produce a new
translation that correctly handles the runtime condition.  So convert
these over to be "normal" exits.

This diff also does some cleanups, including removing unused LdThisNc
instruction, removing label of LdLoc, and reworking genLdLoc.
2013-01-24 12:50:25 -08:00
jdelong ef14f84de0 Remove Rematerializable from LdClsMethodCache; remove unused function
If we actually try to rematerialize a LdClsMethodCache, right
now you'll get a crash because cgLdClsMethodCache assumes the label is
non-null, but rematerialization nulls out labels.  It seems to me that
we probably don't want to be in situations where rematerializing these
happens (since they usually should just be stored to an ActRec
location), so just remove the flag rather than making it support a
null label.
2013-01-24 12:50:25 -08:00
bsimmers f48fad8b86 Modify PHPOutput serialization to ensure doubles will parse as doubles
VarExport will output the double 1.0 as "1", but for
reflection we want the fact that it's a double to be preserved in the
output. Now the double 1.0 will be output as "1.0" in PHPOutput mode.
2013-01-24 12:50:25 -08:00
jdelong eb67555b06 Minor tweaks to DumpIR for usability with TRACE
If you want tx64 tracing at the same time as DumpIR, right
now the output interleaves in a bit of mess.  Send the dumps to the
trace facility if it's enabled.
2013-01-24 12:50:25 -08:00
alia 16d3406b1a Implemented IterInit[K] and IterNext[K] in HHIR.
Implemented IterInit[K] and IterNext[K] in HHIR. Added
support for the loading addresses as arguments to ArgDesc and
cgCallHelper.
2013-01-24 12:50:25 -08:00
bertrand 21dd7f2477 Stop parsing URIs at first hashmark
Makes HPHP end URI parsing at a hashmark, if encountered.
Clients shouldn't send them and it's a potential security issue.
2013-01-24 12:50:25 -08:00
ottoni d52ac930e6 Disable translation of CreateCont 2013-01-24 12:50:25 -08:00
jdelong 6eafa5a46c Short term fix for GuardType with dce'd dest
Trying to debug sandboxes and I hit this.  I think this fix
is actually correct, although it'd probably be better to teach the
register allocator to require that GuardType is the last use of its
source, and just always map the src value register as the destination.
2013-01-22 11:10:41 -08:00
smith 6df3c0e415 Introduce SSARange (using folly::Range) in HHIR code.
Slices and Ranges are a handy way to work with arrays and
sub-arrays, and work with C++11 foreach syntax.  Use it in
various places.
2013-01-22 11:10:40 -08:00
mwilliams eedd5ac3b9 Dont flush the targetcache within a request
rpc requests preserve state across requests, so we cant drop
the TargetCache just because the thread has been idle for a
few seconds. The result was that all classes, functions and
certain items of global state became "unloaded" while most
global state was preserved. The autoloader then did its best
to set things straight, but some things were beyond repair.
2013-01-22 11:10:40 -08:00
mwilliams ea27c85f26 Dont use a local StringData for invoke
If the StringData ever gets put into a String or Variant
it will cause the (stack) memory to be put on the GarbageList,
leading to crashes later. This was exacerbated by not incReffing
the StringData (so the String/Variant didnt even have to outlive
the StringData for this to be a problem).

We probably couldnt hit this case prior to function autoloading,
but now its easy. Making an rpc request to a non-existent function
hits it reliably.

It turns out that invoke is normally entered via the version that takes
a CStrRef, so this should actually be an improvement on the old code
(which threw away the incoming StringData and created a new one on the stack).
2013-01-22 11:10:40 -08:00
mwilliams 489fcf7e7d Always set the dumpable flag for the process 2013-01-22 11:10:40 -08:00
jdelong a0350a7b7c Start of a PreClass/Class comment 2013-01-22 11:10:40 -08:00
jdelong 19601670c5 Remove a comment in asm-x64.h 2013-01-22 11:10:40 -08:00
ptarjan d75ed2f269 add isClosure to ReflectionFunction 2013-01-22 11:10:39 -08:00
bsimmers 5afbfb052c Add basic TypedValue by value support to cgCallHelper
This expands ArgDesc and cgCallHelper to fully support
passing TypedValues by value to helper functions, and changes all
relevant helpers to take TypedValues by value, instead of taking value
and type as two separate arguments. I expect that we might need to
teach cgCallHelper how to emit >6 arguments at some point, but that's
not needed yet.
2013-01-18 11:44:14 -08:00
je@fb.com 1b3e72975c Modify hphp to batch units together when writing to a repo.
Modify hphp to batch units together when writing to a repo, in order to
reduce transaction commit overhead.  Do all writes on the main thread,
in order to avoid database lock contention.

Short-circuit FunctionScope::RecordFunctionInfo() unless in WholeProgram
mode.  This removes a major point of lock contention.
2013-01-18 11:44:14 -08:00
je@fb.com cd1893cce7 Reduce jobs multiplier under hhvm 2013-01-18 11:44:14 -08:00
aravind 3c081d5c22 Disentangle perf-pid.map and DwarfInfo generation
DwarfInfo takes up a lot of memory in production,
and is only needed if we want to see PHP symbols in core
files. Disentangle it from perf-pid.map generation, which is useful
for profiling.
2013-01-18 11:44:13 -08:00
kma d460d1df6f Forget about the stack slot builtins write to.
If you line up a tracelet *just* right, you can have a live
register for the stack slot that FCallBuiltin outputs. Since FCallBuiltin
works in-memory, this register will contain a stale value. This can
cause arbitrary badness; it was first sighted by Emir as a branch that
goes the wrong way in PHP.
2013-01-18 11:44:13 -08:00
bertrand 8cba073b5f Replace CT_ASSERT with static_assert
Since static_assert is supported now, we're replacing CT_ASSERT with it.
Added descriptions to each assertion as required by static_assert.
2013-01-18 11:44:13 -08:00
bertrand 7dd93ff347 Remove unused runtime options 2013-01-18 11:44:13 -08:00
smith 3ecd907bee A few more Marker cleanups
Remove stale friend decls, using no-op macro for Marker.
2013-01-18 11:44:12 -08:00
Sara Golemon 791fb8602c Pass options and full context through to wrappers 2013-01-18 11:44:12 -08:00
Sara Golemon 9d74bb85c6 Add lcfirst() function 2013-01-18 11:44:12 -08:00
jdelong 84d63ff2d0 Document the guard instructions 2013-01-18 10:50:02 -08:00
mwilliams 13c00c80c1 Dont create VarEnv's for functions that dont expect them
Inside Unit::mergeImpl, a ReqDoc would create a new local
VarEnv if the current function didnt already have one. That was
wrong because the unit must have been required via either ReqSrc,
ReqMod or fb_autoload_map. In addition, it meant that we were
attaching a VarEnv to a function that might not be marked
AttrMayUseVV - with the result that we would leak the varenv.
2013-01-18 10:50:02 -08:00
Sara Golemon c9a19a6847 Guard saving persistent PDO connections which are invalid.
Handle a couple edge cases where an active PDO handle dies
before request shutdown can put it back into the persistent
connection pool.
2013-01-18 10:50:01 -08:00
smith 4d5501e161 Add new MarkerInstruction subclass for HHIR Marker
The Marker opcode's fields did not overlap with DefLabel,
nor do we ever branch to a Marker; so give it a separate
subclass and clean up the code.
2013-01-18 10:50:01 -08:00
mwilliams cee24e62ae Fix data flow when a try block returns
We approximate the dataflow for try/catch by adding
edges from the start and end of the try block to the start
of every catch. But a top level return in the try block will
kill the edge from the end.

This diff explicitly adds edges from a return in a try block
to every catch. This is sub-optimal, and still misses a
hopefully unlikely case; I'll follow up with a bigger fix to
control flow.
2013-01-18 10:50:01 -08:00
jdelong 383c4718c3 Remove IRFactory argument from InstructionBuilder
This was an artifact from a mid-refactor stage when
ExtendedInstruction wasn't gone yet (it always needed an IRFactory to
be created).
2013-01-18 10:50:01 -08:00
mwilliams d1314efcc2 Reduce allocations for ImmutableMap and VectorData
ImmutableMap was doing 3 mallocs (one for the ImmutableMap
itself, one for the hash table, and one for the buckets). In
addition, it was pointlessly rounding up the number of
buckets to the next power of two. Reduce it to one malloc,
and only allocate the required number of buckets.

Similarly SharedVariant::VectorData was doing two mallocs. Reduce
to 1 by inlining the data.
2013-01-18 10:50:01 -08:00
Owen Yamauchi e9db5975a5 Remove unsed variable 2013-01-17 10:43:51 -08:00
Owen Yamauchi fd4f3cacf6 Do LdFunc/LdFixedFunc before AllocActRec
They can reenter. Make sure the reentry happens before the logical write to the
stack, or else we'll reenter with an incorrect vmsp.
2013-01-17 10:43:51 -08:00
bsimmers 5bf250a73b Restore previous frame if Class::newClass throws
Unit::defClass sometimes needs to set up a top-level ActRec
before calling Class::newClass, because newClass can
throw. Previously, the old ActRec would remain in place and the
VMExecutionContext would eventually get confused and try to execute
memory that didn't have valid bytecode in it.
2013-01-17 10:43:51 -08:00
smith d3e0eb88d0 s/ASSERT/assert 2013-01-17 10:43:51 -08:00
jdelong aefaa80b20 Finish removal of IRInstruction::m_type, and remove ExtendedInstruction
Finishes moving value types from IRInstruction into SSATmp
(changing the other m_type uses to use m_typeParam), and allows any
instruction to have any number of srcs.  Also consolidates creation
overloads for out different IRInstruction shapes into one helper, so
we need fewer constructors/wrappers.  Adds an outputType() routine
that gives the return type of an instruction given its src types and
type parameter.  (We may want to change outputType() and
assertOperandTypes() to be table-driven---I was initially expecting
more instructions would have logic there, but they are all really
simple.)
2013-01-17 10:43:50 -08:00
Owen Yamauchi 2357c864b2 Fix and re-enable CreateCont translation
I disabled this back when I was messing with continuations. It's really not
complicated at all.
2013-01-17 10:43:50 -08:00
Owen Yamauchi 2722e3f63e IR translation for ContEnter, tweak translation for ContExit
ContEnter is pretty straightforward after my change to use call/ret in tx64. The
change to ContExit is to generate slightly simpler machine code (now that I know
what DefSP actually does).
2013-01-17 10:43:50 -08:00
kma 6d2f5c1419 Reduce irtranslator's dependency footprint.
It looks like irtranslator copied translator-x64's headers. Its
concerns are a lot more cleanly separated, so let's exploit that. The
vestigial "log.{cpp,h}" were also sitting around taking up precious git
repo space.
2013-01-17 10:43:50 -08:00
Owen Yamauchi e3f5161e52 Allow IR dumping to use something other than std::cout
traceInstruction was hardcoded to use stdout, via printf. Abstract that out.
Everything's still going to stdout, but we can now change that to any other
std::ostream if we want.
2013-01-17 10:43:50 -08:00
jdelong 83a8937c44 Change HhbcTranslator to own its TraceBuilder
It's looking like having a stack of TraceBuilders in
HhbcTranslator might be nice for stuff I'm trying with inlining, but
rather than do that intertwined with those changes I separated it out.
Most of the lines changed here are m_tb becoming a pointer instead of
a reference.  Also removed a little bit of cut&pasted things and
unneeded includes in irtranslator.cpp while waiting for things to
compile.
2013-01-17 10:43:50 -08:00
jdelong ea2212d53d Some fixes for comparison ops with objects
When comparing objects with strings, we can re-enter, and may
throw or run arbitrary user code.  We shouldn't CSE or DCE any of
these cases, and we need to pessimize memelim and do a spillStack for
the exception case.
2013-01-17 10:43:50 -08:00
smith 391e25fe99 Remove LabelInstruction::m_trace
This field is only for the DefLabel instruction, and is always
the same as m_parent, so we don't appear to need it.
2013-01-17 10:43:50 -08:00
mpal 17f6690d3b hhir, patch cgJmpZeroHelper when operands are constant
Problem occurs since there isn't a late run of simplification
to identify this, change it to a direct jump, and eliminate
any following IR.

This is a patch to materialize the condition in the flags reg
and then jcc.  After the simplifier's extra pass is implemented,
this if stanza can be removed or become an assert(false);
2013-01-17 10:43:50 -08:00
jdelong 3a16d51c45 Fix an issue with unused LdClsCns instructions
If you LdClsCns and don't use the output, it doesn't get
assigned a register which breaks the check for uninit.  To solve this,
split the uninit check into a separate, Essential instruction that
consumes the output of the LdClsCns.  (Presumably we could leave out
this instruction in cases where we know the class is loaded, and the
LdClsCns could rightfully be optimized out in that case.)
2013-01-15 16:32:56 -08:00
kma 7ae4de0dc4 Handle redeclared functions less sadly.
When redeclaring functions, there was some line noise from an
assertion failure in the emitter and a crash in debug builds. Approximate
our behavior for other kinds of redeclaration. According to Zend, this
really is an include-time failure.
2013-01-15 16:32:44 -08:00
Sara Golemon ecb6ca491f Add Zend style Stream Wrapper abstraction layer
Register supported URI schemes mapping to internal
handlers for File::open().  If no scheme is specifid,
the file:// wrapper is used by default.

This diff also adds the file:// and zlib: wrappers which were
previously only invoked via default and compress.zlib://
respectively.
2013-01-15 15:35:27 -08:00
Sara Golemon 4610519ce8 Skip building test if HPHP_NOTEST=1 is set in the evironment 2013-01-15 13:51:56 -08:00
ottoni ce9f9c2949 Add support for virtual helper calls, and use it for release methods
This avoids going through a wrapper when calling release methods, just
like Tx64 currently does.
2013-01-15 11:38:47 -08:00
smith 5f98fa8a7b Add SSATmp::m_type
Adds a Type field to SSATmp, so we can store the type of a variable
separate from the type hint attached to an instruction, *and* so that
we can have instructions with more than one destination, each with
a distinct type.

For the time being, this field just copies IRInstruction::m_type and
tries to keep them both up-to-date.  Future diffs need to decouple the
use cases for the two fields.
2013-01-15 11:38:46 -08:00
jdelong b9b679bbfa Remove TypeInstruction and some associated clean up
Gets rid of TypeInstruction, instead putting a new (possibly
Type::None) Type in the base class for the IsType instructions.  This
should go away after things are changed so SSATmps have types instead
of instructions having types (needed for multiple-dsts).  I think it'd
also be nice to remove the ExtendedInstruction vs IRInstruction
distinction (allow any instruction to have any number of srcs (and
eventually dests)); this is a small step toward that.
2013-01-15 11:38:46 -08:00
je@fb.com 1a8adf5b8f Remove repo contention for TestCodeRun*.
Modify the test_code_run program to specify a distinct repo for every
test, so that no repo contention occurs.

Remove the default limit of 20 parallel tests, and for hhvm increase the
default to four times the number of CPUs to improve throughput.  hphp
uses a lot of memory when building, so leave the hphp default at the
number of CPUs.
2013-01-15 11:19:16 -08:00
je@fb.com 733d4e3d6a Support WholeProgram=false for hhbc compilation.
If -v WholeProgram=false and --optimize-level=0 for hhbc compilation,
use the same file-level optimization configuration as is used by hhvm.

Update repo documentation.
2013-01-15 11:19:16 -08:00
jdelong cc6e2635cf Add FTRACE macro to util/trace.h
Trace with folly::format.
2013-01-15 11:19:16 -08:00
mwilliams b02b985176 Fix a bug in apc serialization
ArrayData::hasInternalReference had an incorrect
short-circuit when ds was false; if it found a
Serializable object, it immediately returned false,
even though later events might have forced it to
return true.

The result is that arrays with internal references
that contain Serializable objects may not deserialize
correctly (the internal references can get split, for
example).
2013-01-15 11:19:16 -08:00
jdelong 8316b3041d Comment out assertion in codegen.cpp 2013-01-15 11:19:15 -08:00
smith 49bcbee9e9 Flesh out more IR specification
And remove some more dead code, while I'm at it.
2013-01-15 11:19:15 -08:00
Sara Golemon 0821fd8172 Fix folly build w/ boost >= 1.48 2013-01-14 18:16:16 -08:00
jdelong 3bbe8740ab Remove PropCache 2013-01-14 11:00:43 -08:00
jdelong 30a7a6e310 Use folly/Likely.h to get LIKELY/UNLIKELY macros
Various headers from folly use the versions of these from
folly/Likely.h, so we might as well also so we can include those
headers.
2013-01-14 11:00:43 -08:00
jdelong 9a689ace79 Fix a bug in Simplifier::simplifyCmp
When there was a non-const null and a const bool, the
simplifier would continuously flip the arguments and recurse
infinitely.  For some reason there was a check for const bools before
the check for null, although the optimizations we can do knowing the
rhs is null seem just as good as the optimizations knowing the rhs is
a const bool.  (In fact after a couple more recursive calls I think it
ends up there.)
2013-01-14 11:00:43 -08:00
smith 509cf048e6 Remove dead code in HHIR 2013-01-14 11:00:43 -08:00
mwilliams 5c34c18826 need to pre-initialize liboniguruma
liboniguruma claims to initialize itself correctly, but
its init routing isnt thread safe (despite trying).

onig_init looks like:

  if (inited) return;
  pthread_mutex_init(...);
  pthread_mutex_lock(...);
  inited = true;
  // perform initialization
  pthread_mutex_unlock(...);

So
 - if a second thread comes along after inited is set
   to true, but before the initialization is complete, it will
   read from tables that are being initialized.
 - if a second thread comes along after the first one has called
   pthread_mutex_init, but before it has set inited, it will
   try to call pthread_mutex_init again, which is undefined
   behavior

We can avoid all the issues by calling onig_init() at startup time.
2013-01-14 11:00:42 -08:00
mwilliams 4623ef48d2 Need locking around addLineEntries
addLineEntries modifies a std::vector which another thread
could be reading. The reader has a lock, but the caller of
addLineEntries was explicitly dropping the lock right before
calling it. Since the lock is needed again, just hold it to
the end of the function.
2013-01-14 11:00:42 -08:00
smith a42da6531c AddNewElemC Array API
AddNewElemC is a new helper method for HphpArray that directly
implements the NewElemC opcode and avoids the need for a wrapper
when invoked from JIT compiled code.

The value is passed by value with no ref counting; semantically
the same as CVarRef or TypedValue*, but without the added indirection.
Its also worth noting that its semanticly the same as using VarNR for
the parameter type, but since we rely on simple structs being passed
in registers on x64, I wanted to avoid VarNR with its constructors, etc.
2013-01-14 11:00:42 -08:00
Sara Golemon 10fd276e90 Support php://fd/%d type streams 2013-01-14 11:00:42 -08:00
smith 640cf62584 Change AttachString to copy
This modifies AttachString mode for string creation to immediately
copy the string to smart-malloc'd memory and free the input block.

Since we always copy malloc'd strings to smart-malloc'd memory,
and we require strings created with CopyMalloc to run their destructors,
the only kind of sweepable string is the IsShared (SharedVariant) kind;
this slightly simplifies sweeping strings.  (fewer need sweeping, at
least).
2013-01-11 09:40:08 -08:00
jdelong 52fca86c95 Print sources for store instructions as sources
I found it a bit confusing that we draw them as dests.
2013-01-11 09:40:08 -08:00
kma 73210dfbee Fix a reentrancy buglet in arr_to_bool.
My hacking around with non-deterministic finalization found
this segv lurking in our current build; if you destroy an array, that
destroys an object, that has a destructor, we didn't have a reentry
record for the call to arr_to_bool.
2013-01-11 09:40:08 -08:00
mwilliams b592bc22a5 Fix stack parity for contEnterHelperThunk
It was leaving the stack at a multiple of 8, which then
crashed in DEBUG builds due to misaligned sse moves.
2013-01-11 09:40:08 -08:00
mwilliams bd24286cc6 Fixes for gcc-4.7.1
This fixes some bugs in our code that were exposed by
gcc-4.7.1 and fixes/disables some warnings.

In addition, it works around a bug in gcc-4.7.1
(apparently fixed in 4.7.2) that ends a temprary's
lifetime too soon.
2013-01-10 14:08:17 -08:00
jdelong 76037f6b54 Move IRFactory stuff out of ir.{h,cpp} into its own file
Seems like a logical thing to split out...
2013-01-10 14:08:17 -08:00
jdelong e45459fcb1 Remove some dead AllocActRec code in codegen.cpp
We only use the 6-argument version of AllocActRec now.
2013-01-10 14:08:16 -08:00
jdelong 59c69b31cf allocRegsForTrace doesn't actually need a TraceBuilder
Remove unused parameter.
2013-01-10 14:08:16 -08:00
jdelong cc042b658d A few minor cleanup tweaks, mostly Translator::analyze related
Some minor comment tweaks to make them closer to truth; add
some missing header dependencies; return unique_ptr<Tracelet> and take
SrcKey by value; move stackFrameOffset to not be a member variable;
and remove some uses of Transl::curFunc from the IR.
2013-01-10 14:08:16 -08:00
bsimmers 2443ed40ec Don't populate 'args' array in backtrace frames in RepoAuthoritative mode
hphp has been doing this for ages and a number of internal
tools rely on this behavior. hhvm is now consistent with hphp.
2013-01-10 14:08:16 -08:00
aravind 56f512a11c DebugInfo cleanup 2013-01-10 14:08:16 -08:00
smith 3bee753a41 Factor out tvRefcountedDecRef/IncRef where possible.
Use helpers where we can.  Introduced new helpers to aid fast-path/cold-path code that checks to see if a destructor will be called before doing a decref.
2013-01-10 14:08:16 -08:00
aravind a0ab3cceff Add class name to symbols in perf-.pid.map 2013-01-10 14:08:05 -08:00
bsimmers 695aef28ae Fix TestCodeRun-Hint
hphpc and hhvm have different code for generating the default
value text used in reflection. This updates hphpc to be consistent
with hhvm.
2013-01-10 12:52:12 -08:00
jdelong 74ff3ca27e Make HHIR returns a little more like tx64 returns
Adds and modifies few IR instructions so that the generic
return case can use the tx64 freeLocalsHelpers.
2013-01-10 12:52:12 -08:00
Sara Golemon b7907b4bf3 Update system generated files and fix generator scripts 2013-01-10 12:52:12 -08:00
jdelong 405920c0a9 Remove need for cgFoo functions to return their start address
Remove some boilerplate.  Also most functions (top-level IR
instructions) seem to be intended to have the semantics that emitting
no code returns null, while many helpers just returned the frontier.
This lead to some cases (e.g. cgLdStack, cgStMem, etc) having
different semantics from other instructions.
2013-01-10 12:52:12 -08:00
jdelong 90988d199f Tweaks to IR trace printing
Indents the IR and assembler output more than the respective
previous representations (seems easier to understand than outdenting
things relative to the HHBC).  Also fixes support for ostreams other
than std::cout and get rid of the php-source line numbers.
2013-01-10 12:52:11 -08:00
Sara Golemon 76a789b290 Add folly to third_party 2013-01-10 12:52:03 -08:00
Sara Golemon 56c9e3e6cb Add libdouble-conversion to third_party 2013-01-09 00:19:08 -08:00
jdelong 62c7a7fb14 Make SIMPLIFY_CMP not a macro
Made it easier to debug/edit this function.
2013-01-08 17:51:22 -08:00
Thomas Jarosch bbd468f22e Use delete (not free) for deallocating new'd memory.
A few random places where blocks are being allocated
with new, but deallocated with free.
2013-01-08 17:51:22 -08:00
smith 975a0d4a43 Remove a bunch of unnecessary double-semicolons
I saw these in ir.h and found a few more with git grep.
2013-01-08 17:51:22 -08:00
aravind d411f8ab86 Don't emit FCallBuiltin for redefinable builtins
We were emitting FCallBuiltin at emit time for "idx", but were
resolving "idx" to the user-defined function at runtime.
2013-01-08 17:51:22 -08:00
bsimmers bf6517c28f Fix expected string for TestHint
A previous diff made a couple changes to the text returned from
ReflectionFunction::getDefaultValueText() (it now returns
double-quoted strings and uppercase NULL constants). I forgot to
update TestHint which tests this.
2013-01-08 17:51:21 -08:00
bsimmers 72c886ce80 Fix default value text for ReflectionFunction
The escaping used by outputPHP produces valid PHP, but it is
sometimes a string concatenation expression which can't be directly
substituted in as the default value of a function. This diff adds a
new mode to VariableSerializer that will always output a single string
literal for string values.
2013-01-08 17:51:21 -08:00
Sara Golemon 5fcd4b90ff Hide unused result warnings. 2013-01-07 18:53:40 -08:00
Sara Golemon 6195dd37ac Silence type conversion by using the correct initializer 2013-01-07 13:39:26 -08:00
mwilliams ce54c5dd2f Fix leaks with iterators and exceptions
Lots of edge cases. All sorts of order of evaluation issues,
a number of leaks, and at least one over-eager free.
2013-01-07 10:22:34 -08:00
jdelong 67bea594ff Don't include hhbctranslator.h in translator-x64.h
This means less .cpp files to rebuild when changing IR
headers.  (Translator-x64.h is included in a lot of places.)
2013-01-05 13:11:18 -08:00
jdelong 64d2c8fcc9 Change spl_autoload not to use get_globals in hhvm
The LVariableTable is ignored by invoke_file in hhvm.
(There's an assert that it is null in our hhvm invoke stub now, but it
shouldn't be causing any issue in release.)
2013-01-05 13:11:18 -08:00
jdelong f9a237aac0 Fix tab completion in hphpd
Change to get the list of globals from the global VarEnv in hhvm.
2013-01-05 13:11:18 -08:00
bsimmers 179b91b13f Fix stacktrace file generation
During bt_hander's move out of src/util, the default value of
'/var/tmp/cores' for CoreDumpReportDirectory got lost. This diff
restores it.
2013-01-05 13:11:18 -08:00
jdelong bf49edb2c9 Change most of our lowercase asserts to a new always_assert 2013-01-05 13:11:06 -08:00
jdelong 261ea4169f Rename assert.h to assertions.h
Earlier when trying to make libutil compile separately via
rules.mk I ran into issues where cassert was including our header
instead of the system assert.h.  Might as well fix it: probably it's a
bad idea to name our own headers after stdlib headers.
2013-01-05 13:11:06 -08:00
mwilliams 58611bf7cf Add support for lto builds
Sets up a new lto build option controlled by USE_LTO=1. It gets its own
OUTDIR_BY_TYPE directory.
2013-01-05 13:11:06 -08:00
amenghra 410a181ee3 Add support for generic-ish arrays.
We want to let people write code that looks like this:

function foo(array<int> $x) { ... }

or

function foo(array<string, string> $y) { ... }

There is of course no guarantee that $x contains only ints, or that $y contains string=>string. This is
no different from containers like Vectors, and the guarantees will come from the type checker.

The parser will let you do crazy things like foo(array<Foo, string> $x). This is somewthing we'll
catch in the type checker.
2013-01-05 13:11:06 -08:00
jdelong 02b0698013 Remove HaltVM exception for exiting nested VMs 2013-01-05 13:11:06 -08:00
smith 1bc109e9f5 Remove dead helper function: non_array_getm() in hphp_array.cpp
This became dead when some of the specialized array helpers were
removed.
2013-01-05 13:11:05 -08:00
mwilliams efbfab3590 Fix crash in curl_exec when exceptions are thrown
libcurl isnt exception safe. In a few places it saves a heap
pointer, replaces it with a pointer to a local, calls something
involving user callbacks, and then restores the original heap
pointer. If an exception is thrown, the original value doesnt get
restored, and when the curl handle is freed, it attempts to
free a pointer into the stack.

So we catch exceptions around the callbacks, return normally,
and then raise the exception before returning from the original
call.
2013-01-05 12:42:49 -08:00
jdelong 09eec0a067 Remove some .txt files left over from early IR development 2013-01-05 12:42:48 -08:00
jdelong b1dbdb9e46 Fix fscanf to only read one line at a time
Zend behaves this way.
2013-01-05 12:42:48 -08:00
je@fb.com 4be17fc520 Remove an obsolete assertion.
Remove an obsolete StaticString initialization assertion related to
integer string constants.  Integer string constants are now allocated as
StringData rather than StaticString, so they have no impact on
StaticString.
2013-01-05 12:42:48 -08:00
je@fb.com b0c2cac837 Merge integer strings into general static string pool.
Replace the precomputed integer strings with an array of pointers to
static strings that are allocated via the generic
StringData::GetStaticString() mechanism.  Reduce the range of
precomputed integer strings from [-128..65535] to [-128..3969].  Lazily
populate the pointer array unless running in server mode.
2013-01-05 12:42:48 -08:00
jdelong f7e373ce8e Fix opt build
In a certain configuration assert(false) isn't enough to
avoid -Wreturn-type in release builds.  (I think because we're not
really defining NDEBUG in release for the old Makefiles.)
2013-01-05 12:42:48 -08:00
Jason Evans ae98235e0d Remove icu_get_checks().
Remove icu_get_checks(), and convert the related thread-locals from
NO_CHECK to standard checking implementations.  This reduces startup
overhead for command line hhvm.
2013-01-05 12:42:48 -08:00
je@fb.com c5fc7f347f Lazily initialize kMaster (used by icu_tokenize()).
Lazily initialize kMaster, which is used internally by icu_tokenize(),
in order to speed up VM initialization in script mode.
2013-01-05 12:42:48 -08:00
jdelong ed93c8f074 Remove xconstants.php-related stuff from ext_hhvm 2013-01-05 12:42:47 -08:00
jdelong 670d128b5f Refactor to support internal compiling modes 2013-01-05 12:42:43 -08:00
jdelong 538b82725b Convert opcode flags table to use named identifiers 2013-01-05 11:35:54 -08:00
jdelong 45f93b78ce Fix a bug in LinearScan::computeLiveOutRegs
When looping over the indexes for assigned regs for a SSATmp,
the index wasn't being passed to the getReg (previously
getAssignedLoc) function.
2013-01-05 11:35:54 -08:00
Owen Yamauchi 0e281796cb Get rid of DefSP's sources
It doesn't need sources now. It's just a hint to the register allocator to give
you an SSATmp that's always assigned to rbx.
2013-01-05 11:35:54 -08:00
ottoni b8a8108cb6 Kill duplicate assignment to rStashedAR in FCall
cgCall uses emitBindCall, which sets rStashedAR already.
So don't do this in cgCall too.
2013-01-05 11:35:54 -08:00
mathieubaudet cbe33ecc3b Make strlen behave as zend53 on arrays and objects
- Changed input & return types of f_strlen() to be CVarRef & Variant instead of CStrRef & int64.
  * strlen($array) now prints a warning and returns null.
  * strlen($obj) checks if $obj->__toString exists, if yes uses it, otherwise prints a warning and returns null.
- Updated x_strlen(), fni_strlen(), iopStrlen(), emitStrlen(), analyzeStrlen(), translateStrlen() accordingly
- Updated files idl/string.idl, system/string.inc and fbmysqllexer.cpp
- Added test cases
2013-01-05 11:19:51 -08:00
aravind b25354bec2 hex2bin should return false on failure
So says the doc: http://php.net/manual/en/function.hex2bin.php.
Currently, it fatals on malformed input.

Also add a new field for return type hints in idl files. This
can be used for type prediction for builtin functions that
return Variant.
2013-01-05 10:33:06 -08:00
mwilliams 48eaa25789 Revert "Banish std::string and std::map from ext_obc, take 2"
This reverts commit 155f3b2
2013-01-05 10:12:29 -08:00
aravind 9f5c8e2f1b Include JitEnableRenameFunction in unit hash
Since we enable FCallBuiltin based on whether or not
JitEnableRenameFunction is enabled. We don't want a repo
built with JitEnableRenameFunction=false to be run with
JitEnableRenameFunction=true.
2013-01-05 10:12:21 -08:00
jdelong 7e81796a80 Add a few instructions to ir.specification 2013-01-05 10:12:21 -08:00
mwilliams 80793c7e7d ReflectionMethod should autoload the class
It didnt. Also add a test for ReflectionClass (which already did)
2013-01-05 10:12:21 -08:00
mwilliams 5176f4f367 constant() should autoload
A test breaks without this. Also this adds an
hhvm specific implementation, to avoid going through
the pointless and expensive ClassInfo mechanism. It
also cleans up the implementation of defined.
2013-01-05 10:12:21 -08:00
Owen Yamauchi 66ea8c3309 Use call/ret, real prologues for ContEnter, ContExit (tx64)
Before, generator bodies were entered without prologues, meaning they didn't get
stack-size checks or surprise flag checks. This fixes that.

This lets us use an entry path that's much more similar to regular function
entry, including the use of the call/ret instructions, which should offset some
of the perf regression caused by the extra checking on entry.
2013-01-05 10:12:21 -08:00
jdelong 880d2590ec Remove a few preprocessor defines from dce.h 2013-01-05 10:12:21 -08:00
bsimmers 86b07934d1 Clean up regalloc/codegen for native calls with many args
These two patterns were frequently repeated and I'm going to
add even more instructions like this with the vector translator.
2013-01-05 10:10:53 -08:00
mwilliams 952bc15d64 get_class_constants should autoload 2013-01-05 10:10:53 -08:00
mwilliams 0d21c3477e Add optional autoload params to function_exists and defined
Now we have autoload for functions/constants, we
need to be able to test for function/constant existence
without triggering autoload.
2013-01-05 09:52:08 -08:00
andrewparoski 262526116d Collection literals 2013-01-05 09:16:32 -08:00
smith eba0b4dfb0 IR Specification
Rough out a first outline for the HHIR specification
2013-01-05 09:14:12 -08:00
jdelong 3333e83dfa Remove hhvm.php
Unneeded after 3279ac37
2013-01-05 09:14:12 -08:00
Sara Golemon cfb712e2b2 libxml2 2.9.0+ compat fix; xmlBuf changed to anonymous struct
Define wrappers for accessing size/contents on older versions
of libxml2 which match the function protos in 2.9.0 and later.

Thanks to github/nareshv for finding the issue and providing a fix.
2012-12-17 22:56:27 -08:00
ide 792b6c3232 Add a timeout to pagelet_server_task_result + fix return code
The PHP master that calls into pagelet server currently needs to wait
indefinitely on the worker. This adds an optional timeout parameter so that the
PHP master can timeout after e.g. 10 seconds and log a descriptive message
rather than dieing with the generic message of "the request timed out after 30
seconds".

There was also a bug with the return code for partial flushed responses.
Sometimes the PHP master would receive a bogus return status like 65353. I
traced this down to the fact that the return code was never set for partial
responses, so it would be the initial value of `int rcode` on the stack.
2012-12-17 22:40:37 -08:00
jdelong 3279ac37dc Make hhvm not a hphpc-compiled script
Separates hhvm from hphpc.  (This will mean we don't have to
compile hphpc when iterating on VM changes, and will help for eventual
hphpc-deprecation.)  Details:

   - Stubs for hphpc-externals symbols that can't yet be removed.

   - src/system now includes g_system_class_map, which is essentially
     what the hhvm class map contained (only system stuff, plus things
     from constants.php).

   - VM::ProcessInit was the only part of the runtime that depended on
     libext_hhvm---breaks that dependency using a function pointer for
     now so you can link hphp_runtime without linking ext_hhvm.

   - Remove dlsym usage to access compiler symbols, using function
     pointers for now too.
2012-12-17 21:28:29 -08:00
Sara Golemon 07d6be0b63 Refactor idl.php and remove some unused module features
Crutch is long dead.
idl/base.php hasn't supported DeclaredDynamic in some time.
2012-12-17 16:27:47 -08:00
ottoni a474a676f0 Make separate IR instructions for guard type checks
LdLoc and LdStack, when provided a label, also do the type check, and
that's how guards were being implemented.  Although that has the nice
effect of hoisting the loads early in the trace, it's bad because the
loads effectively end up as part of the guards and they execute
redundantly when guards fail.

This diff splits the checks into their own instructions, but also
loads all the dependencies right after the guards to preserve the
hoisting effect.
2012-12-17 16:23:55 -08:00
mpal f9f407dd51 IR, stat counters for IR code
Report dynamic counts for execution of IR translations
2012-12-17 15:55:57 -08:00
ottoni 7def483efa Add support for relaxed guards in HHIR 2012-12-17 15:55:57 -08:00
ottoni 47c9c5c0c2 Pass to the IR statically inferred types for tracelet-produced values
Values produced by the tracelet which had their values inferred by
static analysis were not being passed to the IR.  This was not only
bad for performance, but it was only causing correctness issues (see
new test, which used to fail in repo-authoritative mode).
2012-12-17 15:55:57 -08:00
aravind e6c0decf72 class_implements should use autoload if specified 2012-12-17 15:55:57 -08:00
mwilliams e241655b7e Add fb_autoload_map
fb_autoload_map($map, $root) specifies a mapping
from classes, functions and constants to the files
that define them. The map has the form:

  array('class'    => array('cls' => 'cls_file.php', ...),
        'function' => array('fun' => 'fun_file.php', ...),
        'constant' => array('con' => 'con_file.php', ...),
        'failure' => callable);

If $root is non empty, it is prepended to every filename
(so will typically need to end with '/').

If the 'failure' element exists, it will be called if the
lookup in the map fails, or the file cant be included. It
takes a kind ('class', 'function' or 'constant') and the
name of the entity we're trying to autoload.

You can supply the autoload map to hphpc at compile time.
Currently, this is just used to augment hphpc's parseOnDemand
feature. It will use the map it to find more files to add to
the build based on class/function and constant names used.
This becomes necessary when all the requires are removed.
2012-12-17 15:02:51 -08:00
ottoni 0dbfc50b14 Trace through jumps that don't break tracelets
This ability was added to Tx64, but not to the IR.
It was causing the IR to end a trace prematurely.
2012-12-17 14:38:36 -08:00
aravind a153b70bce Don't free VM stack for RCPRequestHandler
For RPCRequestHandler threads, the ExecutionContext can stay alive
across requests, and hold references to the VM stack. Make
sure we don't free the stack from under the ExecutionContext.
2012-12-17 14:38:36 -08:00
mwilliams 1bab520cf0 Fix order of evaluation for locals in ArrayPairExpression
$a = 'foo';
$a = array($a => $x[$a = 'bar']);

should be equivalent to

$a = array('bar' => $x['bar']);

but hhvm was treating it as

$a = array('foo' => $x['bar']);

In production mode, some code transformations resulted in code similar to
the above example, which hhvm then mis-interpreted.
2012-12-17 14:38:36 -08:00
andrewparoski 380905ff33 Add another test for optional types 2012-12-17 14:38:31 -08:00
bsimmers f6aa8f8e7f Kill CGetM_GE 2012-12-17 14:38:31 -08:00
bsimmers 5ec7d4a765 Remove a couple big macros from translator-x64-vector.cpp
Equivalent functionality is achieved with tables of member
function pointers. This should make debugging much nicer.
2012-12-17 14:38:31 -08:00
ottoni d912d357a3 Call a helper for decref'ing popped stack values (PopR/V/C)
Call a generic decref helper for PopR/V/C. Added an additional
helper entry point for the case where we are decref'ing TOS, which happens
for PopR.
2012-12-17 14:38:30 -08:00
njormrod 4a60060f53 Set parent when inserting instruction into a trace
ir.h contained an outdated and unused declaration for
eleminateDeadCode. It has been removed.
opt.cpp has a bug whereby an instruction is inserted into a trace, but
the backedge (IRInstruction's m_parent) is not being correctly set to
the trace. This has been fixed.
2012-12-17 14:38:30 -08:00
Sara Golemon df67b5b83c Add UConverter to intl extension to match Zend
HPHP implementation of http://wiki.php.net/rfc/uconverter
2012-12-17 14:20:22 -08:00
andrewparoski 0216d0f7a1 Parser/lexer refactorage
This diff cleans up some issues in the lexer and parser with XHP tags
and other stuff.
2012-12-17 14:20:21 -08:00
jdelong d0a388b804 Remove unused facebook-specific code_error.inc or dependency.inc 2012-12-17 14:20:13 -08:00
jdelong 2ab35dc2fc Add licenses to a few files in src/util/tests 2012-12-17 12:51:28 -08:00
aravind f62652f631 Emit default values for FCallBuiltin
Add support for default values in FCallBuiltin.
2012-12-17 12:12:40 -08:00
aravind b1e928d8f1 FCallBuiltin for reference return types
Add support for builtins with return by reference.
2012-12-17 12:12:40 -08:00
Sara Golemon 1882a07c6c Clean up uses of printf without arguments.
Gets rid of a lot of warnings in the cmake build,
and allows us to set -Werror=format-security to catch
potentially broken calls.  Mostly codemod changes.
2012-12-17 11:52:53 -08:00
alia 0b2fc2224c Inlined calls to native builtins in the IR.
Inlined calls to native builtins in the IR.
2012-12-17 11:49:54 -08:00
ottoni 46aea6b5ce Move prologue redispatch code to 'a'
This code is hot, so put it in 'a' instead of 'astubs'.
2012-12-13 11:07:04 -08:00
bsimmers 9bcfb74295 Enable the AdminServer in config-server.hdf
Now that the admin server isn't enabled by default, we have
to turn it on in the config for TestServer. Also fixed up
test_server.cpp so individual tests can be run.
2012-12-13 11:07:04 -08:00
alia 9369661b76 Implemented call-ret support in IR.
Implemented suport for using the ret instruction in the IR.
2012-12-13 11:07:04 -08:00
alia 6ce5f67848 Changed CG_PUNT macro to print its argument.
Change the CG_PUNT macro in codegen.cpp so that it prints its argument
instead of its function. This allows us to get much more precise reasons
for why codegen punted.
2012-12-13 11:07:04 -08:00
ottoni f6bdf891c5 Add support to FPushObjMethodD for fast method lookup using known class
FPushObjMethodD implementation in HHIR was lacking a fast-path
implemented in TranslatorX64, namely when the base class is known.
2012-12-13 11:07:04 -08:00
alia 0910451ba4 Supported BareThis, IncStat, and SetOpL in the IR.
Added HHIR support for 3 bytecodes, IncStat, SetOpL, and BareThis.
These showed up among the top reasons the IR punts in a sandbox run.
2012-12-13 11:07:04 -08:00
smith 666198d28a NewTuple IR implementation
Add support for NewTuple.  The new_tuple helper function needs
the count and values passed to it on the stack, which is like
a call instruction but unlike most other IR instructions.
2012-12-13 11:07:04 -08:00
kma 823973b70e Turn on CGetM type prediction.
This diff enables the dormant CGetM type prediction code.
This affects tracelet geometry, sometimes making the trace guards explode.
To compensate, I appear to need two new heuristics:
1. give up on type prediction if we're in a polymorphic trace
2. don't inline returns in polymorphic traces.

These two heuristics use different tracelet depths to kick in;
an exhaustive search of an 8x8 matrix of parameters suggests (2,6)
is the right setting for now.
2012-12-13 11:07:04 -08:00
kma ef096348d7 Some refactoring to get rid of bogus KindOf*.
Let's try to keep internal bits out of DataType. This
was an easy first step; I'll go after the other TypeCheck ones in
a follow-on diff.
2012-12-13 11:07:04 -08:00
bsimmers 980c70af00 OpSame and OpNSame are always native calls
Any comparisons that are simple enough to be done inline end
up getting converted to Eq. This makes for much nicer register
allocation around the call.
2012-12-13 11:07:04 -08:00
bsimmers 4cc4a0f078 Emit more compact code for uninitting locals in prologues
This saves 2 bytes for the first local and 4 bytes for each
local after that in the inline case. Converting the loop code to the
new style saves a byte on the storel (it used to store 8 bytes to get
both _count and m_type, now it stores 4 bytes to m_type).
2012-12-13 11:07:04 -08:00
Owen Yamauchi 6f923caefb IR translation for IncStat 2012-12-13 11:07:03 -08:00
jdelong f3e7ae6726 Move LinearScan and MemMap classes out of headers
These can be private to their respective translation units,
so we don't have to build other things when changing them.  No big
deal.
2012-12-13 11:07:03 -08:00
jdelong b697c7c0a7 Move peephole from runtime to compiler
Peephole was including MetaInfoBuilder from the compiler.  It
makes more sense to be out of the runtime anyway.
2012-12-13 11:07:03 -08:00
ottoni 0ef2a3e791 Enhance IncRef/DecRef elimination
Enhance IncRef/DecRef elimination by emitting a DecRefNZ when
dec-refing a value that is also stored in a local -- since a local
still contains a reference to the value, such DecRef can't get to zero.
2012-12-13 11:07:03 -08:00
smith ca1ce967a7 Factor out decRefObj and decRefRef
More code cleanup for common the common decref pattern.
2012-12-13 11:07:03 -08:00
Owen Yamauchi 61c382df3c IR translation for UnpackCont, PackCont, and ContExit
Pleasantly straightforward. This implements translations for all the Cont*
instructions that appear inside actual generator bodies. I have to still do
CreateCont and ContEnter, but in a separate diff.
2012-12-13 11:07:03 -08:00
smith 2da92877d3 Remove the CGetM_LEE special case
Array access of the form [int][str] seems like a narrow
case to optimize for; the helpers are tricky and we're
i-cache limited.  This removes the special case.
2012-12-13 11:07:03 -08:00
njormrod 5b7e9af239 Added a test-generator cpp file
Generates an extremely extensive coverage test for
comparison operators. ~166k test in total.
2012-12-11 11:55:50 -08:00
mwilliams 7043e78181 Fix scope for UnitMergeKindReqDoc
When we optimize ReqDoc inside Unit::merge we need to
respect the caller's scope.
2012-12-11 10:10:05 -08:00
bsimmers a25db97606 Add new style movzbl, convert some related codegen to the new style
Pretty straightforward, I just had to fix up a few issues in
emitCMX.
2012-12-11 10:10:05 -08:00
jdelong 2f6d5efd34 Turn off -Wno-parenthesis
We don't have many violations of this, so it seemed easy
enough to fix them and turn it on.  It looks like it caught one bug in
Func::mustBeRef(), but everything else looked right.
2012-12-10 17:14:58 -08:00
jdelong adfec915ad Remove a few deprecated conversions from string literals to char*
String literals should be const char*.
2012-12-10 17:14:58 -08:00
jdelong eb49ddcefa Remove codegen support for spilling homes
This looks like it was left over from back when we might
split a trace with a home on the stack.
2012-12-10 17:14:58 -08:00
jdelong 6ec51d4d13 Some minor cleanup with how Local objects work
Move Local objects from being arena-allocated to values
in-place in the ConstInstruction.  Some minor const-correctness stuff.
Also, the number of locals was being incorrectly counted and passed to
linearscan (which didn't really use the count for anything except an
initial vector size).
2012-12-10 17:14:58 -08:00
jdelong fb577e0795 Make instruction flag functions non-virtual and combine implementation
These don't need to be virtual.  While doing that, changed to
a shared implementation (may make adding/removing bits from the
instruction table marginally easier).  Also moved documentation from
the .cpp to the header.
2012-12-10 17:14:57 -08:00
jdelong 3657d58b93 Replace uses of RegNumber with PhysReg in codegen.cpp
Catches codegen up to translator-x64 in terms of how we're
using types for registers.
2012-12-10 17:14:57 -08:00
jdelong c0e3163a4a Clean up on SSATmp and LinearScan
Moves SSATmp spill information into a separate API from
allocated registers, with a bit indicating whether we're spilled.
This lets us drop the encoding of spilled vs. mmx vs. reg as integer
ranges, so we can move away from RegNumber everywhere (followup diff).
Also separates the concept of getNumRegs into numAllocatedRegs and
numNeededRegs, with some documentation on it and removes all the
LinearScan:: constants that duplicate abi-x64.h.
2012-12-10 17:14:57 -08:00
amaury 63b486f510 SSwitch implementation in assembler.
SSwitch are now parsed and assembled for assembly files (hhas).
2012-12-10 17:14:57 -08:00
Sara Golemon e416104caf AdminServer should use text/plain content type
Make it readable from a web-browser since the default
content type (text/html) treats newlines as normal whitespace.
2012-12-10 17:14:57 -08:00
Sara Golemon 1b66452ceb Make AdminServer disabled by default. 2012-12-10 17:14:47 -08:00
bsimmers f1442e24fe Warn when not enough args are passed in the jit 2012-12-10 16:47:42 -08:00
Sara Golemon 1dc1d10bd9 Merge pull request #647 from nareshv/master
libdwarf cmake rule update for fedora systems
2012-12-10 12:59:47 -08:00
bsimmers fbc1308bf6 util/tests/asm fixes
- objdump prints everything as an unsigned displacement
- unlink the binary file after disassembling it
2012-12-10 11:36:03 -08:00
bsimmers 9eb7aa1b1c Don't use compiler_id.h in stack_trace.cpp 2012-12-10 11:36:03 -08:00
bsimmers 9bfc079318 Change lea to take memory refs
This is more consistent with the syntax we're trying to
mimic.
2012-12-10 11:36:03 -08:00
smith 44282caece Turn cgCallHelper bool arg into enum SyncOptions
Cosmetic change to make callsites more self-documenting.
2012-12-10 11:36:03 -08:00
jdelong 6a55497dce Rename SSATmp "analysis value" to spill slot
It feels like premature space optimization to give this a
generic name.  If we need to chunk space down later, we can use unions
internally while still preserving a public interface to SSATmp that
has real identifiers.
2012-12-10 11:36:03 -08:00
jdelong bd8b37a025 Rename getAssignedLoc to getReg
Right now, assigned registers and spill locations are stored
on SSATmp with some ranges of integers indicating what means what.
I'm going to separate those, and the name getReg() will make more
sense than getAssignedLoc after this.  (The only time getAssignedLoc
can really return spill locations instead of regs in codegen appears
to be cgSpill and cgRestore.)
2012-12-10 11:36:03 -08:00
jdelong 6735d7466b Use RegSet for liveOutRegs; cleanup some linearscan.h bitmask stuff
Puts RegSet into physreg.h so we don't really need to include
regalloc.  Also uses PhysRegSaver to save regs instead of new code for
it.  (RegSet/PhysRegSaver/etc should probably move to a util/x64 soon
after this ...)  Ideally PhysReg can go away some day (after old-style
assembler apis are unused, we should probably just use Reg64 or a sum
type of Reg64 + RegXMM).
2012-12-10 11:36:03 -08:00
jdelong 70d2f941e0 Make more of LinearScan private; order the members
I think we probably ideally want the only real public part of
this class to be the non-member function assignRegsForTrace.  We'll
need a PhysReg-like abstraction hanging off of SSATmp to encapsulate
all the rest.
2012-12-10 11:36:03 -08:00
jdelong ef82c8549a Remove a thing from coding_guideline 2012-12-10 11:36:03 -08:00
smith fb8cace4d0 IR Support for NewArray capacity hint
Add NewArray capacity hint support to IR.
2012-12-10 11:36:03 -08:00
aravind c157fd9948 Fix FrameInjection for debug_backtrace
FrameInjectObjectMethod can free an object without
first setting m_object to NULL. If the object destructor
eventually calls debug_backtrace(), it would return the
freed object as part of the backtrace.

This diff fixes it so that FrameInjection NULLs out an object
before releasing it.
2012-12-10 11:36:03 -08:00
smith 437018a73d Refactor ArrayData decref into decRefArr function 2012-12-10 11:36:03 -08:00
Sara Golemon 1643e31a5f Fix regression test for parse_ini_string() w/Constants 2012-12-10 11:36:02 -08:00
Sara Golemon b5163add57 Make Translator sizes configurable
Eval {
  JitASize = 512 << 20 # 512MB
  JitAStubsSize = 512 << 20 # 512MB
  JitGlobalDataSize = JitASize >> 2 # 128MB
}
2012-12-07 18:53:50 -08:00
jdelong 0782c64232 Fix changes to job_queue.h for hphpc
An if (hhvm) was left out.
2012-12-07 18:53:50 -08:00
Owen Yamauchi cef2e9e1cf Delete unused continuation-related IR opcodes
This happened as a byproduct of my work to reimplement continuation support in
the IR. I'm putting it up as a separate diff to keep the others simple.
2012-12-07 18:53:49 -08:00
bsimmers 1f4f65f21b Add an environment variable to disassemble with AT&T syntax
Setting HHVM_ATT_DISAS before running hhvm or tc-print will
result in any disassembled instructions being printed with AT&T
syntax. The default is still Intel.
2012-12-07 18:53:49 -08:00
smith 662f380a7b One less instruction for virtual calls
When doing a virtual call using a vtable, use call offset[vtbl_ptr],
which saves one instruction.
2012-12-07 18:53:49 -08:00
bsimmers 249bb59579 Don't emit metainfo for Iter(Init|Next)* instructions
These are the only instructions that take two HA immediates
and the emitter is not set up to handle that. In the IterInit* case,
it was causing failed ASSERTs in the translator due to misnumbered
metainfo.
2012-12-07 15:47:00 -08:00
smith 7c9a528d0a Use appendWithRef instead of nvAppendWithRef
The dedicated function for HphpArray doesn't pay for itself
so replace it with a call to ArrayData::appendWithRef instead.
If this path were hot enough, a dedicated HphpArray constructor
would be best.
2012-12-07 15:47:00 -08:00
smith f958400532 Cleanup: Use decRefStr instead of the manually inlined equivalent
This just factors the common pattern of decref & release of a StringData
into a helper function.
2012-12-07 15:47:00 -08:00
jdelong 68752be143 Make numberInstructions not copy-construct the instruction list 2012-12-07 15:46:59 -08:00
jdelong 88f83eaf60 Remove duplicate argNumToRegName from codegen.h 2012-12-07 15:46:59 -08:00
jdelong ec815f4dc0 Do jmp/call with a memory operand when calling destructors 2012-12-07 15:46:59 -08:00
jdelong 9f81505923 Make callUnaryStub not trash r10 if it doesn't need to
When calling a stub that is also inside a/astubs, we
shouldn't need to load the address into r10 first.  Also modifies
Stats::emitInc to preserve rScratch.  This should fix TRACE=stats:1.
2012-12-07 15:46:59 -08:00
jdelong b356ba5188 Remove unused Variant::getDebugDump
This doesn't do much and we can use TypedValue::pretty()
instead.
2012-12-07 15:46:59 -08:00
bsimmers 0e9d236276 Don't include Nopped instructions in the stream after a failed IR translation
I missed this use of RuntimeOption::EvalJitIR
2012-12-07 15:46:59 -08:00
jdelong dc17e5f877 Add some assembler unit tests
Tries assembling a bunch of things and makes sure we get the
expected string back from disassembling it with objdump.
2012-12-07 15:46:58 -08:00
jdelong 2a349cd1aa Move asm-x64.h to util/
I want to write a unit test for codgen, and this file doesn't
really depend on anything VM-specific.
2012-12-07 15:46:58 -08:00
jdelong b0593fce6b Minimal support for gtests for src/util stuff 2012-12-07 15:46:49 -08:00
jdelong 24c63b4604 Make make -j -C src/util work.
This makes it possible to do make -j -C src/util if you just
want to build util.
2012-12-07 15:44:28 -08:00
jdelong fee490c9aa Remove SA_INC_GEN from build process
We don't need this anymore because there are no longer
extensions that add smart allocator types.  This also makes it
possible to make -C src/compiler again.
2012-12-07 15:44:28 -08:00
jdelong 8287b8d196 Make src/util/parser not depend on src/runtime
The parser only needed string_md5 from zend, which also
requires a few other things.  I pulled a few related zend functions to
util/zend (ideally we'd pull everything that doesn't use runtime/, but
no need to get carried away).  After this (and the other diffs), the
only dependency from util to runtime is compiler_id.h.
2012-12-07 15:44:27 -08:00
jdelong 1a335a7070 Move segfault handler out of src/util
StackTrace (and Logger via it) only depended on the world
because of the seg fault handler code importing execution_context.
Move this to runtime/base (it seems more logical to not have it part
of the StackTrace lib anyway).
2012-12-07 15:44:27 -08:00
jdelong 1019e095ed Make util/job_queue.h not depend on bytecode.h
It would probably be cleaner if most of the drop-stack
machinery was moved into a policy, but for now this just moves the
part that is VM-specific out so we don't need to depend on bytecode.h.
Only hooks up the servery ones to do a drop on the VM stack (I don't
think the workers in the compiler should need this?).
2012-12-07 15:44:27 -08:00
jdelong 7c7392ec3f A few steps toward making src/util not depend on anything
It looks like the main pain if we want a libutil.a is Logger,
which depends on StackTrace, which depends on execution context, which
depends on everything.  JobQueue also needs to call VM::Stack::flush
right now (separate diff), and the parser probably would need to be
pulled out of util/.  This diff just does the remaining easier things:

  - put TypedValue::pretty outside of trace.cpp
  - ringbuffer/pathtrack didn't really need to include asm-x64.h
  - move stat_cache (uses VM::Transl and some other things) to runtime/base
  - move hardware_counter (VM::Transl and complex_types.h) to runtime/base
2012-12-07 15:44:27 -08:00
smith a7ff15831a Cleanup array_setm helper code
With nvSet(int,int) out of the way, we don't need as much templated
code.
2012-12-07 15:44:27 -08:00
smith ccb650f7fe Simplify nvAppend
HphpArray::nvAppend is semanticly equivalent to ArrayData::append.
All call sites but one were passing copy=false with a guaranteed HphpArray,
except one, which is cleaner as a call to ArrayData::append anyway.
2012-12-07 15:44:27 -08:00
Sara Golemon ecf3b56671 Remove some unnecessary verbosity from cmake 2012-12-07 15:44:26 -08:00
smith 674ab6b2c7 Use findForNewInsert in HphpArray::add, and other tweaks
Firstly, the ArrayData add() method is only legal when the key
does not exist, so we can use the fast findForNewInsert method
when adding strings to an array.  (We already assert on dups).

Second, if we assume most find() operations on strings (for
get access) find the string on the first probe, then it makes
sense to do the string-equal check first, before the empty-pos
check.
2012-12-06 11:23:10 -08:00
ottoni c18a58fba6 Add support for BC mappings, translation counters, and add new kind for IR-based translations in TC dumps 2012-12-06 11:23:10 -08:00
nareshv bcdb3b208a Update CMake/FindLibDwarf.cmake
fedora installs libdwarf headers in /usr/include/libdwarf/
2012-12-06 17:11:37 +05:30
Owen Yamauchi 5373eaa57e Smarten up type calculus of Cont* instructions
- We know the type of local 0 for all Cont* instructions inside generator
  bodies: it's an object. We don't need to guard on it. I removed the typehint
  (normally added by the parser) because it results in a useless VerifyParamType
  (which results in a tracelet guard). Theoretically we should be able to derive
  the information I added in MetaInfo from the typehint, but that's for another
  day.

- PackCont and UnpackCont don't touch locals anymore.
2012-12-05 13:33:51 -08:00
bsimmers b6e1930f57 Re-analyze tracelets when IR translation fails
When Translator::analyze runs with the IR enabled, it skips
most optimizations. This is what we want to keep the instruction
stream clean for the IR, but if it has to pass the tracelet back to
TranslatorX64 for translation, the resulting code will be missing all
the optimizations that analyze would've done. Now we re-analyze the
tracelet with m_useHHIR == false if the IR translation fails.
2012-12-05 13:33:51 -08:00
ottoni d54b34d891 Relax guards for CGetL, RetC, RetV
Use guard relaxation for CGetL, RetC, and RetV.

This diff also changes the DataType numbers to give one bit for each
type (with the exception of KindOfUninit, which is still 0).  This
enables a more efficient check in some cases, such as "uncounted but
not uninit", which is used for CGetL.
2012-12-05 13:11:21 -08:00
kma 69ea0d6951 Don't guard on KindOfClass.
The stack slots that hold a KindOfClass are a verifiable
static property. Don't guard on them.
2012-12-05 12:47:26 -08:00
alia 67c1c89c39 Refactored LdRaw/StRaw to support 4-byte loads for Strlen and fixed a Strlen bug.
Changed LdRaw/StRaw to take an enum specifying the field accessed
by the Ld/St instead of an offset. Introduced a new class, RawMemSlot that
specifies the type, size, and offset of each field accessed by LdRaw/StRaw.
Fixed a missing evaluation stack bug in Strlen. Fixed bug in encoding of int3
in asm-x64.h. Fixed bug in rematerialization of LdLoc.
2012-12-05 12:47:26 -08:00
aravind 50e54b6d49 Skip ActRec for builtins
A number of builtins needs to access the ActRec of the calling
function in order to get context information (this, context
class, etc). Currently they do so by explicitly skipping over
the builtin's ActRec. However, when calling builtins with
FCallBuiltin, there is no builtin ActRec, and these builtins
must be marked with the "NeedsActRec" flag.

This diff eliminates the explicit skip step, and changes it so
that the innermost ActRec is automatically skipped if it is
the builtin's ActRec. With this change, fewer builtin's need to
have the NeedsActRec flag.
2012-12-05 12:00:11 -08:00
mwilliams cc210c60d4 Fix TestDebugger-WebRequest
Fix the config file so it picks up the user name.
2012-12-05 12:00:11 -08:00
smith 123df9f70d Simpler circular-list logic for Sweepable and String sweep list
The sweep lists for Sweepable and StringData are circularly linked
lists, with the head pointing to an arbitrary node if the list is
non-empty, or null if its empty.  By changing the head to a node
instead of a pointer, we can remove the branches from the insert/remove
code since they don't have to check for NULL.
2012-12-04 11:13:54 -08:00
smith 78ce48f94b Remove specialized nvSet(int, int)
This specialized set method doesn't seem to pay for itself, but its used
often enough to compete for cache/TLB with existing code.  Removing it.
2012-12-04 11:13:54 -08:00
asukhachev fed3439943 Always remove the temporary file when --temp-file is passed
There are too many branches in execute_program_impl(), so to reliably
remove the temporary file, making the wrapper function do it.
2012-12-04 11:13:54 -08:00
jakubv e5febfa6d0 Don't add 1900 to years above 100 in mktime()
It differs from PHP implementation: http://git.php.net/?p=php-src.git;a=blob;f=ext/date/php_date.c;hb=d23f9194b171443cc0ff40e34915df3e73f1c486#l1414
I also see no reason for it.
2012-12-04 11:13:54 -08:00
smith 1dd8681910 Clean up some dead code and inline some used-once code in array helpers. 2012-12-04 11:13:54 -08:00
bsimmers 48dc6219d2 Ignore NonRefCounted metadata for now
The static analysis it uses isn't perfect.
2012-12-04 11:13:54 -08:00
mwilliams 5c736b05b0 Misc fixes
While tracking down other issues, I hit a bogus
ASSERT in sendImpl.

I also noticed some fragile code, where it would have
been possible to write "HphpArray*arr; ArrayIter(arr);"
expecting to hit the ArrayIter(const ArrayData*) constructor,
but actually hitting the const HphpArray* constructor.

The latter is a special one that skips refcounting, and skips
null checks - so force the user choose it explicitly.

Also make another special constructor more self documenting.
2012-12-03 11:25:01 -08:00
jdelong 04b97e06f8 Fix a bug in wantInlineReturn
Aravind noticed that the logic here was broken; it didn't
check enough locals when counting how many were ref-counted.  (We'll
probably want to revisit the value for kMaxInlineReturnDecRefs after
this; I'll start perflabs for a few values.)
2012-12-03 11:25:01 -08:00
mwilliams 9cde222eae Fix crash when 86sinit and 86pinit fail
If 86sinit or 86pinit failed (eg the reference unknown class
constants), and there's a user error handler, local
NameValueTableWrappers could be leaked into the backtrace,
resulting in use-after-free errors and crashes.

This fixes the issue by skipping these functions in the
backtrace (which is desirable anyway - they're just an
artifact of our current implementation).
2012-12-03 11:25:00 -08:00
kma ada59f8661 Fix an overly aggressive assert.
Functions sometimes return Refs, and we might as well predict them
as such.
2012-12-03 11:25:00 -08:00
ottoni f84919290b Disable some generated checking code in non-debug builds
We were generating calls to sanity-checking helpers at the beginning
of each tracelet, and also at the end of tracelets ending with a Ret*.

That's not good for performance... so only do it for debug builds. :-)
2012-12-03 11:25:00 -08:00
jan 73f1c0ebd9 Reorder ObjectData properties to free alignment space for subclasses
remove unused m_propsOffset
move 32-bit o_id and 16-bit o_attribute to the end, so the the
  remaininig 16 bits can be reused by subclasses
2012-11-30 14:15:26 -08:00
mwilliams cad90186a0 Kill DebuggerProxy's before its too late
The debugger keeps a map of DebuggerProxy's in Debugger::s_debugger.
When a DebuggerProxy is destroyed, it has to wait for the
corresponding thread to finish its work, and then exit. As things
stood, this didnt happen until s_debugger's destructor was called.
But that was way too late - lots of things (such as empty_array)
have been destroyed, and the thread would typically crash.

Clearing the map on Debugger::Stop shuts them down at the right
time, and things go much more smoothly.
2012-11-30 14:15:26 -08:00
psnell ae018be068 Got rid of IterKey/IterValue and moved their functionality into IterInit/IterNext. 2012-11-30 14:15:25 -08:00
Sara Golemon 183ccbd505 Properly annotate upload_max_filesize with 'M' suffix.
This brings us in line with Zend's return value.
2012-11-30 14:15:25 -08:00
bsimmers 8ada368bdd Efficiently support switches with static string cases
This is similar to what I did for integer switches: when
every case in a switch is a literal string, the new SSWitch
instruction is used instead of a series of if/elses. At translation
time, if the input is a string and none of the cases are numeric
strings, we can turn it into a hashtable lookup. Otherwise we simulate
the code that would've been emitted by comparing the subject against
each case in the order they appeared in the source.
2012-11-29 13:30:26 -08:00
jdelong 47f80c9bb0 Some cleanup related to shift
Remove a false TODO (already implemented) and an unused
function.
2012-11-29 13:30:26 -08:00
jdelong c3943a91bb Rename register_name_t to RegNumber 2012-11-29 13:30:26 -08:00
jdelong 8d79603485 Add more syntactic sugar to X64Assembler
Adds some new syntax for using the assembler, to try to make
it look a little more like an x64 DSEL.  Backward compatible with the
existing APIs, and stops short of any sort of massive conversions (we
can do this if it proves to be nice to use in new translations).
Converts a few small pieces of translator code to make sure it worked
and to experiment with using it.
2012-11-29 13:30:25 -08:00
jdelong f820106e13 Remove operator* from LazyScratchReg and DumbScratchReg
We'd like to use operator* on registers to indicate register
indirect addressing in the assembler, so it's a little confusing if it
is also used to dereference scratch registers.  This uses r(reg) as
the syntax to get at the underlying PhysReg.
2012-11-29 13:30:25 -08:00
mwilliams 2ecd532ae5 Fix zend array sorting when exceptions are thrown
A missing "throw" caused memory to be double freed,
and to be referenced after the first free.
2012-11-29 13:30:25 -08:00
mpal a24f2b5223 IR, Guard exits Jcc directly to anchor translation
Check the beginning of traces for a contiguous sequence of
Marker, DefFP, DefSP, and either LdLoc or LdStack with a label.
Record in the LdLoc and LdStack instructions that these
should branch directly to the anchor translation.
This is almost exactly what is needed to enable the
same optimization for slow exits inside the trace.
2012-11-29 13:30:25 -08:00
smith 22cc7ad9be Remove remainder of tv_macros: TV_INCREF, TV_UNBOX, and TV_READ_CELL
This completes the removal of tv_macros.h, in favor of inline
functions in tv_helpers.h
2012-11-29 13:30:25 -08:00
smith 89aff77229 Get rid of TV_DUP_* macros, use inline functions instead.
Code cleanup to reduce use of the TV_DUP* macros, plus a few
other minor cleanups to use available helper functions.
This also fixes comments about not modifying _count.
2012-11-29 13:30:25 -08:00
varunk 13be9333f7 Varint encode the header size for lz4 compression 2012-11-29 13:30:25 -08:00
mwilliams f32f118d02 Avoid infinite recursion in array wrappers
GlobalArrayWrapper and NameValueTableWrapper convert numeric
keys to Strings. But due to changes in the interface, the
cast to Variant now results in a recursive call back to the
int version. Cast directly to String instead.
2012-11-28 11:18:07 -08:00
smith e47c1c8618 Use a std::string in DebuggerClient for api output buffering
Using a malloc'd StringBuffer leads to memory corruption because
of StringBuffer's internal smart-alloc'd StringData.  So use std::string
instead and copy to a String on demand.
2012-11-28 11:18:07 -08:00
njormrod b4d097262f bools are now bytes in the IR 2012-11-28 11:18:07 -08:00
peterv c8f49abc06 Implement wrapper for ICUMatcher for better bidi/rtl regexes
Implement a new PHP function called icu_match that is loosely
modeled on the semantics of preg_match that wraps ICU library's
regex compiler and matcher. Also steal some pattern parseing
code from f_preg_match(). Function returns 0 (no match),
1 (match) or false (error).
2012-11-28 11:17:33 -08:00
zoel 23a6c4cdcd Made the log line for HeaderMangle more greppable 2012-11-28 10:54:41 -08:00
mwilliams 92a759d01e Fix the translator's type inference for (null)->prop
Per the existing comment, it was broken. Fix the code, and
remove the comment
2012-11-28 10:54:41 -08:00
kma 96a161b277 Fix the prediction stress a little more.
The prediction stress code was producing some impossible traces:
C* instructions that left a Ref on the stack, and KindOfUninit right
hand sides. This could cause rare downstream failures.
2012-11-28 10:54:40 -08:00
mpal 3ac34e0351 IR, always check surprise flags in Ret
IR skipped surprise flag check when it did not handle freeing
locals inline.
Update surprise check mechanism to use testb 0xff,surpriseFlags
2012-11-28 10:54:40 -08:00
kma 4939cbd48d Fix some bugs with FPushClsMethodF on non-strings.
foo::$bar() where $bar was not a string would assert fail in
some places. Hit this while playing around with CGetM's type
inference.
2012-11-28 10:54:40 -08:00
smith 21640ece9f Replace TV_WRITE_NULL and TV_WRITE_UNINIT with inline functions
Simple cleanup to use the inline function versions of these macros.
2012-11-28 10:54:40 -08:00
bsimmers 155f3b2273 Banish std::string and std::map from ext_obc, take 2
The first version of this diff dropped counters on the
floor due to an assumption about the ordering of std::map that I
didn't catch and fix.
2012-11-28 10:54:40 -08:00
mwilliams b65e519008 Warn when fetching an apc primed key fails
If fetching an apc primed key fails, raise a notice, return
false, and dont store the returned value (so that we'll
continue to raise the notice on every fetch).
2012-11-27 10:41:17 -08:00
mwilliams 808fc605f1 InterruptVMHook needs a VMRegAnchor
InterruptVMHook accesses the current frame from
the execution context, so needs a VMRegAnchor.
2012-11-27 10:41:17 -08:00
mwilliams 555e2cb69c Fix default args in call_user_func_array
If the function entry had not been translated,
and we couldnt translate it (because the write lease
was held by another thread) we would incorrectly
setup the pc to point to the function body, which
would skip the default initializers.
2012-11-27 10:41:17 -08:00
Sara Golemon e75e166f28 Substitute defined constants in INI files. 2012-11-26 15:54:19 -08:00
bsimmers efcb2d2c8e String concatenation helpers can reenter 2012-11-26 15:53:36 -08:00
jdelong 16f81af4bb Unnecessary template metaprogram for iopFCallBuiltin
Replace perfectly reasonable macros with some templated
stuff.  (Makes it so we can easily add support for more return types
and supports double arguments (but that doesn't matter since the JIT
doesn't know how still).)
2012-11-26 15:53:36 -08:00
kma af74bb3fcf Handle trivial array and object casts.
Don't do work when casting arrays to arrays, or objects to
objects.
2012-11-26 15:53:36 -08:00
kma 77c33dced6 Avoid a partial register stall when converting from ints.
Edwin and the Internet both agree: cvtsi2sd is considered
harmful without doing something to break the dependency on the target
register's high-order bits.
2012-11-26 15:15:38 -08:00
mwilliams 9cf9154c61 Workaround a bug in HphpArray::u*sort
The array was being modified in place, while calling the
user sort functions, with the result that the user sort
function saw garbage. As a temporary fix, always duplicate
the input array, sort that, and then update the original
array reference.

A better fix would be to only do this for
the user sort cases. Even better would be to sort an array
of indices, and then update the array itself after the
user functions have been called. (task #1910931)

In addition, the new test case I wrote revealed a bug in
the translator's type inference. It failed to take account
of OpBindM's effect on its base. Also fixed here.
2012-11-26 15:15:38 -08:00
mwilliams 20848c8781 Make Continuation::rewind equivalent to next
There was code that assumed it could call foreach
more than once on a continuation (as long as the
continuation wasnt "done"). This was broken by
recent changes to Continuation.
2012-11-26 15:15:38 -08:00
mpal eaf23483cf IR, (val1 == val1) ==> true is not correct when val1 is a NaN
Turn off simplification rule for (val1 OP val1) when val1
is a double, since NaNs have their own 'special' behavior.
2012-11-26 15:15:38 -08:00
aravind 45f733f037 Optimize builtin calls
Optimize builtin calls so that they can be invoked directly
without going through fg_wrappers. Adds a new opcode FCallBuiltin
that does not require an ActRec for builtin calls.

Add a new flag "NeedsActRec" to mark idl functions that require
an ActRec.
2012-11-26 15:08:43 -08:00
mwilliams 7cf23bbd4a intercepted functions could unbalance the stack
The cleanup code assumed that the number of parameters
reported in the actrec was the number of parameters
pushed on the stack. But some of them could be in
extraArgs.
2012-11-26 11:07:44 -08:00
mwilliams 6a535f44f7 PREP_VAL needs to check its register is available
PREP_VAL tries to allocate a specific register (since it
will be used as a call argument). But there's no guarantee
the register is free. Clean/smash is not the right thing to
do, because it could be that one of the /other/ call arguments
is using that register.

So if the desired target register is not free, just use
any register, and let the usual argument shuffling take
care of getting it into the right place
2012-11-26 11:07:44 -08:00
Sara Golemon 866bb33974 Add license header to smalllocks.h 2012-11-21 00:11:34 -08:00
mwilliams dd752f8669 Fix crash creating objects derived from builtins
The fast path was checking for classes which
are builtins, but not classes which are derived
from builtins.
2012-11-21 00:11:02 -08:00
aravind 542a057af0 Don't infer static locals as non-refcounted 2012-11-21 00:11:01 -08:00
mwilliams 5673128b4f Fix incorrect UseVoidReturn warnings
When we inserted type assertions, we didnt
always propagate the "unused" flag correctly.
2012-11-21 00:11:01 -08:00
xning da275477b1 Added get_http_request_size() php function to return the size of the incoming http request
1. Added Transport::getRequestSize() to expose the http request size. For LibEventTransport,
the size is computed based on the headers because libevent hides the data structure needed
to directly get the size (in evhttp_connection, not exposed).

2. Exposed the previous new API as a php function.
2012-11-21 00:11:01 -08:00
aravind 888752cd19 Set ref context for unset
Summary:
For examples such as this:

class A {
  public function foo() {
    unset($this);
  }
}
$obj = new A;
$obj->foo();
2012-11-20 23:48:08 -08:00
jdelong bf66675d40 Fix destructed_this in hhir
Store back null.
2012-11-20 23:44:04 -08:00
ottoni fedfddba84 Revert "Handle empty string types"
Summary: This reverts commit b532cedf6a
2012-11-20 23:44:04 -08:00
jan af051f2d31 Set value consistently to null on finish
"yield break" is setting the current() value of generator to null, but
end of generator execution, or thrown exception do not. Let's be
consistent and set the value to null everytime a generator is closed.

This also makes generators more consistent with Zend's behavior:

https://wiki.php.net/rfc/generators
"current: Returns whatever was passed to yield or null if nothing was
passed or the generator is already closed."

IIRC we had this behavior for end of generator execution a few months
ago.
2012-11-20 23:44:04 -08:00
smith a4d00a35dc Decref string keys after calling nvGetKey()
A few callsites of nvGetKey were not recounting correctly,
which causes string keys to be leaked.

Added a few new helpers that we can start using elsewhere too.
2012-11-20 23:44:04 -08:00
andrewparoski 8692f09d69 Set StrictCollections=true by default
We've been running with StrictCollections=true in our configs for a while
without problems. Let's make it true by default, and then in the near
future we can remove this runtime option.
2012-11-20 23:44:04 -08:00
bsimmers 014309abcc Add an IncStat opcode
This is useful for getting runtime counts of events that are
more readily identified at emission time.
2012-11-20 23:44:03 -08:00
jdelong f4b554cf2b Fix guardedThis on RetC
This was being skipped in applyInputMetaData.
2012-11-20 23:44:03 -08:00
bsimmers 16d5a4bbcf Forget stopped threads in TimeoutThread
TimeoutThread was never notified when a worker thread
exited. This was causing a crash during shutdown when it tried to set
the timed out flag of a deleted thread (in hhvm the surprise flags
live in the targetcache, which is unmapped during thread shutdown).
2012-11-16 15:53:15 -08:00
bsimmers 09d3ef9ef0 Add Runtime and Version lines to stacktraces
Runtime will be 'hhvm' or 'hphp' and Version is the
compiler-id.
2012-11-16 15:53:15 -08:00
kma efb707b3c6 Add a regression test for mixed int/double math patch 2012-11-16 15:53:15 -08:00
kma 3cb9e77aa7 Mixed int/double math. 2012-11-16 12:12:25 -08:00
ottoni 095c19b5c2 Fix order in which classes get their traits imported
We were not enforcing that traits from base classes are imported
before importing traits in their derived classes.  This could result
in a derived class with an abstract trait method not "seeing" a
concrete definition of this method if the parent method got that
definition from a trait as well.  This would result in a "pure
virtual" fatal being thrown.
2012-11-16 12:12:25 -08:00
mwilliams 872eeebdcb Static type guards for Iter* bytecodes
We often know the type of an iterator
statically. Add meta data to avoid guarding
on the type in those cases.
2012-11-16 12:12:25 -08:00
bmaurer 72b23c389c Lock reads from the APC prime file
Thread building blocks issues -- concurrent map only uses spin locks
and calls sched_yield to pause, which just doesn't work well. If there
is any contention, it causes the system to spin like crazy.

This type of contention seems to be happening at startup when many
people are trying to use the same variables from APC. Based on profiling
I think that people are trying to read data structures that are very
array heavy, and in the handleUpdate spend a lot of time freeing it, all
while holding a writer lock.

This diff introduces a lock when you first read the piece of data from
disk. Because you hold a reader lock with the const_accessor, there's
no risk of the datastructure itself being freed. One thread is allowed
to read the object.

This also introduces a SmallLock datastructure which implements a mutex
in the space of a single int. As noted in the comments, this could be
made smaller. It could also be extended to other small locking structures
(eg, a pointer that could also serve as a lock).
2012-11-16 12:12:25 -08:00
jdelong d5ebbfda07 enterTC code tweaks
A few minor tweaks.  Changes things so the compiler will
inline the fast path of getTranslation, only stores service request
args when there is a non-REQ_EXIT request, and removes the resume()
virtual since we're using TranslatorX64* in bytecode.cpp anyway.
2012-11-16 12:12:25 -08:00
andrewparoski fc1e89f684 Sorting for collections
This diff adds support for Vectors to sort and usort, and adds support for
StableMaps to asort, ksort, uasort, and uksort.
2012-11-16 12:12:25 -08:00
kma c0e082285a Nop out trivial CastDouble's.
I noticed this in je's command-line script and in histograms
of interp'ed instructions from www. A lot of the time (double) is just
to make sure on something that was already a double.
2012-11-16 12:12:24 -08:00
je@fb.com cb2f97937d Use in-memory SQLite journaling for hphpc.
Use in-memory SQLite journaling for hphpc, since any hphpc failure by
definition results in an unusable repo anyway.
2012-11-16 12:12:24 -08:00
jdelong ebaf5584af Don't guard on nonrefcounted locals at RetC
If a local is known not to be reference counted at a given
RetC site, we don't need to guard on it when doing an inline return.
2012-11-16 12:12:24 -08:00
jdelong 73253c6a0a Improve the generic freeLocalsHelper
Removes more branches from common cases in the
frameFreeLocals helper by calling to different offsets in a
generic-decref slide.  Also inlines the decref and destructor calls
instead of calling out to tvDecRefHelper.  To support this it also
always emits the varenv check (for AttrMayUseVV) and decrefs
ActRec::m_this in translateRetC translation.  For now this removes the
limit on total number of locals to do a specialized return (it leaves
the limit on number of reference counted locals).
2012-11-16 12:12:13 -08:00
jdelong 2b5d7bcc82 Improve generic dtor stubs and support frame-less shared TC stubs
By allowing avoiding frames and using a custom calling
convention, combines the two generic dtor stubs and fits them on one
cache line.  Also inlines the call-table lookup for release helpers
instead of jumping to a C++ stub that does it.
2012-11-16 12:11:36 -08:00
jdelong c8e11a0d41 Move the inline vs. generic RetC cases into subroutines
Cut down a tad on function growth hormone imbalance syndrome.
2012-11-16 12:11:36 -08:00
jan 7d9414f0dd Transform only foreaches with yield statements inside
Use the FunctionContext parser abstraction to keep track of
open foreach statements and presence of yields.
2012-11-16 12:11:36 -08:00
jan 88cf84191e Separate "yield break" from "yield" parsing
"yield" and "yield break" are fundamentally different statements. Separate
their parsing paths and don't generate unused goto labels for "yield
break".

Parser's m_generators logic was updated to cope with zero labels case
that is now possible. A test case was added to cover this case.
2012-11-16 12:11:36 -08:00
kma e298b1b901 Fix bug, increase coverage for binary arithmetic.
Our attempts to handle reffy left-hand-sides for *= and friends
have always been broken. I noticed this while debugging an assertion
failure caused by misparenthesizing a check in analyzeSetOpL.
2012-11-16 12:11:36 -08:00
kma 76f5f8db46 Predict Int for %, Double for /.
These operators produce unpredictable results. However, in the
vast majority of correct programs they produce a numeric type.
There's some uncertainty for /, so favor Double. We could
ultimately profile-drive this if we want more precision.
2012-11-16 12:11:36 -08:00
Sara Golemon 3a671e83d9 Make HPHPc no longer default, require exprot USE_HPHPC=1
As part of the migration to making HHVM the default, all
builds must now explicitly state which version of HipHop
they would like to use.

For HHVM:  export USE_HHVM=1
For HPHPc: export USE_HPHPC=1

Setting both (or neither) will result in an error message
from cmake.
2012-11-16 10:34:20 -08:00
smith 4bd19f2060 Refactor TV_DUP_FLATTEN_VARS as an inline function.
As a macro, this one has teeth; it can mutate the 'fr' parameter,
so I rewrote it as an inline function.  Also cleaned up a hack in
instance.cpp that was committed before we removed the _count = 0
from TV_DUP_FLATTEN_VARS.
2012-11-15 11:10:13 -08:00
jdelong de70cf9d75 Remove unused call* functions in asm-x64.h
Probably predate EMIT_CALL.
2012-11-15 11:10:13 -08:00
bsimmers 7a6b59fa16 Don't enregister variant keys in the vector translator
Their types can change because of reentry during intermediate
operations.
2012-11-15 11:10:13 -08:00
kma ebec8fb32a Translate Double.
I noticed an interpOneDouble in the emitted code for
evaluate_logistic_regression. No excuse for that.
2012-11-15 11:10:12 -08:00
mwilliams 284637bc8b Use isVolatile() for persistent classes
This mimics the hphpc behavior, which we're
already relying on. Gets similar perf improvements
and so far no correctness issues.
2012-11-15 11:10:12 -08:00
mwilliams ef20ec1b90 Fix missing pseudoMain
There was one place where we didnt check
canUseDummyPseudoMain(), resulting in a
possibility of compilation errors. It was
pretty unlikely, because usually, such
requires have already been removed.
2012-11-15 11:10:12 -08:00
kma 175c5356ad Hardware FP mul, sub, and add.
Use the hardware FPU for double operations. Instead of teaching
the register allocator about FPU regs, we just commandeer xmm0 and xmm1
temporarily to evaluate a single term. Doubles continue to live in GPRs
at instruction boundaries. E.g., to subtract two temporaries in $rax
and $rcx:

  mov %rax, %xmm0     ;; inout
  mov %rcx, %xmm1     ;; in
  subsd %xmm0, %xmm1
  mov %xmm1, %rax     ;; out
2012-11-15 11:10:12 -08:00
smith 3973e7cfcf Fix read-overrun in smart_realloc
If a block ended exactly at the end of a page, and then was
smart_realloc'd to a larger block, and the next page wasn't
mapped, you get a segfault.  the extra 8 bytes we copy aren't
initialized anyway, so if we don't meet these three conditions
then the overrun is harmless.

If realloc's nbytes paramter was smaller than the existing block,
the bug doesn't happen because we clamp the copied size to the
passed-in nbytes parameter.  So no write-overrun can occur.
2012-11-14 11:52:48 -08:00
jdelong d99bcaef70 Make decisions on inlining returns based on number of refcounted locals
Makes two flags that determine when we inline returns.  We
must have more than kFewLocals to use a generic return, and may not
have more than kMaxInlineReturnDecRefs.
2012-11-14 11:52:48 -08:00
Sara Golemon 736139d58a preg_replace() should return an empty array when subject is same
Since return_value isn't actually initialized, it remains
null until a value is set into it.
2012-11-14 11:52:48 -08:00
Sara Golemon 85b46baedb Update XHP to git://github.com/facebook/xhp.git rev d478951476
Also get rid of the PHP Extension files which aren't relevant
to HipHop.
2012-11-14 11:29:23 -08:00
smith 3a9a2a3a52 Call array_getm_impl from TC
array_getm_s/s0/s_fast/s0_fast all just pass some constant flags to
array_getm_impl(), so bypass them and call array_getm_impl directly
from JIT code.  Also, rename to array_getm_s for symmetry with
array_getm_i.
2012-11-13 13:43:14 -08:00
bsimmers 830082111b Don't always addTranslation the anchor in getTranslation
Now that we're reusing service request stubs, it doesn't
always make sense to add a new translation and assert that we've added
it.
2012-11-13 13:43:14 -08:00
mwilliams 56704b3202 Fix some issues with generated code
Redeclared and volatile classes could cause
compilation failures. Fix some of the issues.
2012-11-13 13:43:14 -08:00
je@fb.com 7d5642f5a9 Fix Unit::defClass() ActRec initialization.
Fix Unit::defClass() ActRec initalization to correctly set m_soff.  This
fixes a crashing bug in the unwinder in the case where a fatal is thrown
during class validation.
2012-11-13 13:43:14 -08:00
kma 1eefd915d1 Ad hoc vector optimization for arrays.
If the key is a small integer, try to avoid pulling the m_hash into cache. Guess that we're a vector-like array, and try skipping straight to m_data[key].

As part of this, I've knee-capped the (always dubious, imho) inlined array getm code. Since we're coming out ahead, I claim this worthwhile. Edwin, if this completely overlaps with your vector work I'll happily abandon.
2012-11-13 13:43:14 -08:00
kma 7c3af72631 Fix stats:1 runs.
The stats build was broken again because of a flag smash
in stats. This has been a recurrent problem; let's just save/restore
flags around the add unconditionally.
2012-11-13 13:43:14 -08:00
mwilliams 9456ca56ac Relax redeclared class checking in hphp
It was matching zend behavior, where any attempt to
redeclare a class is a fatal. But under hhvm we allow
the same PreClass to be declared multiple times. Now
hphpc matches hhvm.

Also, properly escape the class name in the error
message.
2012-11-13 13:43:14 -08:00
njormrod ffdfffa663 All comparisons now implemented
Added cgOpCmpHelper function, which amalgamates the logic from
all of the eight different comparison operators. It dispatches control
for specific comparisons via function arguments, calling into
runtime/base/comparisons.h.
This diff also brought to light some bugs and needs-for-improvement
inside of simplifier.cpp. These are included in the diff.
2012-11-13 13:43:14 -08:00
jdelong 9ae14f5bc8 Make some exit helpers not unbalance the return stack
Sometimes we have m_savedRip set to something other than
enterTCHelper.  In these cases, we're unbalancing the return stack.
Change the rets from the stubs to use indirect jumps so we only
mispredict once instead of all the way out the stack.
2012-11-13 13:43:14 -08:00
alia f00c729de2 Created hot path for new_iter_aray.
Split new_iter_array into hot and cold paths. Optimized the hot path
so that its a leaf function and tail calls the cold path as a separate function.
2012-11-13 13:43:14 -08:00
bsimmers e5f2d7b4c5 Log translation creation when TRACE=trans:1 is enabled
I used this to watch our translation rate in production and
we might want to use it again at some point.
2012-11-12 13:45:09 -08:00
bsimmers 7435197c6c Check jemaloc version in Class::alwaysLowMem
We're using a feature that's only stable in jemalloc >= 3.2.0
2012-11-12 13:44:18 -08:00
alia e42e38f55d Optimized iter_value_cell_array fast path.
Split iter_value_cell_array into hot and cold paths. The hot path is
now a leaf function that handles the common HphpArray case and tail calls the
cold path as a separate function.
2012-11-12 12:24:25 -08:00
aurelienf ba7693b0d7 Fixed stack depth computation
Stack depth computation had a number of issues. This diff introduces a new
way to compute the stack depth:

- Added a new structure, StackDepth. This structure is linked to a block of
instructions (usually starting at a label), and tracks the current stack depth
in this block. This tracking can take two forms:
  * absolute depth: the depth of the stack is exactly known for this block
  * relative depth: the depth of the stack is unknown for now. We keep track
    of an offset, relative to the depth of the stack at the first instruction
    of the block

- Each Label structure contains a StackDepth structure
- An additional StackDepth structure is created at the beginning of each
function, with an absolute depth of 0.

During the parsing process, when a Jmp instruction is encountered, the
StackDepth structure for this jump becomes linked to the StackDepth structure
of the label. The absolute depth at the label can then be inferred from the
absolute depth at the jump.

Besides being able to track precisely the stack depth, these changes also
give us the following information:
- detection of the unreachable parts of the code
- detection of some bugs (for example when two Jmps with different stack
depths target the same label)
2012-11-12 12:07:17 -08:00
mwilliams 2cb32f62c5 Redeclared classes should fatal
In hphpc, we just didnt bother to check; as with many
fatals, the idea was that its faster not to check, and
the code should have been tested in hhvm anyway.

In hhvm, we tried to get the rules right. But the rules
for hoisted classes are very complex with lots of edge
cases; typically you have to try to define each class twice,
ignoring fatals the first time. We were bitten by a case where
the first pass correctly didnt fatal, and the second pass
was omitted as an optimization.

To make matters worse, in the cases where hhvm didnt
fatal, it ignored later definitions of a class, while
hphpc always retained the last definition.
2012-11-12 12:07:17 -08:00
bsimmers 6fe3aebdd8 Turn CLSMETHOD_BODY into a template function
I did it in preparation for an optimization that didn't pan
out, but this part seems worth keeping.
2012-11-12 12:07:17 -08:00
jdelong 14b89c0999 Some clean up in enterTC
enterTC in a release build was still making function calls
related to gremlins and tls accesses for DepthGuard.  This separates
the main code path from the handling of translation-time service
requests, and makes some of the debug-only code actually get compiled
out.
2012-11-12 12:07:17 -08:00
jdelong ce47bb63a0 Fix KindOfUninit setting in freeLocalsHelper
Typo; this should be setting m_type.
2012-11-12 12:07:16 -08:00
alia dc3d55a2cf Optimized the iter_next_array runtime helper via hot/cold splitting.
Optimized iter_next_array by splitting it into a hot part and
a cold part. gcc now generates really nice code for it. The hot part is a
leaf function that uses only caller-saved registers, so there are no frame
creation or register save overheads. The cold part is a tail function call
invoked via a jump.
2012-11-12 12:07:16 -08:00
aurelienf 7ed93036f1 Fix the doc for TRACE_SET_MOD
In the header of trace.h, when explaining how to set the module,
use the new macro TRACE_SET_MOD instead of manually setting the
static variable.
2012-11-12 12:07:16 -08:00
jdelong bd9f3761de Machine code generic return helper, and minor RetC tweaks
Replaces frame_free_locals with an asm stub.  This involves a
change to the order that we destroy locals, and destroys m_this before
destroying locals.  Also changes it so we still inline returns for
functions with AttrMayUseVV, so all calls to this helper have more
than kFewLocals to free, allowing a little less branching.
2012-11-12 11:58:22 -08:00
jdelong 1681422837 Add a line to invariants about catch entry points 2012-11-12 11:58:22 -08:00
jdelong 38b667e61b Use some more xmm in vector translator
A couple other places that are safe to use emitCopyToAligned.
2012-11-12 11:58:21 -08:00
jdelong 1ea599dacd Add assembler support for movdqu and lddqu
More xmm.
2012-11-12 11:58:21 -08:00
ottoni aab83105e4 Faster checks for string types
This diff shifts DataType values to enable a faster check for
"KindOfString or KindOfStaticString". The old sequence was a
"mov + and + cmp", which is replaced by a single "test".
2012-11-12 11:55:19 -08:00
jdelong 200640f133 Remove unused emitPropGet from translator-x64-vector.cpp
Nothing seems to use this.
2012-11-12 11:23:57 -08:00
smith 25180cd4d6 Add ArrayData::m_kind field to support easy array typechecks.
We need a better way to do instanceof checks from C++ code,
without doing hacky testing of the vtable pointer value.
This patch also moves a few other fields so ZendArray,
HphpArray, and VectorArray stay packed as well as before.
2012-11-12 11:23:57 -08:00
andrewparoski f94b35a6d7 Add syntax for directly calling a closure stored in a property
When a closure is stored in a property (ex. "$o->p = function(){..};"),
there is no way to call the closure directly. Currently, if the user wants
to invoke a closure stored in a property, an intermediate local variable
must be used like so: "$cl = $o->p; $cl();".

This diff tweaks HipHop's grammar to be a little more flexible so that it
is possible to directly invoke a closure stored in an object property. If
a closure stored inside "$o->p", the closure can be invoked like so:
"($o->p)();". The parentheses wrapped around "$o->p" lets the parser know
that we are not calling a method named "p", but rather we are invoking a
closure stored in a property named "p".

This diff also introduces similar syntax for invoking a closure stored in
a static property ("(C::$x)()") or in an array inside a static property
("(C::$x[0])()").
2012-11-12 11:23:57 -08:00
bsimmers fee6bd998b Temporarily disable persistent classes
They're causing problems with some www revisions. Unfortunately I
couldn't get the problems to go away with a more precise hammer than
this, so hopefully we'll have a real fix soon.
2012-11-12 10:10:12 -08:00
bsimmers 5570bcebce Add loaded units count to check-health admin port command
This is also a number we'll care about in production.
2012-11-12 10:10:12 -08:00
jdelong 65468feeeb Don't use unary stubs in emitDecRef
Right now we jump to a register-specialized astubs block that
just jumps back to another stub that pushes a ton of regs and then
calls a destructor.  Since we're already specializing, we might as
well specialize the push code to be specific to the register allocator
state.  Still calls the unary stubs in the case that emitDecRef is
happening on astubs.
2012-11-12 10:10:12 -08:00
jdelong ef232baa66 Minor cleanup (dead typechecks and move stackOverflowHelper)
Put the stackoverflow helper at the end of the astubs helpers
(it should be rare), align callToExit, remove some dead typechecks,
and remove an unused tv_helper.h function.
2012-11-12 10:10:12 -08:00
jdelong 1cc1726dd5 Use movdqa for CGetProp
We know that object properties are aligned, so we can use
these to copy them to the stack.
2012-11-12 10:10:12 -08:00
jdelong 5ba214b02d Use movdqa to copy TypedValues in RetC
Instead of a pair of loads and stores.
2012-11-12 10:10:12 -08:00
jdelong f0a6bca295 Basic support for movdqa in asm-x64.h
Adds support for loads and stores.  Reg-to-reg moves should
be easy on top of this but aren't added yet.  Also fixes bugs when you
use rbp or r13 with cmp_imm8_disp_reg8, and adds assertions about rsp
and r12 (which it also doesn't handle correctly).
2012-11-12 10:10:12 -08:00
bsimmers 957429a43c The array_issetm_* helpers can reenter 2012-11-12 10:10:12 -08:00
Owen Yamauchi cdc320b6a3 Fix PreparableStackTestCase
My big diff changed the way getOrigFuncName behaves for non-static
method continuations. It should return the classname of the continuation's
$this, not the classname where the method is actually defined.
2012-11-12 10:10:11 -08:00
bsimmers 04f262442d Optimize FPushCtorD for persistent classes
When we construct an object of a persistent class, all sorts
of things are known at translation time. This diff takes advantage of
most of those. I'm sure there are a few more tweaks I can do but this
is a good stopping point for one reasonably sized diff.
2012-11-09 11:10:44 -08:00
Lionel Touati 2a310d778e Declare informational psuedo-ini options for APC
APC is always "enabled" even from CLI, and may or may
not stat depending on Repo.Authoritative mode (or being HPHPc)
2012-11-09 11:10:43 -08:00
bsimmers ae76940c42 Use ReplayTransport to replay warmup requests before accepting connections
This allows us to specify requests that will be used to warm
up the runtime before accepting real requests.
2012-11-09 11:10:43 -08:00
Sara Golemon 83cf387e10 Generate meaningful COMPILER_ID/REPO_SCHEMA when not on git
Currently if HHVM is built outside of git, the COMPILER_ID
and REPO_SCHEMA values will effectively be constants which
means that schema changes won't be picked up properly.

This diff works around the absence of git by using the system
time (nanosecond scale) to make a "random enough" number.
2012-11-08 11:46:27 -08:00
bsimmers ce8a8cea7a Add a check-health admin port command
This returns the current number of active requests, the
number of queued requests, and (for hhvm) the size of the translation
cache and target cache, as json.
2012-11-08 10:58:27 -08:00
jdelong b775121c39 Fix grouped returns wrt setprofile in generic translateRetC 2012-11-08 10:58:27 -08:00
Owen Yamauchi 280cee44ba Fix TestArrayForEach
I just broke this with my foreach-reset fix. This change may seem hacky but it
makes semantic sense to me: it's OK to "rewind" a continuation to put it at the
beginning (i.e. run it till the first yield if it's not been started) but not at
other times.
2012-11-08 10:58:27 -08:00
Owen Yamauchi 85ad77020d Fix foreach transformation in generators
foreach is supposed to reset the iterator at the beginning, and the way we
transformed foreach inside generators wasn't doing that.

This actually generates an "impossible" parse tree but the rest of the system
doesn't seem to mind:

  ($__foreach__1 = hphp_get_iterator($f))->rewind()
2012-11-08 10:58:27 -08:00
zoel b7029811a4 Spoofy header logging in HipHop
PHP maps hyphens to underscores when populating the SERVER array,
which allows a malicious user to spoof headers which might otherwise
be stopped by a proxy.  This patch adds detection, and allows the user
to specify a rate limit, Log.HeaderMangle.
2012-11-08 10:58:26 -08:00
bsimmers 6a556e6704 Don't initialize MInstrState for statically known SetMs
This only saves one store since we no longer sub/add %rsp for
each vector instruction, but it can't hurt.
2012-11-08 10:58:26 -08:00
mwilliams 430fd09029 Fix an issue with constant control flow
After an optimization to deal with known-to-be-constant
conditionals, the emitters virtual stack could become
unbalanced due to emitting code for unreachable expressions.

This fixes it, by skipping the unreachable code.
2012-11-08 10:58:26 -08:00
smith d1626aa21c Fix missing initialization of m_pos from NewTuple arrays
When you add the first element to an array, its internal m_pos
is set to the first key.  Need to do this in the NewTuple constructor
for HphpArray.
2012-11-08 10:58:26 -08:00
ottoni 8d3d2e67ae Relax guards for SetL
Add initial framework for relaxing tracelet dependencies, and use it for SetL.
2012-11-07 08:31:40 -08:00
kma 6076bb6bca call/ret for FCall/RetC.
Use the hardware's call/ret instructions for FCall and RetC.
Since we don't want the C++ stack unbalanced for long stretches,
we call, then pop the return value and store it into the ActRec
in the call destination. RetC loads the return address, pushes,
and ret's.
2012-11-07 08:31:40 -08:00
njormrod 6f16b1e953 cgOpEq for Objects/Resources
Type::Obj can refer to either an object or a resource. Now that
that distinction is made, cgOpEq for Type::Obj works.
2012-11-07 08:31:40 -08:00
mwilliams 408927f322 Better code padding
Dont pad one-time service requests
Often only the immediate needs to be padded in a Jcc, so dont force
the entire Jcc to be smashable.
For a jcc+jmp, we only need the two to be smashable individually.
2012-11-07 08:31:39 -08:00
smith f8ed3e6c90 Inline nvSet and streamline nvGetCell
Except for a TypedValue->CVarRef cast, ArrayData::nvSet() and set()
are identical, so do the cast inline and eliminate two more virtual methods.

All of nvGetCell's callers except one passed in error=true, and
converted a NULL result to KindOfNull.  So refactor the outlier
to use nvGet(), then streamline nvGetCell by returning init_null_variant
if the key does not exist.
2012-11-07 08:31:39 -08:00
ottoni 64ea4d2378 Fix outputDependsOnInput for OutIncDec 2012-11-07 08:31:39 -08:00
mwilliams 6ef1086622 Use visitIfCondition for loops
visitIfCondition visits a conditional expression in
such a way as to avoid creating unnecessary temporaries,
and collapsing logical nots as it goes.

But we weren't using it for the conditions in loops.
This fixes that, and also expands it to recognize constant
conditions and emit constant branches for them.
2012-11-07 08:31:39 -08:00
ottoni 151ecf6b1c Add missing output types to outputDependsOnInput
This doesn't seem to have been kept up to date as new output types were added.

Don't use default in switch statement so that it won't compile if people
forget to update this again.
2012-11-06 11:11:14 -08:00
bsimmers e1f1d717d8 Use byte-sized tests where possible in the translator 2012-11-06 11:11:14 -08:00
bsimmers 06ea4d6ec8 Use a bitmask for common classes and interfaces to speed up instance checks
During warmup requests, the interpreter keeps track of the most
commonly used names for InstanceOfD and VerifyParamType. The first time one of
these instructions is translated, this information is used to assign each of
the top 127 of these names a bit in Class::m_instanceBits. This allows for
very efficient instance checking for classes and interfaces: if the
target name is in this new map, we can skip all the usual drama and just check
a bit in the object's Class struct. Since the bits are keyed on names and not
Class*s, they can be used in sandbox mode and for non-unique classes.
2012-11-06 11:11:14 -08:00
smith 2847b13feb Don't malloc in StringUtils::Implode or ToLower
More hot callers of malloc that can use smart-malloc
or String's ReserveString mode.
2012-11-06 11:11:14 -08:00
njormrod 3bf9c4458b Bugfixing SIMPLIFY_CMP
Tidying up and bugfixing the SIMPLIFY_CMP macro
2012-11-06 11:11:14 -08:00
njormrod 25ce06692f cgOpEq for Arrays 2012-11-06 11:11:13 -08:00
andrewcox 767bbc74d0 Fix accelerated compact protocol for negative field ids
Negative field ids in compact protocol were decoded as unsigned
shorts, then converted to int64. This stopped them from correctly
sign-extending.

This changes decodes them as signed shorts so they sign extend on
conversion to int64.
2012-11-06 11:11:13 -08:00
smith 640e20f9d5 Convert more compresion utilities to ReserveString
These api's still use malloc+AttachString; convert them to ReserveString
to avoid malloc overhead.
2012-11-05 10:19:14 -08:00
jdelong 929e5048bd Split MethodCache::lookup C++ helper into a fast and slow path
Various attempts to inline a fast path for the MethodCache
into the TC looked like they cut instructions but always lost on
icache misses.  This change makes the fast path in the C++ helper
execute fewer instructions, and seems to not hurt icache.
2012-11-05 10:19:14 -08:00
mwilliams 9d880b5e3d Func::m_shared needs to be AtomicCountable
The refcount gets updated from multiple threads at once.
2012-11-05 10:19:14 -08:00
bsimmers 63ded6d58a Make some JccBlock branches prediction friendly
I profiled our JccBlocks to see which ones are taken often
(see the attached task). If a JccBlock is taken the majority of the
time it's probably going to be causing a bunch of branch
mispredictions, so I've reorganized the lopsided ones to make the
forward jcc the uncommon case.
2012-11-05 10:19:14 -08:00
varunk c5cc0f42c1 Update IDL files for lz4 2012-11-05 09:53:36 -08:00
jdelong fdaf8a1c44 Formatting proposal for semiLikelyIfBlock
Format it more like a control structure (one less indent on
the function arg list).
2012-11-05 09:34:44 -08:00
Inez Korczynski 6f8593dcf4 Fix AutoloadHandler for Closures
AutoloadHandler::getSignature() uses the callback
name, which for closures is just Closure::__invoke
(or Classname::__invoke for other invokable classes).
Follow the array($object,$method) pattern of appending
the address pointer to the signature to differentiate it.
2012-11-04 18:08:57 -08:00
smith a56107b534 ArrayData wrappers for litstr, CStrRef, CVarRef
Create inline wrappers for the litstr, CStrRef, and CVarRef
ArrayData apis, and remove them from the implementation classes.
Now each method only needs int64 and StringData* overloads.

Added a few StaticString definitions to avoid using litstr methods,
in operators.cpp, ext_error.cpp.

Fixed a bug in the compiler to convert literal bool keys to int,
rather than relying on HphpArray doing it internally.

Later patches will clean up callsites that already have StringData*
so they don't have to use StrNR or other such wrappers.
2012-11-04 18:08:57 -08:00
Owen Yamauchi 3b96353ea0 Make strlen() an opcode
It's the second most-called builtin in production (after idx()) and the common
case of a string argument is incredibly simple to implement (pull the m_len
field out of the arg, decref) so let's jit it.
2012-11-04 18:08:56 -08:00
Sara Golemon 46f8b85a9a Update ext_hhvm generator to catch more ext source files 2012-11-04 18:08:02 -08:00
philipp e840adde0f support compact protocol v1 in thrift_protocol_read_compact
Product uses v1 to store hitdata and docdata in indexes,
but ##thrift_protocol_read_compact## currently supports only v2.

This diff adds reading and writing support for
compact protocol v1.
2012-11-04 18:00:03 -08:00
bsimmers b069c4c67e Use smart_malloc/smart_free when possible in preg.cpp
preg_match_impl was showing up in perf as the top cause of
dTLB load misses from free before this diff.
2012-11-04 17:03:16 -08:00
amenghra 31153c3fbd Add a "silent type"
We would like function foo(@int $x) to be equivalent to not having
any type information (i.e. equivalent to function foo($x)).

For now we are going to silently drop the type. At some point in the future,
we'll keep the type information around and log mismatches (but unlike a normal
type hint, we don't want to fatal in case of mismatch).

This kind of silent type is going to be useful to automatically migrate code
from php to hack.
2012-11-04 17:03:16 -08:00
mwilliams 730d85e7a1 More compact FPush/FCall code
Although the code was already using 32 bit moves when the
TCA's/Func's and Class's were in low memory, it can instead
do store immediates for those cases.

Also, for directly bound builtins, we were incrementing rbx
twice. Combine the two increments.
2012-11-04 17:03:16 -08:00
kma 8dde30875e Huge pages for low_malloc.
Low-memory items are likely to be long-lived, and randomly
accessed. Map them with huge pages.
2012-11-04 17:03:16 -08:00
amenghra 83b54eec95 Hack: add support for class Foo<T as X>
We often need the ability to constrain the generic parameter T.
2012-11-04 16:44:02 -08:00
ottoni 2aeed3d6c0 Pass HPHPc's function return types to HHVM
HPHPc can often infer function return types, although those types might
not be 100% accurate because values can also be Null.  This diff stores
those types in the bytecode meta-data and uses them in the JIT to
generate better code.

In the general case where values may also be Null, the information is
passes as a prediction.  In some cases, HPHPc guarantees that the type
is Null, so these cases are passes in as inferred and not predicted to
save the check altogether.

Also, if HPHPc's predicted type is not ref-counted, we know for sure that
the values is not ref-counted (because it's either that type or Null).
So use that fact to avoid generating any code for PopR in those cases.
2012-11-04 16:44:02 -08:00
bsimmers b532cedf6a Handle empty string types 2012-11-04 16:44:02 -08:00
bmaurer 0323a843a7 Remove unused log types
I'm trying to do a cleanup of some of our logging code, and as a first
step, I'd like to clear out some unused logging functionality. This
removes Log Aggregator (AFAIK, this has not been used at least recently
we have other infra that does the same stuff) and the ability to log
to syslog (never going to be used)
2012-11-04 16:43:25 -08:00
smith eac15a544b Remove some dead code in type_variant.h 2012-11-02 13:44:07 -07:00
alvins dcf17d3d25 Added context for InvalidDerivation error
Added additional context when throwing the InvalidDerivation
error
2012-11-02 13:44:07 -07:00
bsimmers 35df965a65 Add a comment explaining fuseHalfBranch
I forgot to do this before submitting the previous diff.
2012-11-02 13:44:07 -07:00
Sara Golemon 76639bb631 Do not overwrite src/util/safesort.h's license header. 2012-11-01 11:18:24 -07:00
kma 29a2db1b7b Better memcpy.
Looking at the contents of icache ways at evict time, little
fragments of __memcpy_ssse3_back are all over the place. In the version
of glibc we're using, this routine is staggeringly general, and contains
carefully unrolled and tuned loops for every x86-64 civilization has ever
seen. Its final weight is around 11KB.

This is a tuned memcpy for our hardware. It assumes the presence of
movdqu instructions. Since it is statically linked into our binary, we
don't consume a TLB entry for its PLT entry.
2012-11-01 10:42:43 -07:00
kma 5bd50b9927 Fix a stack parity buglet.
Using sse 4.2 from memcpy exposed a stack parity bug here.
2012-11-01 10:42:43 -07:00
bsimmers 2a62a7b69e Add an admin port command to get the static string count
Sometimes I want to know how many static strings are
currently registered in our map.
2012-11-01 10:42:42 -07:00
bsimmers b4f830d90b Pull AttrStatic into MethodCache's entries
Reading m_attrs from the Func was causing a bunch of dTLB and
L1 dcache misses, so pack it into a bit in the targetcache entry.
2012-11-01 10:42:42 -07:00
dihde 552e2715fb fix "cafile" stream context arg in hhvm
Copy/Paste typo
2012-11-01 10:42:42 -07:00
Owen Yamauchi eca0898500 Inline generator stack frames into Continuation body
- The generator body's ActRec, locals, and iters live in the Continuation
  object. The eval stack itself is still on the main stack. Moving the actual
  eval stack turned out to be really hard. It's also not necessary until we
  decide to support yield-as-expression.

- The Switch at the top, and the parse-time transform of yield-inside-foreach,
  are still there. Those can be gotten rid of separately.

- The FPushContFunc-This-FPassC-FCall sequence is gone, replaced by ContEnter.
  RetC is no longer emitted in generator bodies, replaced by ContExit. The new
  instructions are very simple; all they do is frame linkage and a jump into, or
  out of, the generator body.

- PackCont and UnpackCont are still around, but they're also greatly simplified.

- Unwinding, stack printing, and translator fixups needed a bunch of tweaking,
  and a bunch of asserts needed to be weakened or removed. These are the
  messiest parts of the diff.

- The one really gross part of this is the magic number just after the
  Continuation's AR. I use this when tracing the stack. The trouble is that an
  FP pointing outside the stack may now be pointing at a Continuation's AR, or
  into the C++ stack. This is the most "reliable" way I could find to
  distinguish the two cases. Is there a better way? I figured there must be some
  sort of API to tell where the C++ stack is mapped in, but I didn't find one.

- The changes are mostly unimplemented in the IR. The tests pass, because
  everything punts.

- Continuation is now a final class. The {Function,Method}Continuation
  subclasses are gone.
2012-11-01 10:35:48 -07:00
mwilliams 66ef317a5d Improve function prolog guards
The prolog guards were optimized for the case of an
8 byte Func*. Now that we expect them to be 4 bytes,
optimize for that case, reducing the guard size from 23
to 14 bytes, and from 4 instructions to 2.

In addition, store the unguarded address in the Func's
prolog table; in the truly polymorphic case, when the
guard complains, we dont need to check again after
looking up the correct function in the prolog table.
2012-10-31 00:52:43 -07:00
andrewparoski ca5097c7ab Make sort builtins faster
HipHop's current implementation for sorting PHP arrays is a bit unweildy,
with a lot of plumbing and layers of indirection that make it slow. Also,
the sorting algorithm used (zend_qsort) is relatively slow.

This diff delivers a more streamlined implementation for sorting PHP
arrays. Sort APIs were added to HphpArray and ZendArray, which allowed for
data-structure specific semantics for sorting a PHP array in place.
ZendArray works by creating an auxillary buffer of Bucket*'s, sorting the
buffer, and then rewiring the array's linked list. HphpArray works by
directly sorting the element store in place.

Both ZendArray and HphpArray do an initial pass over the array to do some
preparatory work before the sort algorithm runs. For sorts that use builtin
comparators (sort, asort, ksort, natsort, natcasesort), the types of values
are also observed during this first pass. Running the home page with some
simple instrumentation, I found that ~94% of these sorts invovle all
strings, and ~5% of these sorts involve all integers. By observing the
types during this first pass, we can use a specialized comparator for these
common cases and avoid performing type checks during the actual sort.

For now I've only updated sort, asort, ksort, usort, uasort, uksort,
natsort, and natcasesort. It might be nice to go after array_multisort and
collator sorts at some point in the future, though I'm not sure how much
that will matter for overall performance.
2012-10-31 00:52:43 -07:00
amenghra 5c4280d236 Add support for Hack's "this" type.
"this" is useful in code like this:

class Foo {
  public function f1(): this {
    ...
    return $this;
  }

  public function f2(this $x): void {
    ...
    do something with $x
    ...
  }
}

The first case (f1) does not require a grammar change, since the return type is dropped. The second case
however requires this diff, so that the runtime doesn't fatal:

HipHop Fatal error: Argument 1 passed to Foo::f2() must be an instance of this, Foo given
2012-10-30 22:53:39 -07:00
bsimmers dfc4ca8ccd Emit better mid-tracelet guards when possible
Mid-tracelet variant guards account for some nontrivial
amount of our branches to astubs. If we need to take a side exit
because of one of these and there are no dirty registers, we can emit
a very compact inline side exit. And if the current instruction
doesn't have a stack offset we can just emit a single jnz straight to
the destination.
2012-10-30 22:53:39 -07:00
bsimmers f23f37fd21 Clean up outLocal handling in vector translator 2012-10-30 22:53:39 -07:00
kma e832ca5ab4 Some fixes for running under Pin. 2012-10-30 22:53:39 -07:00
kma 0f10774989 Trace past jmps.
A fair number of jmps from try blocks, if's, ?:'s, etc.
artificially break tracelets. We might as well keep tracing through them.
2012-10-30 22:53:39 -07:00
kma 88b86f0fb8 Inline wouldCall into the only site that uses it.
wouldCall turned up on radar for icache misses. Since it's only
called from one, hot site, its body might as well be inlined there.
2012-10-30 22:53:39 -07:00
Sara Golemon ab798ead17 Add lz4compress to hphp
LZ4 seems to have better compression & decompression speed than qlz/etc
- http://code.google.com/p/lz4/.
2012-10-30 22:31:24 -07:00
mwilliams ec2823f813 Fix sp when FCallArray target is intercepted
If the target of an FCallArray was intercepted, and the
intercept handler decided to skip the original function,
we didnt update $rbx, leaving an actrec and the parameter
array on the stack.

The whole system was surprisingly robust against this. If an
exception was thrown, and the register state was dirty (the
usual case) we would recover. But if, eg, we re-entered and
threw an exception we would double free the array, and attempt
to free the ActRec as if it were Cells.
2012-10-30 10:34:19 -07:00
kma b97e7af311 Compute live and dirty ranges for program locations.
Tx64 has always been a purely greedy register allocator, hoarding
as much program state as it can in registers. This makes our occasional
trips off the main trace more expensive; they must save all dirty state,
and restore all live state.

So, let's finally cave and implement live and dirty range tracking. At
instruction boundaries, shoot down any dead registers.
2012-10-30 10:33:56 -07:00
bsimmers 59970dfe63 Don't treat tvScratch as a Variant in member_operations.h
tvScratch often contains garbage, so it's not supposed to be
decreffed or treated as a Variant. IssetEmptyElem was using
tvAsVariant on it, causing a bunch of crashes.
2012-10-30 10:33:44 -07:00
amenghra bb06a5343f Ugly fix to the grammar to accept (string) when we want a (type)
This case can happen when a function takes a function as input:

function f1((function (string): int) $f): int {
  return $f("hello");
}

I talked to pad about "fixing" the lexer and having grammar rules for the casts. At the
end, it's going to be more work and just as ugly since we have methods called
"string" or "int".

A possible solution to these ambiguities would be to force constants to be capitalized, variable names
to start with a lower case letter, etc. I don't think such rules would play well with our goals to
be php-compatible.
2012-10-30 10:33:44 -07:00
bsimmers 2a6769e2f1 Use InstanceOfD's inline fast path in VerifyParamType
VerifyParamTypeSlow was one of the most frequently called
helpers. Its fast path is mostly the same as InstanceOfD's fast path,
so let's use that code here as well.
2012-10-29 11:11:44 -07:00
bsimmers a441caa046 Debugging helpers, type assertions, a little cleanup
- Add some more functions to print information about the current state
  of things
- Add some more assertions about types
- Move the translation for VGetG back to translator-x64.cpp (it's not
  a vector instruction)
2012-10-29 11:11:44 -07:00
bsimmers 5148fdf96b Clean up emitInterceptPrologue
This new version uses two fewer bytes and should be more
branch predictor friendly. I don't expect it to affect production
performance but I started an experiment to approximate its effect when
intercepts are turned on.
2012-10-29 11:11:44 -07:00
smith c5028b5d96 Add nv* virtual methods to ArrayData.
Adding implementations of the nv* virtual methods to ArrayData
lets us remove the IsHphpArray branches along the hot path in
various helpers.  They're implemented genericly in ArrayData.

Of the various ArrayData subclasses, only SharedMap and
NameValueTableWrapper are accessed frequently enough to deserve
specialized implementations (especially SharedMap).

This diff also factors out the calls to raise_notice() into
helpers in ArrayData that the various subclasses can all share.

IsHphpArray() is now only used in a few ASSERTs, so I reimplemented
it in terms of dynamic_cast.  I think we can rip it out in a future
diff, although the JIT still needs a fast is-hphp-array check to
guard inlined nvGet operations.
2012-10-29 11:11:43 -07:00
jdelong b9c4561121 Move thread prefixed logging inside mutex
This is probably what it was supposed to be.
2012-10-29 11:11:43 -07:00
Owen Yamauchi 806721b712 Get rid of alignment gaps between test and jcc
Put some more test and jcc instructions next to each other.

I discovered this oddness with emitCondJmp: it emits a jcc immediately followed
by a jmp, and it forces them to both be on the same cacheline. This could result
in more alignment gap than we need, maybe. Is this necessary for correctness, or
is it OK if the jcc and jmp have a cacheline boundary between them? We already
overwrite them separately and non-atomically anyway.
2012-10-29 11:11:43 -07:00
bsimmers 2a851bfccd Speed up InstanceOfD's translation
- Don't use UnlikelyIfBlock since the thing it was checking is
  actually pretty likely.
- Call different slow path helpers based on whether or not the
  candidate class is probably an interface.
- If the candidate class is unique and not an interface/trait, use
  Class::m_classVec in an inlined fast path.
- Fuse all the branches when applicable.
2012-10-29 11:11:43 -07:00
kma 82714a8ee5 Skip the tv_release_X middlemen for destruction.
This was showing up in production icache load miss profiles.
We only had tv_release_X because we were too lazy to implement C++
linkage, so get one extra cache line out of our working set by skipping
them.
2012-10-29 11:11:43 -07:00
kma e7831ce10e Don't lock when touching already-defined constants.
Some vtune output showed that we were piling up on targetCache's
lock when running wordpress. Since this failure mode could plausibly occur
during warmup of the translator, and if we were falling back to the
interpreter for defines, avoid the lock when doing successful named
lookups.
2012-10-29 11:11:43 -07:00
aravind 1b0b11314e Reuse service request stubs 2012-10-29 11:11:43 -07:00
bsimmers db827a70d3 Supported enregistered string and int keys in the vector translator
This diff modifies the vector translator to pass integer and
string keys to the helper functions in registers, instead of as
pointers to TypedValues. It causes a bit of code bloat with a whole
boatload of templated funcitons but appears to be a net win. The
primary benefits should be slightly smaller translations and fewer
branches in the helper calls (since the key time is determined at
compile time)
2012-10-26 09:18:26 -07:00
psnell 895c89700b Make pseudomains have fixed context.
Pseudomains are now cloned for each context that they appear in
(when they are included), so we can always assume that the
context never changes.
2012-10-26 09:18:25 -07:00
Owen Yamauchi 75fd3dbf46 Move a test right before a conditional jump
I surveyed all of our cmp and test instructions to make sure they come right
before the jcc or setcc instructions that they drive, because processors
apparently like it that way. This is the only one I found that has non-nops in
between. There are several examples of cmp-nop-jcc, which is due to alignment
gaps and can be fixed separately.
2012-10-26 09:18:25 -07:00
njormrod 8cac4a937f Added cgOpEq for string with int
== and != no longer punt when given a string and an integer (in
either order)
2012-10-26 09:18:25 -07:00
asukhachev ac07a15362 Fixing debug_zval_dump()
Initially I thought the culprit was the ref-vs-nonref argument semantics
inside debug_zval_dump(), but after some digging I think the reason is
that m_refCount and m_referenced are not always initialized when
  VariableSerializer::write(CVarRef v)
is called.
2012-10-26 09:18:25 -07:00
mwilliams 6c8cbc2af9 Make some classes/funcs persistent 2012-10-26 09:18:25 -07:00
kma 206fb7ea6c Align func prologues to cacheline boundaries.
Func prologues are bulky entry points. We want them to reside on as
few cache lines as possible. Also, rename breaksBB to breaksTracelet,
which is epsilon more accurate.
2012-10-26 09:18:24 -07:00
jakubv 6239350749 Fix UseUndeclaredConstant in exception.php 2012-10-26 09:18:11 -07:00
kma f5b2b98c50 Inline classof (single caller).
Inline classof; it only has one dynamically important caller.
2012-10-26 07:26:35 -07:00
aravind 8e7576e39c Hack to get LLC counters working on more cpu types 2012-10-26 07:26:35 -07:00
mwilliams 721e90d970 Fix an incorrect ASSERT
It was asserting on the wrong instruction.
2012-10-26 06:13:31 -07:00
alia 63c5aa8317 Cleanups to codegen.
Deleted unused code and parameters.
2012-10-26 06:13:31 -07:00
mpal f7dc613172 IR, reset SrcRec's vector of inProgressTailJumps after a codegen punt
Capture the number of entries in the SrcRec's m_fallbackJump
vector and if IR trace generation fails, throw away the
entries added at the beginning of trace generation.
2012-10-26 06:13:31 -07:00
andrewparoski 56fab8e80a Fix StableMap::toKeysArray
Fix silly bug in StableMap::toKeysArray() where ints and strings were
mismatched.
2012-10-26 06:13:30 -07:00
bsimmers d221e3f597 Improve UnlikelyIfBlock profiling
TRACE=unlikely:2 will key the hits on (function, opcode)
instead of just (function), and unlikely:3 will spit out the same data
as 2 but in csv format.
2012-10-26 06:13:30 -07:00
alia 97c842d637 Fixed a bug in checking whether rdi is live.
We incorrectly used the register name for rdi in a masking operation.
2012-10-26 06:13:30 -07:00
alia a8e5130499 Added aggressive ref count asserts to generated code.
Added a new IR node for asserting refcount values. This IR node
is added to every instruction that generates a ref counted type.
2012-10-26 06:13:30 -07:00
smith bd09ca1bac Streamline HphpArray fast paths
Streamline fast-paths and out-line uncommon paths in HphpArray,
to improve icache locality.  Several functions called allocElm()
after resizeIfNeeded(), causing a redundant full-check.  A few
other functions were inlined too much causing code bloat; even
though they're hot, the inlined copies were big and not any more
specialized from the inlining.

* made find() and findForInsert() non-inlined functions
* inline the fast path of findForNewInsert but outline the
search loop.
* factored the allocElm()/nullcheck/resize pattern into a
newElm() function, with the uncommon (full) case out-of-line.
* split initElm into initElmStr and initElmInt, for clarity.
* made copyImpl() out-of-line
* made nvBind() inline since it's just a tail-call to a helper.
2012-10-26 06:13:30 -07:00
jdelong 840fd01efc Put a ud2 in front of the int3's on unreachable code sections.
They are 2-bytes long, so we can only do it when it fits.
2012-10-23 11:32:57 -07:00
kma cd09336ee4 Dedup some big array helpers.
hphp_array.o is really large, and seems to be blowing out
icache. Some of the biggest helpers were these glue layers for the
translator; we had multiple copies of a 1.8KB routine in array_getm_is*,
for instance.
2012-10-23 11:32:57 -07:00
amenghra 4e59876d88 Modify hphp.x to allow optional xhp as function/method return types.
This change allows us to write:
  function foo(): ?:x:base {
    ...
  }
2012-10-23 11:32:57 -07:00
mwilliams 7664eeb4ce Add an opcode for bare-this
When "$this" is used outside ObjectContext, we would create
a local to hold it. This meant an incRef and decRef for every
invocation of such a method. In addition, "return $this" would
push the local onto the stack, incrementing the refCount, and
then the RetC would decRef the ActRec's $this.

This diff adds a BareThis opcode, which is used in preference
to the local except when the local is passed by reference, or
there are dynamic variables present.

It also special-cases isset($this), is_null($this),
return $this and $this instanceof Cls, to avoid the
refcounting in those common cases.
2012-10-23 11:32:56 -07:00
alia a35b7e416e Fixed bug in checking for MaxHHIRTrans.
TranslatorX64::hhirTraceStart was being called incorrectly when
EvalMaxHHIRTrans was being reached. This had a side effect of emiting code
into astubs.
2012-10-23 11:32:56 -07:00
je@fb.com 7798145279 Tune jemalloc.
Tune jemalloc to use a single arena, and to thread-cache large objects
up to 64 KiB.
2012-10-23 11:32:56 -07:00
jdelong 21070630c5 Align non-fallthrough traces to a cache line size 2012-10-23 11:32:56 -07:00
je@fb.com 0f83af8a41 Fix ZipFile::readImpl().
Fix ZipFile::readImpl() to convert negative gzread() results to 0.
2012-10-23 11:32:56 -07:00
Sara Golemon 5487f9be84 Add MySQL.Socket configuration option
Override default MySQL unix domain socket for
databases running on localhost.
2012-10-20 09:13:31 -07:00
njormrod 61a3d8fb9d simplyConv const int -> string
added the simplifier case for cgConv a const int to a string
2012-10-20 09:13:31 -07:00
bsimmers 85c5b819c3 Profile how often UnlikelyIfBlock branches are taken
I hacked this up to collect data for the attached task but it
might come in handy later as well. Doesn't affect code generation when
disabled.
2012-10-20 09:13:31 -07:00
bmaurer 728df2e6ee Short circuit numericCompare if one of the numbers isn't an int
I'm hoping that most comparisions are either against a static string
or one that has already proven not numeric and that we can avoid a
bunch of expensive calls.
2012-10-19 15:00:00 -07:00
ottoni 7f7b9c28ca Don't inc-ref result on the stack before potential side exits
Also fix problem in HhbcTranslator::emitVerifyParamType where the same
exit was being reused in two places but code is emitted between them.
2012-10-19 15:00:00 -07:00
Sara Golemon cbf73baf1b Version-guard newer datetime features for older timelibs
Enable use of pre 2011.1 timelib in ext_datetime
2012-10-19 15:00:00 -07:00
Sara Golemon 57f063d21c Actually enable JIT by default in server/daemon/replay modes
Previous diff missed that RuntimeOption::ExecutionMode
was being set *after* the config file was loaded, so checking
ExecutionMode always yielded an empty string (and thus not srv).

Also removed from unnecessary duplicate code.
2012-10-18 22:14:05 -07:00
njormrod dd7d2d0402 Added Conv string->int
Implemented cgConv for src:string, res:int
2012-10-18 22:14:05 -07:00
bsimmers 71ab56e279 Debugger fixes/cleanup
The various debugger classes with worker threads need to wait
for the worker thread to finish before destroying the AsyncFunc
object. I also added a bunch of logging to make figuring out exactly
what went wrong easier.
2012-10-18 22:14:05 -07:00
Vardhan Mudunuru a054f2cd3b Fix for hphp_gettid() implementation
Redid the system files update, and now it builds.
2012-10-18 22:12:17 -07:00
Sara Golemon 833d8caf43 Support stream_resolve_include_path()
Code copy of fb_could_include(), but returning
the string rather than casting to bool.
2012-10-18 21:54:34 -07:00
smith c206dca161 Revert prefetcht2 in GarbageList::maybePop() 2012-10-18 21:54:26 -07:00
smith 7bba7e3062 NewTuple should not be trying to allocate registers.
Mark NewTuple as manually allocating registers, since we don't need any.
2012-10-18 21:51:12 -07:00
ottoni d6d4c8bd43 When storing to locals, always store the type for strings
For string-typed locals, we can't skip storing the type even when the
old and new types are the same at compile time. That's because the
guards don't distinguish between static and non-static strings, so
translations should be general to handle both cases.

Also added checks for non-generic cells in SpillStack.
2012-10-18 21:51:06 -07:00
mpal 4e06890e5c Disable direct trace jump when jcc is eliminated during codegen
When a conditional jump is eliminated during codegen, turn off
the direct jump optimization for the associated exits by setting
the jump's data field to kIRDirectJumpInactive
2012-10-18 21:51:06 -07:00
psnell 02e6fbadad Fix private properties not showing up in the debugger. 2012-10-18 21:51:06 -07:00
kma 2817fac59e String equality can be improved.
Ben Maurer pointed out an opportunity this morning while looking at perf top
output: eq_str_str was a little too quick to resort to memcmp. It was relying
on the trinary StringData::compare(), which falls back to
memcmp(a, b, min(len1, len2)) once the easy cases have been exhausted.

If we don't care about which direction the inequality goes (as for ==, !=,
etc.), we can first test length. We apparently test unequal strings frequently
enough for this to be profitable. I'll also try comparing hashes.

This is a little rough as-is; for instance, the short-circuit test for
identical pointers in eq_str_str might not really be helping.
2012-10-18 21:51:06 -07:00
je@fb.com 2c7c564912 Add low_{malloc,free}().
Add low_{malloc,free}(), which use jemalloc functionality to allocate
objects in low memory (via sbrk(2)).  Use these functions to allocate
Unit, Class, Func, and static StringData objects, so that the TC can use
more compact addressing modes when burning in references to them.
2012-10-18 21:51:06 -07:00
alia 2cc5e283b0 Fixed bugs in property accesses, conversion and simplification, and added additional runtime asserts to generated code.
Fixed a bug in static property accesses where we passed the
wrong parameter to SPropCache::lookup. Fixed some code gen problems in
type conversions. Added a check stack that checks top of stack contents
for bad ref counted values. This is called on a function return.
Fixed a refcounting bug in int-to-string casting and CSE'ing of instructions
that produce or consume reference count.
2012-10-18 21:51:06 -07:00
smith 9204c93966 Create new bytecode NewTuple for creating simple arrays
A very common pattern for array-creation is array(<expr>,...) where
no keys are given.  Capitalize on it with an opcode dedicated to that
pattern.  Limit the arity to avoid excessively big operand stacks.
2012-10-18 21:51:06 -07:00
bsimmers 93cbbca45f Fix incorrect assumption in TranslatorX64::useTvResult
"foo()->bar += <expr>;" can produce an instruction where the
bottommost stack input is not the first stack input in
ni.inputs. useTvResult needs to be tolerant of this. I also fixed a
typo in emitPropGeneric that I found while working on literal support.
2012-10-18 21:51:05 -07:00
Sara Golemon 81cbcf7be7 Generated files catch-up. Missed these in a prior push. 2012-10-18 21:50:23 -07:00
kma 084b725c55 Kill the FuncToTCA namespace and its dependents.
I noticed this while messing with targetcache. FuncToTCA is
not used anymore.
2012-10-17 09:59:39 -07:00
mpal efdc3b9d2a Eliminate Jcc to Jmp for conditional branches at the end of a trace.
In eliminateDeadCode(), identify conditional branches at trace ends
that have a side-effect free trace exit.  Connect the trace exits to the
Jcc instruction by appending its result SSATmp* to the exit's list
of inputs and set the value to IR_DIRECT_JCC_JMP_ACTIVE.

Option -- While the SSATmp linkage works and makes it easy to visualize
with Eval.DumpIR=1, I'm considering removing it. Connecting the instrs
using the m_tca in each instruction is simpler.
In addition, linking via the result SSATmp interferes with converting
guard checks to direct branches since these operations are currently
combined with the loads.  May be better to split these into a guard
check with a label followed by a separate load.

Combine cgJmpZero and cgJmpNZero into cgJmpZeroHelper(.., cc);
Use LabelInstruction::m_patchAddr rather than m_asmAddr to anchor
the list of addresses that need to be patched to point to the label.
2012-10-17 09:59:39 -07:00
psnell 338def7024 Fixed TestReflection for real this time.
var_dumping the parameters includes a field
indicating what function they come from.
This is different between hphpc and hhvm for
closures. Now the test only shows the name
of each parameter.
2012-10-16 20:03:05 -07:00
psnell 394ae66b09 Fixed ReflectionClass::getProperties and getStaticProperties to return trait properties. 2012-10-16 20:03:05 -07:00
jdelong f16b072f3f Don't adjust rsp every time we do a generic M-vector translation
There is already enough free space above rsp due to the HHIR
spill locations.  Make this part of the ABI and take advantage of it
for MInstrState.
2012-10-16 20:03:05 -07:00
mwilliams 4dff480a2c Remove unused typedefs and an unused map from Unit 2012-10-16 19:58:39 -07:00
jdelong 5a5dd3e74f Use the SPropCache for BaseS in generic vector translations
Just hook this up in emitBaseS.  Also flags
manuallyAllocInputs on the SetS and CGetS translations.
2012-10-16 10:34:29 -07:00
bsimmers 7a468482c8 Avoid using MInstrState for statically known CGetMs
Many vector instructions don't need an MInstrState struct on
the stack to be executed. The most straightforward of these are CGetMs
with all of their offsets known at compile time, which is what this
diff adds support for. Now the generic vector translator is fast
enough that we can permanently kill off CGetMProp (I've manually
verified that the assembly output for the fast case is exactly the
same). isSupportedCGetMProp is still around for the IR.
2012-10-16 07:26:32 -07:00
bsimmers 1a6715658a Clean up register allocation for Location::This
A few of the places that used Location::This sidestepped the
normal register allocation paths. I've cleaned those up, which should
cut down on the number of times we load from m_fp->m_this. I've also
changed the manually emitted closure code to use StackSym::H instead
of emitting This.
2012-10-16 07:26:03 -07:00
psnell c8dd684b8c Added user attributes to parameters 2012-10-16 04:51:08 -07:00
chip 6e55e452df Correct ifdef check for MYSQL.last_used_con 2012-10-15 18:42:30 -07:00
psnell 479a20fb3a Allow reflection to work on closures.
This allows you to pass a closure to the constructor
of ReflectionFunction in place of a function name.
2012-10-15 18:42:17 -07:00
aravind 866b71a137 Fix InstrInfo for BindS 2012-10-15 17:45:11 -07:00
alia e2ed456543 Fixed bugs in continuations support and conditional jumps, and implemented code gen for GuardType and some conversions.
The Pack and Unpack Continuations helpers were incorrectly
not recording synch points. The DecRef for conditional jumps was being
pushed off-trace, which caused an assertion failure.
2012-10-15 17:45:11 -07:00
smith ac0051e9ea Give opcode NewArray a capacity hint
Add an array-capcity hint to the NewArray instructions, so
compiled expressions like array(1,2) or array(a=>1, b=>2)
have a shot at right-sizing the array before initialization.
2012-10-15 14:26:11 -07:00
mwilliams aacc9893b2 Fix throwing from FunctionEnter/Exit
In a really hard to reproduce edge case, fcallHelper would call
doFcall, which could then throw from FunctionEnter via
CheckSurprise.

In this case, the stack wasnt setup correctly to unwind
through fcallHelper, and the c++ exception mechanism called
std::terminate.

To fix it, I added a try catch to fcallHelper, and smashed
the return address to be the call's true return address.
This allows our unwinder to be called, and everything's happy.

While there, realized that we were swallowing exceptions from
the user profiler (basically to avoid issues like this); but
doing so was pointless, given that CheckSurprise could still
throw.
2012-10-15 14:26:11 -07:00
smith 31b9a66f4a Presize VMEC.m_constants(10000)
This array usually grows to about 8000 elements, reallocing
about twelve times along the way.  This should save some
allocation/memcpy/rehash traffic.
2012-10-15 14:26:11 -07:00
jdelong 5a7463bc56 Enregister object bases for BaseLCR
Can skip an extra check in the first propPre, but probably
doesn't have much impact.
2012-10-15 14:26:11 -07:00
kma 3d02693185 Zero targetcache with memset.
Also, make size driven by a config flag,
and madvise it away when the thread goes idle.
2012-10-15 14:26:11 -07:00
gregor ad1fbf5bd4 Improve hphpd command parsing
The commands that are interpreted as PHP no longer go through
escaping. The ones that aren't still do.
2012-10-15 14:25:27 -07:00
Sara Golemon 5b2e32ea75 Support (some) ssl stream context options in HttpClient & SoapClient
HttpClient isn't stream context aware.  Add in support
for receiving stream context options and processing relevant
ssl context options.
2012-10-15 12:17:45 -07:00
Owen Yamauchi 458d587c25 Tweak mergeImpl loop for hoistable classes
This loop seems to be a significant source of LLC load misses. To some extent
this is unavoidable, since its working set (all the classes in the universe) is
way too big for cache.

However, we can avoid doing a bunch of the same work repeatedly. The series of
pointer chases (*pre->namedEntity()->clsList()) was the major culprit, and if
all the Unit's classes are unique and defined without failure, we "cache" the
results of those pointer chases and identify them with a marked low-order bit.
We already do something very similar for the non-hoistable classes.

Also, comment a few subtle things that I realized as I worked, including a
presumably deliberate (but safe) race condition.
2012-10-15 12:17:45 -07:00
bsimmers 0a31e40633 Support a register base for properties in the generic translator
Most of this diff was pretty mechanical, just expanding
tables of helper functions. The generic translator now supports
getting properties off of a base object that's in a register, avoiding
a bunch of unnecessary stores in the <H ...> case. This also adds most
of the infrastructure necessary to support keeping intermediate values
in registers if we ever want to support that.
2012-10-12 13:18:23 -07:00
ottoni a1ec5cd81e Add support for CheckThis and CGetM for property accesses via $this
The IR was punting a lot more after these recent bytecode changes, so
handle them.

Also, make the DumpIR output more readable and less confusing.
2012-10-12 13:18:23 -07:00
mwilliams fd17e0ec27 Fix use of funcd as a flag for FPushClsMethodF
I used funcd on an FPushClsMethodF as a flag to indicate
that the destination of the call was known at compile time.

But if the FPushClsMethodF is in the fpi region of another
call that was fully bound, funcd will be set on it anyway.

FPushClsMethodF is almost always directly bound, so this
wasnt causing too much trouble. Pretty much the only time
its not directly bound is when the method doesnt exist
(including the case where it doesnt exist, but is handled
by __call or __callstatic).
2012-10-12 13:18:23 -07:00
ottoni 238cc9ba30 Fix cgLdClsCns
Don't call cgCheckUninit if type is predicted.

Also added Type::fromRuntimeType() and use it to clean things up.
2012-10-12 13:18:23 -07:00
aravind b2ad32673e Grow StringData multiplicatively on appends
Some endpoints like WebGraphQLIPhoneFeedController and
/api/perflab_graphql:feed_before do a lot of string appends, for which
we end up allocating O(n^2) memory.

When we append to a string, it is usually a good indication that
we will do more appends. This diff allocates memory for newly
appended strings in a multiplicative manner.
2012-10-12 13:18:22 -07:00
kma 76da87d958 Fix a bug in ClsCnsD type prediction.
In repoAuth mode, for unique classes, the material type of a
class constant is very strong evidence of its type. In other situations
it's just a prediction.
2012-10-12 13:18:22 -07:00
bsimmers 14a61b78f6 Add a vector base location representing $this
This diff adds a new location code 'H', representing $this in
the current frame. A new instruction, CheckThis, is used to preserve
the time at which fatals from a null $this occur. While the primary
purpose of the new location code is to further complicate the emitter
and runtime/translator, it also has the nice side effect of avoiding
about half of the increfs/decrefs we used to perform on $this.
2012-10-12 13:18:22 -07:00
andrewparoski 51c10aefb9 Update outdated .inc files and generated files
Some of the .inc files were out of date after KindOfInt32 was removed. Some
C++ functions use "int" for one or more parameters (we left in support for
Int32 parameters), and this diff updates the .inc files to reflect that.

This diff also updates a few .inc files that were out of date after the
__destruct method was removed.
2012-10-12 13:18:03 -07:00
jdelong ddbb599fb6 Add stat counters to generic property accesses 2012-10-12 11:57:10 -07:00
kma fb354ea8ad Micro-opt in inline array getm.
We can keep probing, rather than bail, if we happen to encounter a
string in our probe sequence while looking for an int. This is probably
very rare, but saving the 5 bytes of code is valuable regardless.
2012-10-12 11:57:10 -07:00
mwilliams 2bb43655da Fix a race condition
TypeConstraint's constructor is not thread-safe on the
first call. This was causing infrequent hangs for repo-
authoritative bulids.

There may be a similar issue in non-repo-authoritative
runs - but Ive never hit it. I suspect that loading
systemlib.php prevents issues. But Ive added an explicit
beginning of time initialization anyway.
2012-10-12 11:57:10 -07:00
Owen Yamauchi 59da308267 LRU-front registers returned from getReg
This was causing an awesome register allocation bug wherein a scratch register
was getting allocated on top of one already being used in the same instruction,
because the LRU order didn't reflect that it was still being used.
2012-10-12 11:57:10 -07:00
smith d7bfaeced2 Remove extra padding from newSlab()
Since we include size for the header before rounding up, we don't need
the padding in MemoryManager::newSlab().  Also clean up a few comments
while I'm in there.
2012-10-12 11:57:10 -07:00
bcsmith fe642ec3b8 Raise a fatal error on class constant redeclaration.
We weren't matching Zend behavior with respect to inherited constants.
This patch makes that happen.
2012-10-12 11:57:10 -07:00
bsimmers 9f32bd2cf7 Use HHVM_RUNTIME_REPO_SCHEMA to override repo schema at runtime
Having the same variable affect compile time and runtime was
causing confusing issues.
2012-10-11 11:46:20 -07:00
ottoni d5c47f4b32 Pass statically known strings to HHIR
The front-end may annotate some known strings in the
NormalizedInstructions, e.g. class and property names.
Pass these on to HHIR.
2012-10-11 11:46:20 -07:00
smith c9487f3502 Remove too-strong asserts
These fire; we need more test cases and fixes.
2012-10-11 11:46:20 -07:00
kma 0bed449cad Fix another subtle decref bug in this path.
We were letting diamondGuard refill rBase after calling the
helper, but the whole point of the helper was to mutate the memory backing
rBase. We push/pop rBase around the helper call, just to be certain.
2012-10-11 11:46:20 -07:00
smith 7ca1866261 Weaken checkSane() but check for null termination in data()
If a partially-initialized string is destructed (e.g. after calling
mutableSlice and writing into it), the destructor can assert.
2012-10-11 11:46:20 -07:00
kma 91919e918b Don't try to decRef rax when inlining cgetm's.
We were assuming we'd called a helper when we may not have.
2012-10-11 11:46:20 -07:00
mwilliams 4439f95fbf Minor register cleanup for vector props
Avoid dereferencing a source variant when we know the
inner type is null, since the register isnt going to
be used.

Use a LazyScratchReg instead of a ScratchReg.
2012-10-11 11:46:20 -07:00
mwilliams 83ad91782d Dont trash an owned register
SetM would dereference the register belonging to a loc
and overwrite the same register, causing issues if it was
used later. Use a scratch reg instead.
2012-10-11 11:46:19 -07:00
smith be74b8ad0b Convert AttachString->ReserveString in ext_pdo_*
Using the new ReserveString API is faster than malloc + AttachString.
2012-10-11 11:46:19 -07:00
jdelong 0a8dc966fb Fix a bug in emitPropSpecialized when doing raiseUndefProp
This was passing the wrong pointer as the base to the helper
function.
2012-10-11 11:46:19 -07:00
alia 5bf0e14ce2 Fixed support for type inference and profiling in the IR.
Passed type inference & profiling information from the
translator to the IR via the HhbcTranslator::emitCGet*
methods.Propagated type information through move and IncRef
instructions.
2012-10-11 11:46:19 -07:00
mwilliams 12747e20ba Translate FCallArray
Translate FCallArray. This adds a pointer to the Func* which
holds an address that will handle entering the appropriate
default-value funclet (or just the function body) after the
rest of the prolog has been setup.

Also cleaned up the dv-funclets, so they know the locals
are uninit-null (and dont have to guard), and to avoid
doint a surprise-check on the backward jump to the function
body.
2012-10-09 13:53:59 -07:00
njormrod 8ce5644d92 Test commit to check base Unit Test errors 2012-10-09 13:53:59 -07:00
mwilliams cb7540947b Fix usage of scratch registers
Scratch regs need to be freed, but some were being manually
allocated - and often not freed.

Switch to RAAI, and add an assert that all scratch
registers are free on instruction boundaries.

Also removes an unneeded clean/smash.
2012-10-09 13:53:59 -07:00
bsimmers 7eab9dfa43 Clean up a few inc/decrefs
I wasn't able to find any inc or decrefs that were doing
unnecessary runtime work, but these were doing some unnecessary
compile-time work so I cleaned them up. The code emitted should be
unchanged.
2012-10-09 13:53:59 -07:00
kma 5e79401caf Huge pages. Again.
MADV_HUGEMEM apparently works fine on sbrk'ed memory, which is nice.
2012-10-09 13:53:59 -07:00
bsimmers db45988e58 Kneecap VMExecutionContext::m_constants' destructor
We think calling this particular destructor was a noticeable source of
LLC load misses.
2012-10-08 19:16:33 -07:00
kma 997064ef74 Allocate more bits at a time.
We've seen a lot of LLC misses touching the bitmaps in
the target cache. I'm working on a more elaborate change
to type-segregate the targetcache, but meanwhile this
simple diff seems to capture some of the opportunity.

We know we'll be allocating a lot of these bits,
so allocate them in great, throbbing chunks.
2012-10-08 19:16:33 -07:00
smith 5d4396e347 Increase slab size to 2MiB to avoid assert 2012-10-08 19:16:33 -07:00
jdelong 5086dfd3ac Revert "Don't clean and smash regs in emitMPre"
There's a reliable assertion failure in verify_quick_jit
after this now.  (Wasn't when I first tried.)  We'll want to debug
before doing this.
2012-10-08 17:06:41 -07:00
smith 3ba5b130b4 Revert prefetch in GarbageList::maybePop() 2012-10-08 17:06:41 -07:00
jdelong fd7500bb1e Don't clean and smash regs in emitMPre 2012-10-08 17:06:41 -07:00
jdelong 2c2b64b4ca Support statically-known Class* information in more M-vector Prop operations
Get more information about statically known object types from
hphpc to the JIT.  Uses this information on intermediate prop
operations for all M-vectors, and final operations for CGetM and SetM.
Removing the old SetMProp specialization now is a win.  I also tried
implementations of the final operations for IssetEmptyProp, VGetProp,
BindProp, and UnsetProp, but none of them seemed to pay (and VGetProp
didn't work) so I'm leaving them out of this.
2012-10-08 17:06:36 -07:00
smith 12085b8887 Consolidated smart-allocators
Rework SmartAllocators so each allocator allocates fresh objects from
the single frontier in MemoryManager, but still has its own
size-specific GarbageList.

Now with smart_malloc and SmartAllocator using the same slabs,
iterating over the heap is no longer possible; sweeping and the
backup cycle gc were effected.

For sweeping, NeedSweep SmartAllocator flag was eliminated.
Strings that need sweeping are placed on a string-specific sweep list,
and SharedMaps are swept using the Sweepable mixin class.  Other objects
that needed sweeping were already using the Sweepable mixin.

The cycle collector is now disabled.  It still compiles but it doesn't
visit any objects.  Since it was not finding many cycles before, and
caused SharedMaps to "inflate", this is okay for now.
2012-10-08 17:06:36 -07:00
mpal 1b7cd7dd64 Fix typo in linearscan which allocated a register for type None 2012-10-08 17:06:36 -07:00
kma 78f3cb283d Let _count float in some more places.
At one point we had a system invariant that the _count field
of root-like TypedValue's was 0. This invariant hasn't been
buying us much, and it costs us a lot of stores.
2012-10-08 17:06:24 -07:00
mwilliams 1c5447de6c Add a bytecode to implement array_key_exists
Its a commonly used, very lightweight function; we
should avoid the overhead of a builtin call.
2012-10-08 17:06:24 -07:00
kma 2363f2cc5f Inline some int-keyed HphpArray accesses.
Stay in translator output for some simple array accesses. For
now, this just further specializes the already-specialized case of
array_getm_i. We'll build on this in subsequent diffs.

The translation inlines the *entire* array access, quadratic probe and
all. This appears necessary; only doing one probe, and then falling back
to a helper did not seem to win.
2012-10-08 17:06:24 -07:00
kma 9d76e17fed Get rid of some suspicious uses of RELEASE.
Using the RELEASE macro is, as far as I understand, a bad idea.
We usually just want !DEBUG.
2012-10-08 17:06:24 -07:00
smith 5f445072d5 Remove dead code for alternate APC implementations
The lock-based table implementations were kept around while the
nonblocking table was "baking", but it's now stable.  This removes
the lock-based code.
2012-10-08 17:06:14 -07:00
mwilliams 10b40e3f0a Dont assume the class exists in FPushClsMethodD
If the class exists at translation time, and is marked
AttrUnique we would burn in the address and assume its
always defined - but it may not be. So add the check.

hphpc does some static analysis to determine that the
class really is available, so use that to skip the check
when possible.

In addition, do some cleanup on Self, Parent, AGetC
and FPushClsMethodF.
2012-10-08 17:06:14 -07:00
je@fb.com e0187dc017 Smart-allocate MIterCtx::m_mArray.
Smart-allocate MIterCtx::m_mArray.  Directly embedding m_mArray bloats
the VM stack enough to cause an overall performance drop, so
smart-allocation is the next best alternative to straight new/delete.
2012-10-08 17:06:14 -07:00
Sara Golemon e5824bea7d Enable Eval.Jit=true when HHVM run in server/daemon mode
JIT is looking pretty stable, time to enable by
default when running HHVM across multiple requests.
2012-10-08 14:52:59 -07:00
aravind 79fd125a69 Convert more mallocs to smart_malloc 2012-10-08 14:52:59 -07:00
jdelong bff2c5d317 Keep smash requiring that regs aren't DIRTY
A change to make smashLoc clean first happened in-flight with
some comments explaining semantics of "smash", so they got
mis-matched.
2012-10-08 14:52:59 -07:00
bsimmers d81006fea1 Rip out dynamic class context PropCache code 2012-10-08 14:52:22 -07:00
bsimmers fa2b46474f Remove a bunch of VMRegAnchors from targetcache.cpp
None of these were needed, either because the function they
were calling had its own VMRegAnchor or they just needed an fp which
was being passed in anyway.
2012-10-05 22:06:58 -07:00
smith 5a373d3ab2 Prefetch next entry in GarbageList.maybePop()
This might reduce the chance of an LLC-load-miss when allocating
from a freelist in smart_malloc and SmartAllocatorImpl::alloc.
2012-10-05 19:02:37 -07:00
smith a40f2a8c96 Avoid malloc when creating strings in ext_fb
Using StringData's ability to reserve space, we can steer more
string allocation traffic to small strings and smart_malloc'd strings,
at clean up code at the same time.

This also fixes a missing request-memory-limit check in smart_realloc.
2012-10-05 16:05:15 -07:00
mwilliams 448d0e9d17 Put the translation cache in low memory
If the translation cache is in low memory, calls to c++ helpers
dont need trampolines. Also, burnt in TCA addresses fit into 32 bits.
2012-10-05 16:05:08 -07:00
bsimmers 57ef3ce17c Initial support for generators in HackIR, fix a few existing bugs
This diff adds and uses IR instructions to support all
continuation bytecode instructions (except ContHandle, which is still
interpOned like in Tx64). Because the ir doesn't support Switch yet
and supporting it might end up being a lot of work, I've added a
runtime option to allow emitting Switch that defaults to true,
unless Eval.JitUseIR=true.

I've also fixed a couple existing continuation bugs:
- The exception handler region inside Continuation::next and
  Continuation::send (under hhvm) was wrong: it's intended to cover
  the body of the generator so it should only cover the FCall, not the
  ContNext/ContSend. ContNext/ContSend were changed to not push the
  continuation on the stack so they can be pulled out of the eh
  region.
- Continuation::next and Continuation::send were setting the received
  field before performing their sanity checks. This could lead to
  wonky behavior if the current value in the received field messed
  with the Continuation object in its destructor. hhvm (jit, interp,
  ir) and hphpc now all perform the sanity checks before setting the
  value.
2012-10-05 16:05:08 -07:00
jdelong 28a5cf94c2 Make EMIT_RCALL use the passed Asm& for recording the fixup 2012-10-05 16:05:07 -07:00
smith 3f72875b6b Add room for header before rounding up in smart_malloc
If we add space for the header before rounding up, then the usable
pointer will be 8-aligned.  However, if we throw away 8 bytes at the
start of every slab, all usable pointers will then be 16-aligned.

To reduce waste, add more size-classes (one every 16 bytes up to 2KiB).
2012-10-05 16:05:07 -07:00
mwilliams dde6daf808 Dont create/destroy std::strings for literals
ConcurrentTableSharedStore logs a lot of its actions. It
passes a literal string to log_apc, which expects a std::string,
causing it to create/destroy a std::string every time (resulting
in a malloc/free).

Create a global std::string for each literal string thats used.
2012-10-05 16:05:07 -07:00
andrewparoski a4a902ee0b Generator cleanup
Fold Continuation and GenericContinuation into a single class and remove
unused fields, reducing the size of Continuation by 8 bytes for hphpc and
24 bytes for hhvm.

Also get rid of the gross MethodCallPackage/CallInfo hack for generators
as it is no longer needed.
2012-10-05 15:58:56 -07:00
kma 4e4fea31cc Let _count float in emitCopyTo.
We're explicitly zeroing out the _count field
in emitCopyTo. The destination is always an hhval,
not a Ref, so it can't matter.
2012-10-05 14:17:04 -07:00
smith 483fe296b8 Streamline copyImpl() code in HphpArray
This is a code cleanup patch to make it easier to spot
bugs and refactor code.

Numerous functions in HphpArray check to see if they must
copy the array first, then contain two whole copies of
the function body, one if we copied and one if we didn't.

There's already a coding style in some functions that avoids
the duplicated code;  this patch uses that style in the rest
of the code.

Early results show this is about 0.1% increase in CPU
Instructions but about 1% decrease in CPU Time, although
some endpoints have 1% noise
2012-10-05 14:17:04 -07:00
aravind ca6070bbe1 Remove AttachDeprecated mode for StringData
In many places we were doing malloc(size) followed
by String(ptr, len, AttachDeprecated). Update this
to use the StringData(int reserve) API.
2012-10-05 12:35:00 -07:00
mwilliams 62236bfabb Fix side-exits for incorrect type predictions
The side exit for an incorrect type prediction should
got to the next instruction; not re-execute the instruction
that just produced an unexpected result.
2012-10-05 12:34:39 -07:00
bsimmers da8dd8ea42 Minor test/ext_curl fixes
- Fail early if anything other than TestCodeRun* is run with
  an hhvm build
- Set the m_url field of CurlResource in the copy constructor
- Don't fail TestExtCurl if test_curl_copy_handle fails. I've spent a
  day trying to figure out why this is failing on Jenkins without much
  luck so far and I want to cut down on the test noise.
2012-10-05 12:34:39 -07:00
mwilliams ee2a2ce2cc emitFCallD needs to take a Func*
The function could be a method, so trying to look it
up using a passed in name could fail (and is pointlessly
expensive, since we've already determined the correct
func anyway).
2012-10-05 12:34:39 -07:00
ottoni fcd706c035 Improve side exits from HHIR to tx64-generated translations
When a side exit from an HHIR-generated translation was taken, a
BIND_JMP service request was being used, which would make it create a
new HHIR translation at the exiting bytecode. This translation would
then generate a REQ_RETRANSLATE_NO_IR to produce a tx64 translation.

This diff avoids the useless HHIR translation generated for the
exiting bytecode in case no translation for this bytecode exists when
the service request is made.  This is done through a new
BIND_JMP_NO_IR request that directly generates a translation for the
exiting bytecode without HHIR if no translation for the SrcKey exists.
2012-10-05 12:34:39 -07:00
jdelong 3e818b943c Macroify definitions of all the prop* functions 2012-10-05 12:34:39 -07:00
smith 3fa9bbbc54 Bugfix: Need to 0-terminate in CstrBuffer.data() and detach() 2012-10-03 08:50:36 -07:00
kma bd064e9938 Exploit type info in array helpers.
This is a somewhat weak optimization that pushes some type
dispatch on keys into translation-time. It's easy to do, and looks like
it might be good for 1% or so; it's in the noise, though, so take it with
a grain of salt.
2012-10-03 08:50:32 -07:00
smith c8a47b1d06 smart_malloc treatment for StringBuffer
StringBuffer only has a few use cases which require it to
either attach to malloc'd memory or produce malloc'd memory
that the client later free's.  This diff refactors those clients
so all StringBuffer-created strings can be smart-malloc'd.

string_cplus_escape() used StringBuffer internally but all callers
work fine (ne better) with std::string.  Changed MemFile and
UrlFile to use a plain String (instead of char* ptr) to avoid having
StringBuffer return a plain char* buffer.

Created CstrBuffer to handle the use case of creating a plain
malloc'd char* buffer, for dynamic_content_cache and
static_content_cache; this seemed like the least-tricky solution
and those were the only use cases for the StringBuffer(char*,int)
and StringBuffer(char* filename) constructors.

With those changes, we only need the StringBuffer(int size)
constructor and it only produces ordinary Strings.  so we have
a privat StringData instance which holds the string memory,
then we finalize it in detach().

I also renamed StringBuffer's fields to match terminology we
already use in StringData.  (size or len = valid bytes of string,
cap or capacity = usable bytes of underlying memory buffer).
2012-10-03 08:50:28 -07:00
smith 8d506996c3 Increase StringData size limit to 2GB (2^31-2).
This diff simply increases the string size limit, and cleans
up a handful of places we used int when we should have used
uint32_t anyway. This clears the way for a followup, which makes
limits StringBuffer to the same length limit as StringData.

We use 2^31-2 because the real limit is 2^31-1 (biggest unsigned
value for a signed-int length), but we want to safeguard against
the likelihood of client code computing size()+1 into a signed-int32
and wrapping.
2012-10-03 08:50:20 -07:00
je@fb.com 1194f319e2 Add translator support for objects in Iter{Init,Next,Key,ValueC}.
Enhance the translator to support object iteration in
Iter{Init,Next,Key,ValueC}.
2012-10-03 08:50:13 -07:00
smith e73906f410 Remove dead class LfuTableSharedStore
This is one of the available APC SharedStore implementations,
but its not enabled at all and the docs (circa 2010) refer to
it as buggy/experimental.
2012-10-03 08:50:02 -07:00
bsimmers 874b34e7cc Don't create a GenericContinuation subclass for each continuation
A subclass of GenericContinuation is created for each
generator function in code we emit. This was originally intended to be
an optimization to allow burning in Func*s in the translation of
FPushContFunc, but that was not a noticeable win in perflab and tricky
to get right in sandbox mode (see the attached task). This diff
changes the emitter and runtime to not generate all these subclasses,
instead just using MethodContinuation and FunctionContinuation to
allow some specialization at translation time.
2012-10-03 08:48:32 -07:00
jdelong fd937a149b Fix tread_hash_map's allocation to be the correct size 2012-10-02 22:32:40 -07:00
ottoni 48e9ceaff3 Get HHIR working with type prediction and pass more static info to HHIR
Type prediction was disabed with HHIR.  Enable it by passing the
predicted (or inferred) types to HHIR.

This diff also passes extra static analysis knowledge to HHIR:
- whether this pointer is available
- whether UnboxR is a no-op
2012-10-02 22:32:40 -07:00
mpal ace710d94e Support turning off IR's use of InterpOne when JIT will translate it
Remove unused IR function HhbcTranslator::emitUnaryArith
Add option to have the IR punt this trace back to the jit rather than
doing an InterpOne for a bytecode to get more sensible perf numbers.
2012-10-02 22:32:40 -07:00
andrewparoski ad8dc162df Support (but raise warnings) for array casts for collections
I noticed that doing an array cast ("(array)$x") on a collection will
produce an empty array (because collections currently use the default
object->array conversion and collections don't have properties).

This diff makes array casts for collections produce the same result as the
toArray() method. Array casts for collections will also raise a warning
(depending on runtime options).
2012-10-02 22:32:40 -07:00
je@fb.com 21cf29f0d2 Fix BaseS class pointer burnin.
Fix TranslatorX64::emitBaseS() to only burn in a class pointer for
unique classes, and only when in repo-authoritative mode.
2012-10-02 22:32:40 -07:00
jdelong b8ab333810 Remove a few friend declarations in Unit
For MetaHandle: a member class's member function counts as a
member of the containing class, so it has access to privates already.
The friend for the other direction appears unused.
2012-10-02 22:32:40 -07:00
jdelong bc7d0eb231 Skip VMRegAnchor for arGetContextClass 2012-10-02 22:32:40 -07:00
Sara Golemon 8cc00a93fa Auto-generate repo_schema and compiler_id on build 2012-10-02 18:39:55 -07:00
smith 6e02d7072a remove dead function SharedMap::getValueUncached(). 2012-10-01 19:37:57 -07:00
kma 07c6994a98 Choose helper reffiness with types.
Some elem/prop helpers know that their keys must be cells, but
those that use locals could get passed Refs. We know the reffiness of
the input keys at translation-time; use this type, rather than the input
flavor, to choose which helper to call. This should strictly reduce the
number of KindOfRef checks in vector instructions.

To gain confidence this was working as intended, I also factored out the
ref checks into a helper that asserts that it has stripped any refs.
2012-10-01 19:37:51 -07:00
smith a65f016fc8 Remove SmartAllocator for Array; its dead code.
Instances of Array (the smart-pointer wrapper) are never smart
allocated, so we don't need the SmartAllocator declarations.
2012-10-01 19:37:47 -07:00
mwilliams 22aef0d20f Fix various issues with the call_user_func optimization
For a call_user_func to a simple function which
didnt exist at the time of the call, we gave the
wrong info to recordReentrantStubCall, resulting
in a corrupt stack.

fb_call_user_func_safe_return didnt always return the
correct result in jitted code if the function existed
when the translation was generated, but doesnt exist
at a later call, and the default value was non-null.

fb_rename_function simply didnt work on any jitted
*call_user_func* code.

The warning for call_user_func* given an unknown function
was different between jitted and interpreted code, resulting
in verify_quick failures.
2012-10-01 19:37:43 -07:00
jdelong 1288032d42 Move some of our ABI constants to an abi-x64 header, and random code cleanup
This was extracted from my working branch on returning values
in registers, without anything related to that part of it.  It is just
a bit of code cleanup and allows sharing a few of the register
constants with the ir, and a little bit of additional documentation on
a few things.  (There are probably more things that should still be
pulled to shared locations between the two translators, and I'm sure
there's still a fair bit of distributed knowledge about which
registers are what.)
2012-10-01 19:37:37 -07:00
andrewparoski 03c8c3baee Fix get() methods for collections for the case where the key is not present
HipHop would crash when the get() method is called on a collection for a
key that was not present. Fix that.
2012-10-01 19:37:33 -07:00
kma f4938ba565 Back off on a broken optimization.
I tried to sneak this in in a code motion diff. Whoops! This
should fix an assert failure.
2012-10-01 19:37:24 -07:00
kma fff343a04d Pull vector instrs into their own file.
This is almost all code motion, though there's a slight
tweak to CGetM to avoid checking reffiness where we can eliminate
it at compile-time. Also make the VM-only helpers in translator-x64
HOT_FUNC_VM rather than HOT_FUNC.
2012-10-01 19:36:51 -07:00
jdelong 2eb5998bdc Store PreClass::Prop and PreClass::Const in-situ in IndexedStringMap
There's no need for these to be across another pointer.  I'm
just clearing out an old TODO here.
2012-10-01 14:45:22 -07:00
smith a7164c6e91 Give StringData the smart_malloc treatment
Add smart-allocation mode for strings; the CopyString constructors and
StringData(int) constructor now imply smart-allocation, and the append
function will smart-allocate if a small, literal, or SharedVariant
string is appended too.

CopyMalloc mode is now used in the few places when a client allocates a
long-lived StringData instance (with new).  These include static strings
and APC strings, plus a few odds and ends.

StringData.reserve(int capacity) ensures there's at least that much room
in the string, similar to std::string.reserve().  Not called yet, but
will be needed later, so adding now.
2012-10-01 14:45:14 -07:00
bsimmers b8af93c924 Translate all StaticLocInit instructions
We can use the fast path for class methods by giving the
cloned Func*s new funcIds (and separate translations). The remaining
cases that the inline fastpath can't handle are easily dealt with by
just calling the slowpath helper. Also fixed up an ASSERT in
Translator::applyInputMetaData.
2012-10-01 14:45:09 -07:00
Sara Golemon 4d1d9318cc Bring HPHP's datetime (nearly) up to par with Zend's
Add DateInterval class

Add methods to DateTime class
  add()
  sub()
  createFromFormat()
  diff()
  getTimestamp()
  setTimestamp()
  getLastErrors()

Add method to DateTimeZone class
  getLocation()

Add matching function aliases for new methods
  date_add()
  date_create_from_format()
  date_diff()
  date_get_last_errors()
  date_interval_create_from_date_string()
  date_interval_format()
  date_sub()
  date_timestamp_get()
  date_timestamp_set()
  timezone_location_get()

Add timezone database version info
  timezone_version_get()
2012-10-01 14:22:52 -07:00
kma 34bc4847b2 Use our conditional jmp machinery to make IterInit nice.
We were emitting slightly bad code for IterInit. The same trick
we do for other conditional branches can improve it.
2012-09-28 12:41:27 -07:00
mwilliams ac85dffb1d Fix some static analysis issues
A recent correctness fix disabled a lot of uninit detection.
While investigating the correct fix, I noticed that many
type predictions for the base of a Vector instruction seemed
to be ineffective (we still generated a guard), and that
"lvalue" vector instructions never generated the DataType
meta-data.
2012-09-28 12:41:12 -07:00
kma 4ea9123e57 Huge pages for datablocks.
We seem to benefit from using huge pages to map the TC and
targetcache. This diff checks that the kernel version is greater than or
equal to 3.2.28-72-fbk12, and if so asks the kernel for large pages.
2012-09-28 12:40:57 -07:00
kma 4fa41641f7 Fix the build. 2012-09-28 12:40:15 -07:00
Sara Golemon 2e10f2e119 Return 0 (false) instead of throwing an exception for get_magic_quotes_runtime()
There's no point fataling on a non-fatal condition.
2012-09-28 12:39:51 -07:00
mwilliams a4c5cf68f9 Make call_user_func_array less strict
If the called function expects a reference,
but doesnt get one, zend raises a warning,
and returns false, rather than executing the
body of the function.

A previous diff emulated that behavior, but we have
a lot of tests that rely on the function being
called anyway. This version still raises the
warning (so we'll hopefully get the bugs fixed)
but continues on and executes the function.
2012-09-28 12:39:34 -07:00
jdelong 6ba41f8cd6 Use smart_malloc for ExtraArgs (and use one fewer allocation)
ExtraArgs doesn't actually need to know its size, and also
doesn't need to have an additional pointer hop.  This seemed *maybe*
like a small win in perflab, but changing to smart_malloc on top of
this looks like it actually cuts instructions and even CPU noticably.
2012-09-28 12:38:57 -07:00
macvicar 31afdeb0ef Implement libxml_disable_entity_loader()
Parsing XML documents from external resources is dangerous at the moment
since they can pass us:

<!DOCTYPE scan [<!ENTITY test SYSTEM
"file:///etc/passwd">]><scan><foo>&test;</foo></scan>

to read /etc/passwd

bit of an issue is that this is an XML global, so leave it loading by
default and a function to disable it. Will test with adding it to our
standard www init stack and see if we can make it off by default.

Test Plan:
Ran unit tests and:

<?php
$string = '<!DOCTYPE scan [<!ENTITY test SYSTEM
"file:///etc/passwd">]><scan><foo>&test;</foo></scan>';
libxml_disable_entity_loader(true);
$a = simplexml_load_string($string);
var_dump($a->foo);
2012-09-28 12:34:56 -07:00
jdelong b94eb310df Use a linked list instead of a hashtable for the Sweepable set 2012-09-28 12:34:33 -07:00
smith 0dc522d022 Use ScopedMem to free optionally-gzdecoded data
This is robust against exceptions, compared to explicit free.
2012-09-28 12:03:26 -07:00
kma 630e61a25f Add a runtime option to nuke hardware counters.
Eval.ProfileHWEnable (defaults to true) can be used to keep hhvm's
grubby mits off the perf counters. This is useful for some profiling work
we would like to do with Intel.
2012-09-28 12:03:04 -07:00
kma 51d2affdd4 Share a RetC in 86cinit methods.
Summary: 86cinit methods have a lot of rets, and they all do the same basic work. This change to the emitter branches to a shared ret body.
2012-09-28 12:02:47 -07:00
mwilliams 4faa4a1f24 Autoload should not create new Strings
We were passing a StringData::data() to a method taking a
CStrRef, which causes a new StringData/String to be created.

Instead, wrap the StringData in a CStrNR, and pass that.
2012-09-28 12:02:32 -07:00
mwilliams 30c1d9e797 Add bytecode support for call_user_func and friends
By adding bytecodes, we can avoid a re-entry. In
addition, we can optimize various cases to avoid
the dynamic lookup.
2012-09-28 12:02:15 -07:00
aravind d4944f9a67 Use StringData* instead of StringData::m_data for hash lookup
For HphpArray lookups, we compare StringData::m_data for
pointer equality, and if that fails, we do a memcmp for
content equality. This diff changes it a StringData*
comparison for pointer identity, which eliminates the
StrinData::m_data dereference.
2012-09-28 11:25:25 -07:00
smith d7e894bea9 Don't use String/AttachDeprecated just to free a malloc'd buffer.
Remove one use of AttachDeprecated; all its being used for is
to optionally free a buffer; that's not so hard to do.
2012-09-28 11:25:09 -07:00
andrewparoski 92cf3ebe97 Fix reflection to correctly retrieve doc comments for generators
Calling the getDocComment() method on instances of ReflectionFunction or
ReflectionMethod was always returning 'false' if the function/method was
a generator.

This diff adds the missing plumbing in the parser to make this work
correctly and adds some test coverage.
2012-09-28 11:24:41 -07:00
ladipro 2a321c68ec Add missing error checks to copy()
HipHop Fatal error: Unexpected object type stdClass. when copy() is called
with a bad http:// URL source, for example:

copy('http://does.not.exist', '/tmp/foo');
2012-09-28 11:24:19 -07:00
andrewparoski 412af0c1c3 Fix crash involving LateBoundCls instruction
The impl for the LateBoundCls instruction was missing logic to handle the
case where there is no late bound class (ex. inside a regular function).
Fix LateBoundCls to raise a fatal error for such cases instead of crashing.
2012-09-28 11:24:02 -07:00
andrewparoski 018f5cfbcc Fix crash involving static properties with traits
Some programs that used static properties with traits would cause the VM
to crash while building the Class. Here is an example:

  <?php
  final class Foo {
    use Bar;
    private static $a = array();
  }
  trait Bar {
    private static $a = array();
  }

The crash was happening because was the m_staticProperties map of the
current class was being accessed before it was initialized. This fixes the
logic to directly read m_val from the SProp structure for static properties
declared by the current class to avoid this problem.
2012-09-28 11:23:39 -07:00
alia 88b22b96d6 Fixed code generation bugs in LdThis and in ActRec allocation for magic calls
Fixed a code generation bug in LdThis where we did not
consider the case that the LdThis target is dead but LdThis itself is
not because of its checks. This was causing the destination register
to be reg::noreg. Fixed a bug in ActRec allocation where we needed to
mask in a 1 into the lower bit of ActRec::m_invName for magic
calls. Added a check to TranslatorX64::translate to check if we have reached
the translation limit for a SrcRec. Fixed an assert in SrcRec::newTranslation
that was off by one: When newTranslation is called when a SrcRec has reached
its limit it will cause the number of translations to become
kMaxTranslations+1, so the assert must check that we are one less than that.
2012-09-28 11:23:21 -07:00
je@fb.com 85bd3df1ee Update string hashes to use MurmurHash3.
Update string hashes to use the 128-bit version of MurmurHash3
(previously used 64-bit MurmurHash2).
2012-09-28 11:01:42 -07:00
bsimmers 4436f4fdea src/test/hopt_preparable.php doesn't need 10000000 iterations 2012-09-28 10:31:17 -07:00
jan 5d5fa213e3 Fix class typehints in IDL for HPHPc
Forward declarations were missing in the generated headers if type
contained a class name instead of just Object. Add them.

Class typehints in extensions still doesn't work in HHVM, but at least
it's possible to test impact of improved knowledge of types in HPHPc.
2012-09-28 10:13:29 -07:00
andrewparoski 86cc9c8a5e Fix collection get() and at() methods
The get() and at() methods for collections were missing a cast from
TypedValue* to CVarRef, causing them to return true or false instead of
returning the value. Fix that.
2012-09-27 18:24:02 -07:00
mwilliams de32d526a3 Fix verifiability when FPass* are elided
In WholeProgram mode, we would convert FPass*
instructions to their known-at-compile-time
equivalents, and then drop the actual FPass*
instruction.

This broke verifiability. Instead, we emit the
equivalent CGet/VGet, and emit a NopOut FPass*
bytecode.

While I was there, NopOut some hand generated FPassC
instructions too.
2012-09-27 18:23:43 -07:00
andrewparoski 878cac1dea Fix multidim assignments with collections for hphpc
Expressions like "$x[0][1] = 123;" were fataling under hphpc if $x was a
collection, regardless of whether key 0 was present and regardless of the
type of value at $x[0]. Fix that.
2012-09-27 18:23:16 -07:00
jdelong f36ddb7b4b Revert "Free memory for preg and memcache"
Bisecting in h2e showed this diff is the rev that causes the elevated
stacktrace rate.  I imagine we'll want to debug and fix it but to unblock
getting an rc out for now we'll revert temporarily.
2012-09-27 18:22:00 -07:00
Sara Golemon 0d22749aa5 Update doc for Uploading options
Summary: At some point these got moved into their own node.
2012-09-27 18:20:07 -07:00
Sara Golemon dbadda9c82 Support post_max_size for ini_get()
Summary: When asked for post_max_size, return it.
2012-09-27 18:19:44 -07:00
psnell 00f1bbb3ba Modified collections to use smart allocators. 2012-09-27 18:18:06 -07:00
andrewparoski 08b4a8a69d Improve the perf of c_Map::reserve
Summary: Improve the code for growing a Map to be more efficient.
2012-09-27 12:15:37 -07:00
psnell dad7911de0 Fixed class_implements. 2012-09-27 12:03:11 -07:00
jdelong a740eb09f1 Turn pause_and_exit() into pause_forever()
Summary:
pthread_exit can lead to confusing crashes for us: it raises
a "forced unwind", which it seems (strangely) will enter into C++
catch (...) blocks: but if you don't rethrow from one these blocks,
glibc will call abort() from a function called unwind_cleanup.  Our
LibEventWorker has a catch block of this sort that doesn't rethrow, so
calling pthread_exit below there will abort the program.  (The point
of this function is to just wait while another thread writes a
stacktrace file, so there's no reason to exit the thread.)
2012-09-27 12:03:05 -07:00
bsimmers 7c67d64bca Fix order of assignment/decref in continuations and Variant
Summary:
Similar to D563995, this fixes more code that assigns a PHP
value so the new value is stored to memory before decreffing the old
value. It's more complicated but unfortunately necessary for
correctness.
2012-09-27 12:02:57 -07:00
mwilliams 20fc5e2e22 Streamline Unit::merge
Summary:
We're still spending a lot of time in Unit::merge.
This optimizes defClass and defFunc for the case
where the class/func is known to be unique. It also
fixes various issues in the emitter so that builtin
classes and functions, closures and continuations
are all marked as unique.
2012-09-27 12:01:36 -07:00
smith 77cd177e3c smart_malloc hphp/vector/zend_array
New smart_malloc/free api for variable-size smart-allocation.  Memory
allocated with smart_malloc can be freed with smart_free, but otherwise
is swept at request-end.  Allocations underl0 1K are bump-allocated from
slabs with an 8-byte header.  Over 1K are routed to malloc with a
16-byte header (doubly-linked list).

ZendArray, VectorArray, HphpArray refactored to use smart_malloc instead
of a bunch of storage-segregated size classes.
2012-09-21 13:46:55 -07:00
Joel Pobar f62a1b209e Use libcurl 7.28.0's curl_multi_wait() or fallback when curl_multi_select not available
Removes the need to patch libcurl and build a copy
explicitly for HipHop.

If libcurl >= 7.28.0 we get the new curl_multi_wait() function.
If not, we either get the patched in curl_multi_select(), or a
fallback which works for FDs < 1024, but fails (with an error
message) for sites which use more concurrent FDs.
2012-09-21 13:46:41 -07:00
Sara Golemon 249aeaba8d Rename bin/gen_system_files.sh to a more generically appropriate name 2012-09-20 17:58:26 -07:00
Sara Golemon 1f553118f4 Add helper script to created generated files 2012-09-20 17:52:22 -07:00
jdelong 10cbc45d15 Fix bug in DebuggerClient's use of Sweepable Socket objects
DebuggerClient attempted to avoid problems with destructing
Socket objects by calling incPersistent so they would not be swept.
However, the semantics of incPersistent apparently require that the
object only is persistent in some sort of thread-local cache (it is
re-added to the sweepable list for the same thread immediately).  When
we disconnect the debugger, the DebuggerClient is deleted and the
socket object is also destructed---the Sweepable destructor tries to
remove it from the current thread's list, so if this is a different
thread, the next sweep loop on the original creating thread will make
function calls on a deleted object.
2012-09-20 13:51:33 -07:00
smith 54ded9ef86 Move the siPastEnd flag into a spare bit in m_strongIterators
Each subclass of ArrayData needs a flag to track whether there's
a strong iterator past the end of the array; use a spare bit in
m_strongIterators to store the flag, and consolidate more strong
iterator code in class ArrayData.

This will also aid in packing fields in subclasses.
2012-09-20 13:51:33 -07:00
smith e725c4c15a Fix leak in safe_free()
safe_free() was so safe, it was a no-op.
2012-09-20 13:46:05 -07:00
mpal 1c635d3d1d Initial IR work
Initial merge of IR (Intermediate Representation) tree.
2012-09-20 13:29:01 -07:00
Sara Golemon 582eb85302 Enable C++11
Moving forward, these compiler features will be required for
IR and other features in the pipeline.  Compilers which do not
support C++11 features will be incompatable.
2012-09-20 13:25:41 -07:00
jdelong 7daf9dadc0 Don't pass empty strings to PlainFile::writeImpl
This function asserts length is not zero, so I was hitting
this in a debug www load.
2012-09-19 10:56:58 -07:00
smith 51511ceb5f Fix injected bug: check m_strongIterators on the copy
This was injected when I converted the strong iterator
list to a linked list.  Only affects HphpArray when
COW occurs on the array being mutated in a mutable foreach
loop.  Starting a strong iteration causes a private copy
to be made anyway, but the bug should be fixed either way.
2012-09-19 10:56:58 -07:00
jdelong 5f43aaca36 Correct some use of smart allocated data in DebuggerClient
The DebuggerClient destructor could try to invoke ~Array
after the smart allocator shut down from a static dtor.  In the case
of the hphpd_get_client API, it also could try to assign null_array to
an Array at sweep time---I think this could be wrong if these Array's
have references to other Object's with custom sweeps.
2012-09-19 10:56:58 -07:00
psnell a62afadb90 Fixed get_class_vars. 2012-09-19 10:56:58 -07:00
smith ef59eb9a06 Initialize m_allocMode in VectorArray non-smart-copy constructor
Non-smart-allocated VectorArray wasn't initializing this field,
which surely can't be good.  This would most likely impact HPHPC
but only when creating static arrays; and its not clear when/if
we create static VectorArrays.  But it's still a bug.
2012-09-19 10:56:58 -07:00
mwilliams f310c7542d Remove incorrect assertion
The assertion assumes we're dealing with a
utf8_string - in which case it will have been
checked for correctness. But preg also works with
non-utf8 strings.
2012-09-18 10:33:16 -07:00
je@fb.com 194ce33cd0 Remove legacy UnsetM translation code.
Remove legacy UnsetM translation code; generic *M translation obsoletes it.
2012-09-18 10:33:16 -07:00
alikhtarov e56395e1e8 fb_compact_serialize: add a VECTOR code
We need a concept of Vector since it will be supported in PHP in the future and C++ code should have a way to represent vectors.
2012-09-18 10:33:11 -07:00
jdelong e652756601 Strengthen is_refcount_realistic assertions
All valid refcounts should be less than or equal to the
static value.
2012-09-18 10:33:11 -07:00
jdelong 9974398919 In finish_thread_locals, use isNull instead of getNoCheck
The getNoCheck function will assert that it's not null, which
this code is apparently trying to check.  (Somehow hit this loading a
sandbox page, but not sure how to repro.)
2012-09-18 10:33:07 -07:00
bsimmers 0ef012355b Fix file_put_contents to work with php://{stdout,stderr}
file_put_contents' implementation was manually opening the
passed in filename. If we use our File class instead, the magic php://
paths just work.
2012-09-18 10:33:04 -07:00
mwilliams 75741d2662 Fix an issue with over-agressive type annotations
This could cause a local with a type assertion to be
inferred non-null at places where thats not the case.

In the new test, the $a in "return $a" was inferred to
to be an object, resulting in a crash when $a was
pushed onto the stack, and its refcount incremented.
2012-09-18 10:33:02 -07:00
mwilliams 005bc0ca3b Allow select threads to bypass the usual thread initialization
Parallel query jobs dont need to do any of the normal thread
initialization, so skip it.
2012-09-18 10:33:00 -07:00
andrewparoski 2eff40fa2f Parser bug fixes and clean up
I combed through HipHop's grammar and noticed a few bugs. HipHop's grammar
does not allow for traits to be declared anywhere except toplevel scope
(whereas Zend allows for this), and the grammar allows for bogus singleton
XHP tags such as '<foo a="1" /foo>' (which are not allowed by the original
XHP grammar given by xhpast).

This diff fixes these bugs, and it also removes some superfluous rules,
duplicated rules, and dead rules from the grammar.

I also took a look at 14 shift/reduce conflicts in the grammar to see if I
could eliminate most of them. 4 of the 14 conflicts went away when I fixed
the issue with the xhp_tag_body rules and when I removed the dead type_decl
rules. Of the 10 remaining conflicts, 2 were due to the if/else rules and
the other 8 were due to the "expr -> expr [ dim_offset ]" rule. Conflicts
due to "if/else" are well understood and conventional wisdom says we're
better off just accepting these conflicts instead of contorting the grammar
to try to get rid of them. Conflicts due to "expr -> expr [ dim_offset ]",
however, are not really well understood and there are a lot of them, so it
seemed worth fixing.

"expr -> expr [ dim_offset ]" was originally added to the grammar to
support using function calls as the base for array element expressions
(ex. "$x = f()[0]"). The rules for variable, calls, array elements, and
object properties were written in a very weird way that made them hard to
update, so I took the opportunity to rewrite these rules in a more natural
form and I updated the rules to support using function calls as the base
for array element expressions. Finally, I ran into cases where developers
were using array literals, class constants, and parenthesized expressions
as the base of array element expressions, so I introduced 'dim_expr' rules
so that HipHop's grammar will continue to support these cases.
2012-09-14 17:20:00 -07:00
bsimmers 3c448d2c80 Only validate that the subject of preg_split is valid utf8 once per call
pcre_exec checks that its subject is valid utf8 every time
it's called (unless told not to). Our preg_split implementation can
end up calling pcre_exec once for every character in the subject for
certain inputs, so rechecking the utf8 validity of the subject is a
waste of cycles.
2012-09-14 16:23:04 -07:00
andrewparoski e6b2585630 Add serialization support for collections
This diff implements support for collections with serialize, unserialize,
var_dump, print_r, json_encode, var_export, and debugger serialization
formats.
2012-09-14 16:05:26 -07:00
nikoloz 6db1b6bb50 Adding finally support to hphp (hphpc only for now)
try/catch()/finally and try/finally constuctions added to hphp. Code is translated into C++.
There still a lot to do:
1. Throw an exception when there's an unhandled exception in finally scope;
2. Write test units;
3. Support finally in virtual machine;
4. Return an error if there's a yield statement into try/finally scope.
2012-09-14 16:05:02 -07:00
mwilliams 993a33b5db Generate INTERCEPT_INJECTION_ALWAYS for dynamicInvoke functions
This means we can avoid compiling with ENABLE_INTERCEPTS, which
significantly reduces the size of the binary.
2012-09-14 14:24:33 -07:00
smith 6a4aede244 Convert MemoryManager to ThreadLocalSingleton
Converting to ThreadLocalSingleton means each MemoryManager instance is
stored directly in __thread memory instead of malloc, and allows clients
to directly access it via the x64 FS register.  This avoids needing
SmartAllocatorImpl::m_stats to update stats.

Moved The GarbageList static_assert to memory_manager.cpp.
2012-09-13 14:12:49 -07:00
jdelong 28e4699428 Make DummySandbox shutdown always call execute_command_line_end
Failing to call this when there are live RequestLocal objects
will can cause them to access deleted objects during pthread's
shutdown (calling OnThreadExit).  This fixes and adds assertions about
ref counts that makes this easier to hit this in a debug build.
2012-09-13 14:12:49 -07:00
jdelong 9db1d12555 Make the translated SetOpM and IncDecM warnings match interp
Some flib tests were failing, and the lines I looked at were
for SetOpM.  The bytecode.cpp version of these two uses MoreWarnings
to decide whether warn is true for setHelper, so do something similar
for the translator.
2012-09-13 14:12:49 -07:00
bsimmers 93f7a60128 Add HPHP::safe_cast and use it in the assembler
This is a wrapper around boost::numeric_cast, to give a
helpful error message if we attempt to use an out of range immediate
or jump in the assembler. I'm sure there are other places in the
codebase it can be useful but this was the first that came to mind. In
RELEASE=1 builds it's just a static_cast so there should be no runtime
overhead.
2012-09-13 14:12:42 -07:00
mwilliams c99d66ab59 Dont call getMInstrCtx unless necessary
The translations for the M* instructions call getMInstrCtx to
set MInstrState::ctx if the context is not fixed, or if there
are property accesses in the vector. But MInstrState::ctx is
only read when the context is not fixed AND there are property
accesses in the vector.

Also found an issue where the BaseN* helpers would access
the current frame without a VMRegAnchor. Fixed by passing in
the correct fp as a parameter.
2012-09-11 22:12:20 -07:00
bmaurer fbede8d914 Free memory for preg and memcache
This introduces a more expensive, second phase of clearing thread caches.
should help reduce long term memory usage
2012-09-11 22:11:49 -07:00
andrewparoski a100a251b0 Disallow dynamic properties for collections
Allowing for dynamic properties on collections is kind of silly, and it
would complicate adding var_dump and serialization support for collections.

This diff disallows property access for collections.
2012-09-11 22:11:36 -07:00
mwilliams 7b0231ead3 Implement fb_could_include
This checks to see whether a file could be included.
  For hhvm in sandbox mode, this just checks the existence
  of the file.
  For hhvm in RepoAuthoritative mode, it ignores the filesystem,
  and looks to see whether the file is in the repo.
  For hphpc it checks to see if the file was compiled into the
  binary.
2012-09-11 21:14:31 -07:00
mwilliams 4c10d9cc45 Make more requires merge-only
Optimize initialization by handling simple defines,
simple assignments to globals, and requires from within
Unit::merge.
2012-09-11 20:20:52 -07:00
andrewparoski 5829296ea8 Make Vector::pop return the value that was removed
Vector::pop is advertised as returning the value that was removed from the
Vector. Make it so.
2012-09-11 20:20:39 -07:00
bsimmers aad7f3fe26 Translate FPushCtor
It's just like FPushCtorD but without the targetcache lookup
(the Class* is on the stack as an input).
2012-09-11 17:39:29 -07:00
mwilliams 7b10c3420b Dont enforce serialization limits during apc_prime
apc can contain some large strings
2012-09-11 17:39:14 -07:00
ifullinwider 4f5304676a Add memory usage information to status.* admin port commands
add a memory section to the information returned by
ServerStats::ReportStatus() for threads handling requests
2012-09-11 16:49:33 -07:00
je@fb.com 5a8c92ea57 Translate all *M instructions.
Implement generic translation capability for all *M instructions.
Generic translations are emitted as series of helper function calls.

Add the Eval.JitMGeneric runtime option to allow generic *M instruction
translation to be disabled, for regression testing/reversion purposes.

Fix callUnaryStubImpl() to account for pushing rdi when argument is
rsp+disp.

Fix the interpreter to warn for BaseLW* as needed.

Fix the interpreter to initialize IncDecL's stack output before
operating on it.
2012-09-11 16:49:27 -07:00
andrewparoski 7aba6acb36 Disallow using comparison operators on collections
Using comparison operators (==, !=, <>, <, <=, >, >=) with arrays and
objects can be expensive and produce strange results in some cases.

Rather than having collections match this behavior, I think it's better to
disallow using these operators to compare a collection with an integer,
string. This diff adds checks to either raise a warning or throw an
exception (depending on a runtime option) when any of these operators is
used to compare collection with an integer, string, array, or object.

Note that collections are still allowed to be compared with null, true, and
false using the comparison operators. Also, collections can still be
compared for reference equality with === and !==.
2012-09-11 16:47:00 -07:00
andrewparoski 7fccb7255a Fix idx() to support collections, add throwBadKeyType in a few places
Update idx() to support collections. Also, for some collections the
contains(), remove(), and discard() methods did not throw exceptions if the
key type was invalid, fix that.
2012-09-11 16:46:53 -07:00
Sara Golemon 797b2b9ccc Strip INJECTION macros from ext_collection 2012-09-11 16:46:28 -07:00
bsimmers 73ca128cc3 Code cleanup for icc
This is a series of gcc compatible code changes to make icc
happy. Most of the changes are assert(false) -> not_reached() and some
type massaging.
2012-09-11 15:15:54 -07:00
mwilliams 58851e172e Revert "Stops response if find a RequestInitDocument redirect"
This reverts commit 4b24643b3a
2012-09-11 15:15:12 -07:00
andrewparoski 5ef1022117 Update error messages for FPushObjMethod*/FPushClsMethod* to match Zend
The current error messages for FPushObjMethod and FPushClsMethod are a bit
cryptic. This diff updates these error messages to match Zend.
2012-09-11 15:15:12 -07:00
andrewparoski 30ac796d07 Fix Vector::pop
Vector::pop should use tvRefcountedDecRef instead of tvDecRef.
2012-09-06 18:47:08 -07:00
smith 0796eb357b Make ArrayData::m_strongIterators a linked list instead of vector
For the cost of one more pointer in struct FullPos, we can simplify
the tracking of an array's currently active mutable iterators.
The current array (vector of FullPos*) requires a secondary malloc()
if there are >1 iterators.  Using a linked list never requires malloc,
and keeps the common case fast (most recently added iterator is the first
one in the list).
2012-09-06 18:36:39 -07:00
Sara Golemon 44044d955a Update timelib 2012-09-06 18:31:36 -07:00
mwilliams f73872798c Fix TestDebugger for certain machines 2012-09-06 16:02:53 -07:00
jdelong 16a219d1c9 Implement a couple easy additional checks in the verifier
Just added checkArrays() and whether or not we have exactly
one pseudo-main.
2012-09-06 16:02:53 -07:00
jdelong fae4262822 Make emitContinuationMethod generate bytecode that passes verification
It was generating a RetC on an UnboxR (on purpose) and a try
region that started with a non-empty stack.  Also adds support for an
HHVM_VERIFY_VERBOSE mode.
2012-09-06 16:02:53 -07:00
smith 9cc46f1414 Remove unused SmartAllocator VarAssocPair enum 2012-09-06 16:02:53 -07:00
alia 606e8e0481 Added isContextFixedCheck to analyze[CGetS, SetS] and cleaned up uses of arGetContextClass.
The static property accessor bytecode translations were not
checking whether the context is fixed, which is incorrect when translating
pseudomains. This diff adds a isContextFixed check to analyze[CGetS, SetS] to
make sure we are not in pseudo-main. It also replaces uses of arGetContextClass
with curFunc()->cls() where its clear that we don't want to be in pseudomain.
2012-09-06 15:57:32 -07:00
andrewparoski d4eb293455 Clean up some old hphpi cruft
This diff removes the GeneratorClosure cppext class (which was only used
by hphpi), reenables a disabled trait test, and cleans up some other
miscellaneous things.
2012-09-06 15:57:19 -07:00
smith 7839972d32 SmartAllocate VectorArray and ZendArray buffers (max=64)
Use SmartAllocator to allocate VectorArray and ZendArray buffers up to 64
entries.  The size of inline allocation space (4 slots for VectorArray,
8 Bucket*'s for ZendArray) is unchanged, since experiments showed any
change in either direction was a regression.

Also use helper functions to round up to powers of 2 rather than a
while loop; the helpers use __builtin_clz.
2012-09-05 20:51:25 -07:00
bsimmers b7c593bb27 Fix order of assignment in SetM and UnsetM
SetM (jit only) and UnsetM (everywhere) were decreffing the
destination before storing the new value. This allows user destructors
to get access to dangling pointers, potentially leading to objects
with invalid refcounts and other badness. Both instructions now store
the new value before decreffing the old value.
2012-09-05 20:51:25 -07:00
jdelong dfbf43b498 Wrap verifier error prints into a utility function
Eventually we might want a mode that throws an exception if
it fails verification, etc.  This also fixes some inconsistency in
what the error message prefix looked like.
2012-09-05 20:51:25 -07:00
jdelong 799dc4379a Verifier support for string/int immediates in vector instructions 2012-09-05 20:51:24 -07:00
smith 30a9a5fb8c Remove ptv and pvar from Variant/TypedValue
Access to the value in a RefData must be via RefData.tv()
or RefData.var() accessor methods.
2012-09-05 20:51:24 -07:00
jdelong 8a7e4e6ec4 Add options to verify non-systemlib units only
Verifier chokes hard on systemlib right now (I think due to
the OpSwitch changes).  This lets you use it just on a small file.
Looking at updating for OpSwitch next ...
2012-09-05 20:51:24 -07:00
smith 07e5419fe6 Disable sizeof(ObjectData) assert in HPHP builds
In the VM we want sizeof(ObjectData) to be 16-aligned,
but due to ifdef'd fields this means it can't be in HPHPC,
so just disable the assert.
2012-09-05 20:51:24 -07:00
mroch c9597af8cb Add JSON_PRETTY_PRINT to json_encode
PHP 5.4 added the JSON_PRETTY_PRINT option to json_encode:
http://php.net/manual/en/function.json-encode.php
2012-09-05 20:51:24 -07:00
kma be6752d679 16-byte-align objects, properties.
Lots of properties were straddling cacheline and page boundaries,
so that reading or writing one property required two entries in important
hardware caches. First, allocate ObjectData's at 16-byte boundaries;
second, make ObjectData itself 16-byte sized, so that its trailing
properties will also be aligned. Along the way drain a code-copying
swamp.

There are still alignment issues with objects that extend an extension
base class; some of them seem to have ragged sizes. We should pad them too,
but baby steps.
2012-09-05 20:51:24 -07:00
kma e709bf271b Handle inheriting from GenericContinuation correctly.
GenericContinuation does custom deallocation of memory, but did
so assuming it would not be inherited from. While inheriting is useless for
end-users, we implement some real continuations by inheriting from
GenericContinuation, so simply making it final is not an option.

(This appeared to work before because we weren't testing with enough fields
in the child class.)
2012-09-05 20:51:23 -07:00
andrewparoski 7a67457689 Fix isset() for collection classes under hphpc
There was a code path for isset() under hphpc that did the wrong thing for
collections. Fix that and add some tests.
2012-09-05 20:51:23 -07:00
andrewparoski 00ef04e18f Get rid of unneeded __destruct methods from the cppext classes
I noticed that a lot of cppext classes define __destruct methods that do
nothing and this causes the VM to do an unnecessary re-entry to run these
__destruct methods. This diff removes __destruct methods that do nothing
from all cppext classes.
2012-09-05 20:51:23 -07:00
Drew Paroski 404cd2cab7 Update inconsistencies doc 2012-09-05 20:51:23 -07:00
Sara Golemon 0a9d3c5875 Generated files 2012-09-05 20:51:09 -07:00
jdelong c628168ac5 Fix use of boost graph to properly use ADL
I think I messed these up when removing "using namespace
boost" from this file.  For the various graph concepts, we're supposed
to use unqualified name lookup and ADL, which avoids this header
ordering thing.
2012-08-30 16:28:13 -07:00
jdelong 67f1eca902 Move initialize_repo() earlier so it affects --repo-schema output 2012-08-30 16:28:13 -07:00
mwilliams afa580582e Dont call the auto-generated ctor
Many classes dont have a user defined ctor. In
those cases, we can skip calling the compiler
generated one.
2012-08-30 16:28:13 -07:00
Sara Golemon 1b02f4e6ae Allow DOMDocument::registerNodeClass() to extend DOMNode
Zend-PHP compat fix.
Currently, if you try to extend DOMNode, you're told:
DOMNode is not derived from DOMNode which is true,
but inappropriate for the intent of the method.
2012-08-30 16:03:24 -07:00
andrewparoski 7841db0d0d Add builtins for Vector, Map, and StableMap 2012-08-30 16:01:21 -07:00
Sara Golemon 206cd05d3c Update is_a() and is_subclass_of() to match PHP 5.3.9's behavior.
PHP 5.3.9 adds "allow_string" parameter to both methods.
Each method defaults to the behavior which they had before the
additional parameter.
- is_a() allow_string defaults to false
- is_subclass_of() allow_string defaults to true
2012-08-29 21:30:09 -07:00
bsimmers 72ee038984 Store Continuation locals inline at the end of the object
The call to free() in ~c_GenericContinuation was a nontrivial
source of dTLB misses. The locals previously stored in that malloced
buffer are now stored in extra space allocated at the end of the
object, just like builtin properties at the end of an Instance. This
also makes translated code touching these locals slightly faster by
replacing a mov with an lea.
2012-08-29 18:05:50 -07:00
mwilliams 8ac7fa81ad Lock all targetcache allocations
There were a few places (including Cache::alloc and
allocStatic) that allocated space in the targetcache
without taking the handleLock. This was mostly ok,
because they were only called when we held the
write lease; but there are paths in the interpreter,
the file cache and Unit::merge that can allocate
target cache entries without holding the write lease.

This resulted in hard to track inconsistencies in
targetcache state.
2012-08-29 18:05:50 -07:00
jdelong b160848e68 Remove lookup of __destruct from Instance::destruct 2012-08-29 18:05:50 -07:00
bsimmers 6e202ed03d ASSERT(false) -> not_reached() to placate the compiler 2012-08-29 18:05:49 -07:00
smith eeddfbb4a6 De-unionize StringData.m_hash and m_shared
Now that we have inline-string space in StringData, we can use it
to store the SharedVariant* m_shared field for shared strings,
shrink m_hash to 32 bits, shuffle fields around so they still
pack nicely, then increase the inline space in StringData from
40 bytes to 44 bytes.

Doing this requires reducing string hashes to 32 bits everywhere,
which means 31 bits in practice because we use the high bit as a
flag in various places.  (as before... we're really going from
63 bits to 31 bits).

The change also ripples into HPHPC tables which contain a string
hashcode since we can shrink that field to 32 bits.
2012-08-29 16:59:38 -07:00
alikhtarov f74ee31b35 Synchronize generated classes and export fb_compact_unserialize_from_buffer 2012-08-28 11:08:05 -07:00
Paul Saab 3c4f34db99 Remove msync MS_SYNC from SharedStorage
There's no reason to sync out the APC data to be persistent on
disk since it's recreated every start.  Data will lazily be flushed back
and this will reduce the start time of the process by 20-30 seconds.
2012-08-28 11:08:05 -07:00
jdelong c24af4e417 Switch back to new/delete for ExtraArgs
There was a place where these were being leaked in the
translator, but also the idea of leaking the top-level ones until the
end of the request breaks long running scripts.
2012-08-27 15:24:50 -07:00
dwitte 21b54e8335 Add pcre size query to hhvm admin server
Add a "pcre-size" query that reports back the size of the PCREStringMap in preg.cpp.
2012-08-27 15:24:50 -07:00
jdelong d64b86075f Add the ability to override repo schema with environment var 2012-08-27 15:24:50 -07:00
mwilliams 15feb51c98 Fix an unused variable warning from generated code
Make sure the components of a list expression know when
their result is unused. This came up when:

  $x = expr1 + expr2

was optimized to

  (expr1, expr2)

But then expr2 generated a temporary variable to hold its result,
which was never used.
2012-08-27 15:19:31 -07:00
Paul Saab 79e94e9895 Protect the apc expiration priority queue
It's possible to store the same key over and over again with a
ttl and it will grow the expiration queue unbounded.  Use a concurrent
hashtable to store items which are already in the queue to prevent
adding the same key over and over.  We only honor the first TTL and
ignore the rest.
2012-08-24 11:45:31 -07:00
mwilliams 050133c796 Fix order of evaluation for LSB
Parameters were not automatically fully evaluated during
the preOutput phase if they couldnt interfere with each
other. But this didnt take account of the ordering wrt
late static binding.
2012-08-24 11:45:31 -07:00
mwilliams 7d6a90457f Fix dynamic lookup for interface constants
Interface constants were omitted from the property
tables, and so were not visible to dynamic lookup.
2012-08-24 10:54:52 -07:00
mwilliams 74737a4663 Dont do uninit/reference analysis in pseudoMain
I had assumed the test for LDynamicVariable was sufficient,
but its not set (automatically) in pseudoMains.
2012-08-24 10:54:25 -07:00
alikhtarov ab4a2a9877 fb_compact_serialize/fb_compact_unserialize
New, more compact serialization. See comment doc for more info.
2012-08-24 10:51:20 -07:00
smith 8aa7022087 Allocate ThreadLocalSingleton storage inline
ThreadLocalSingleton stores a __thread T* and lazy-initializes the
object by calling T::Create, which typically allocates a new object.
Access to the thread local T is indirect through this pointer.

We can do better by just inline-allocating __thread T.  This patch
does so while preserving the timing of when T is initialized or
destructed.
2012-08-24 10:50:34 -07:00
aravind 83448a0b18 fix gdb dwarf generation bugs
A number of bugs seem to have crept into the gdb dwarf generation code
that didn't get tested because we had turned off gdb syncing by
default.
2012-08-24 10:50:34 -07:00
kma f205743067 Fix TestCodeRunVM-Traits.
I accidentally made a test of a function's parent's attributes
into a test of the func's attributes. Whoopsy. While I'm at it, use the
appropriate types on the scalars in Class.
2012-08-24 10:50:34 -07:00
kma 610bfd043b Avoid allocations on a reenterVM.
Some investigation of DTLB misses showed that a tremendous amount were happening from free()'s called in the VM reentry path. This turns out to be due to the hash_map/vector pair we were using to record entry points.
2012-08-24 10:50:34 -07:00
mwilliams 46b81324c2 Revert "Fix dynamic lookup for interface constants"
This reverts commit 60c9118191
2012-08-24 10:50:34 -07:00
Sara Golemon f6e7627131 Dump ancient (and out of date) libevent-1.4.13 diff.
Builds should be against 1.4.14 (and that patch) at this point.
2012-08-22 10:57:09 -07:00
Paul Saab f05373676a Implement FB Specific SHUT_LISTEN
Use a FB specific option to shutdown(2) which disallows all new
TCP connections, but does not drop any connections which have completed
the three-way handshake and will allow the application to accept(2) any
remaining connections.

OSS Note: This feature is gated on RuntimeOption::ServerShutdownListenWait
However OSS builds should never enable this option as the shutdown() call
will fail due to receiving an invalid argument.

This patch is included on github for consistency.

You will need to reapply libevent-1.4.14.fb-changes.diff
and build your custom libevent after applying this patch,
but before rebuilding hiphop.
2012-08-22 09:31:03 -07:00
mwilliams 60c9118191 Fix dynamic lookup for interface constants
Interface constants were omitted from the property
tables, and so were not visible to dynamic lookup.
2012-08-22 09:20:28 -07:00
mwilliams 7c4eafd216 Fix some potential length overflows in StringData
There were a few places where an invalid length could sneak in.
2012-08-22 09:08:10 -07:00
kma aa92b363f8 Cache a copy of attrs using a free word in Class.
A lot of hot class paths involve looking up the preClass's
attributes. perf runs for dTLB and l1-dcache load misses highlighted these
as a possible problem.

Alignment means we have a spare word in Class. Cache the preClass's
attributes there.
2012-08-22 09:08:10 -07:00
phyllipe 4b24643b3a Stops response if find a RequestInitDocument redirect 2012-08-20 18:54:56 -07:00
smith cb31ae38eb Remove SmartAllocator stats and stop tracking freelist size on the fly.
It should be cheaper to just calculate freelist length when we need it
than keeping track of it on the fly.  Frequent logging of freelist
length thwarts this, so lets not frequently log that stat.
2012-08-20 12:17:10 -07:00
bwester b8cb692561 Don't allow empty property names to be created by referencing
In HHVM, a fatal error is now thrown when an invalid object property
(one with an empty name) is accessed while creating references.  This
behavior matches Zend.
2012-08-20 12:17:10 -07:00
smith f117b9b198 Fix use-after-free bug in assignRefHelper
assignRefHelper() takes care to increment the refcount before
copying a value in case destroying the LHS destroys the owner
of the ref; but then it reads from said owner after destruction,
which is a free-after-use bug, for example:

  $x = array(0);
  $x &= $x[0];

It never showed up before because SmartAllocatorImpl::dealloc().
did not garbage-fill freed memory.  We just need to save the
newly created pointer before destroying the LHS value.

This patch also enables garabge-filling for
SmartAllocatorImpl::dealloc().
2012-08-20 12:17:10 -07:00
Sara Golemon d32c7aff0b s6_addr32 is a linuxism. Pack s6_addr into 32bit words manually.
Explicitly pack in6_addr octets into 32bit BE words
rather than relying on non-cross-platform s6_addr32 linuxism.

Less efficient than autoboxing, but this is just a unit test.
2012-08-20 09:12:43 -07:00
Sara Golemon 930c135e4e Rename SmartAllocatorImpl::roundup to itemSizeRoundup
FreeBSD defines roundup as a macro which confuses
gcc enough to error out.  Just use a different name.
2012-08-19 10:02:11 -07:00
Sara Golemon 0c40d07e86 Pass -1 as placeholder fd to mmap()
Per the mmap man page: MAP_ANON
The fd and offset arguments are ignored; however, some implementations
require fd to be -1 if MAP_ANON is specified, and portable applications
should ensure this.

FreeBSD fails on fd == 0
2012-08-19 10:02:11 -07:00
Sara Golemon 71c3bbebff Allow disabling of HardwareCounter (cont'd)
Somehow missed the important part of this commit during
the merge from internal when I committed 7761a65
2012-08-18 02:09:42 -07:00
Sara Golemon 29ce7fa493 Explicitly link libiconv and libunwind 2012-08-18 01:44:10 -07:00
Sara Golemon 7b3e14ffb1 Add check for inotify.h and (optional) libinotify.so 2012-08-18 01:42:49 -07:00
Sara Golemon 7761a65900 Allow disabling of HardwareCounter
HardwareCounter depends on linux specific ioctls
and kernel hooks.  This makes them unusable on other platforms.
2012-08-18 01:16:09 -07:00
bsimmers 52cb344e43 xml_set_element_handler should allow unsetting callbacks
If false or the empty string is passed as a callback to
xml_set_element_handler, we should unset the callback instead of
warning that it's invalid.
2012-08-18 01:13:52 -07:00
bsimmers 0642495d66 Limit verify_quick to 20 threads by default 2012-08-18 01:13:51 -07:00
Sara Golemon e864fc0bae Perf Event based hardware counters are only available on Linux 2012-08-17 22:01:22 -07:00
Sara Golemon c68eb3e8f8 Make sure that libiconv gets linked in for the ICONV_CONST test 2012-08-17 21:20:47 -07:00
Sara Golemon 1b0e92bbe9 GCC 4.4 should work following 3691f85 2012-08-17 17:22:46 -07:00
Sara Golemon 3691f85504 sizeof() compatability fix for gcc 4.4
GCC 4.4 doesn't recognize sizeof(Class::InstanceVar)
Declare the instance var with a typedef
and use sizeof(Class::TypeDef) instead for successful parsing.
2012-08-17 17:20:27 -07:00
Sara Golemon 83ef02e385 Generated files for 82e4b93 2012-08-17 17:03:42 -07:00
Drew Paroski f893be4ce4 Add gc_collect_cycles() and related builtins
Summary:
This diff adds the following builtins related to circular reference
collection:
  gc_collect_cycles()
  gc_enabled()
  gc_enable()
  gc_disable()

The current implementations for these functions just raise a warning and
return. In the near future, we can hook up these builtin functions to
HipHop's cycle collector. This will allow programs written for Zend PHP 5.3
to transparently use HipHop's cycle collector without requiring changes to
the program.
2012-08-17 17:02:21 -07:00
bsimmers f2aa3bc917 Limit TestCodeRun* to 20 jobs unless overridden.
TestCodeRunVM ends up spending >85% of CPU time in _raw_spin_lock
on the certain machines with more than 21 jobs. Cap it at 20 to be safe.
Also let HPHP_SLOW_TESTS_JOBS apply to all TestCodeRun suites.
2012-08-17 16:26:16 -07:00
smith f24d806aa0 Fix assert in SmartAllocator::alloc when sizeof(T) < sizeof(void*)
We need to enforce a minimum allocation size a) for GarbageList,
and b) for RefCountTombstoneValue.  sizeof(void*) is not actually
big enough, but we're getting lucky since no real-world size is
less than 16.
2012-08-17 16:26:16 -07:00
mwilliams 5325f9a25e Annotate more variables as UninitNull.
I noticed that we weren't annotating the type of
an FPassL even if the variable was known to be UninitNull.

Fixing that exposed a bug in the metadata argument numbering,
and existing tests in TestCodeRun revealed another bug in type
inference, in scopes where $this is altered via a dynamic
variable ($t='this'; $$t = 'surprise').
2012-08-17 09:40:21 -07:00
mwilliams b7d87a0fbc The generated 86ctor method should not be callable
The 86ctor method is only there for the benefit of FPushCtor*, it
should not be called via parent::__construct.

This removes it from the method table altogether, since we never
need to look it up dynamically; which also fixes:

  $ctor = '86ctor';
  $x->$ctor();

While I was there, I also removed 86pinit and 86sinit. For now, Im
leaving 86cinit, since it would mean increasing the size of Class
(by one pointer).

This also revealed a bug - 86ctor was not supposed to be inherited,
but it could be if the emitter "forgot" to create one when needed -
or if the user failed to create one using hhas. One of the hhas
examples violated this. I changed the base class constructor to be
__construct instead of 86ctor.
2012-08-17 09:40:21 -07:00
mwilliams 82e4b9373e Fixes for gcc-4.7.1
Fix various issues when compiling with gcc-4.7.1
2012-08-17 09:40:21 -07:00
jdelong b24f0942d9 Make register_name_t a strong typedef
Using the type system to make it harder to make simple types
of errors when using our x64 assembler.
2012-08-16 16:14:56 -07:00
jdelong 627b6e42b5 Don't translate pseudo mains
We're not really doing it right, and currently it doesn't
seem to be a major perf thing.  Turn it off for now?
2012-08-16 16:12:47 -07:00
mwilliams c4e110ec43 Fix ini_get('memory_limit') to return -1 for unlimited.
A recent change set the default limit to INT64_MAX, which
broke scripts which tested for -1 to see if a limit had been
set. (eg they would set a 1G limit if no limit had been set).
2012-08-16 16:12:46 -07:00
smith e4483fbd0a Have SmartAllocator bump-a-pointer on empty freelist.
When the freelist is empty, allocating from the frontier can be
done with just two pointers, but the current code must access
m_blocks, m_row, m_col, and m_colMax.  Instead, maintain just
a pair of pointers (next, limit).

This diff also cleans up the way SmartAllocatorImpl.m_stats
is set up.
2012-08-16 16:12:46 -07:00
mwilliams 794bd22867 Add support for imageantialias
This was disabled because it requires a special php version
of the gd library. But the existing gd library has similar
functionality via a different api. Since there are only
a few functions that are affected by antialiasing it was
fairly easy to intercept each of the affected routines and
do the right thing.
2012-08-16 16:09:48 -07:00
Paul Saab ef8270bde5 Allow CAP_SYS_NICE
We have the need to change the priority of threads, so allow
this capability.
2012-08-16 16:07:16 -07:00
mcohen 1be68350b8 Correctly bake in code references from require so they can be invalidated
StatCache was broken because of require setting references that
could not be destroyed
2012-08-16 16:06:37 -07:00
Sara Golemon 994d1664e2 Bump libtbb version requirement to 3.0 (Interface 5005) minimum
Note that since 3.0 compatability uses the preview version of
concurrent priority queues, version 4.0 or higher is stronly
recommended.
2012-08-15 10:17:18 -07:00
Sara Golemon 92b1b1d8e7 32bit builds are broken for the foreseeable future.
Let anyone trying to build know that so they don't get confused.
2012-08-15 10:10:04 -07:00
Sara Golemon bdc819a529 Bump required GCC version to 4.6 2012-08-15 10:07:09 -07:00
jdelong c808845bde Cache compiled pcre's in a global cache, fix some other issues
We want to spend less memory on these, so we'll put them in a
tbb::concurrent_hash_map and share across threads.  Also fixes various
memory leaks in some early-return and exception cases in various preg_
functions.  Also removes the HAVE_SETLOCALE stuff, since it wasn't
working anyway (and zend53 doesn't handle it in preg_match after
setlocale either in a quick test).
2012-08-14 14:49:22 -07:00
kma 80dacb96f3 Type prediction clean-up. 2012-08-14 14:49:22 -07:00
smith 5fc2159237 Remove unused str union member from TypedValue and Variant. 2012-08-14 14:49:21 -07:00
Sara Golemon b7aa3cfa16 Add CMake rule to find new dependency libunwind 2012-08-14 11:11:27 -07:00
Sara Golemon ad35fedc43 Sync generated ext_hhvm files 2012-08-13 18:40:53 -07:00
mwilliams 3f318d544f Fix return value in mysql_query
When a query timed out fetching the result, we would return true,
rather than false. Note that queries that return data should only
return false, or a valid MySQLResult resource. The queries that
are allowed to return true have already been weeded out by the
"mysql->status != MYSQL_STATUS_GET_RESULT" above.
2012-08-13 15:59:04 -07:00
Paul Saab 4e5a5c6455 Fix conversion to usec
to_usec needs to know if we're dealing with cpu-time, and only
do the conversion to usec from nsec when using the fast clock_gettime
for cpu time only.
2012-08-13 15:59:04 -07:00
Paul Saab a689976da8 Cache res_ninit per-thread
res_ninit will read /etc/resolv.conf using stdio, which will
mmap 4k worth of data each time res_ninit is called, causing contention
in the kernel.  Cache this per-thread.
2012-08-10 13:11:15 -07:00
mwilliams b00810bbcf Unit::getClassesInfo() was returning interfaces and traits
After a rewrite to use iterator style, the checks for
interfaces and traits were apparently dropped.
2012-08-10 13:11:15 -07:00
mwilliams f831f447c8 Fix a segfault in get_declared_classes()
In rare circumstances, it could attempt to read an invalid iterator.
The problematic case is where a function or class has a name that
puts it at the "end" of the NamedEntityTable (the order of which is
undefined to start with) - and if its a class, its definition must
have been seen, but it must not have been declared yet.
2012-08-10 13:07:08 -07:00
Paul Saab 4686b4e15b Use setbuffer to allocate stdio buffer
glibc's stdio routines use mmap directly to allocate BUFSIZ
bytes to manage internal buffering of data, but this causes contention
on the shared address space in the kernel.  Instead, use setbuffer to
provide an already malloc'd buffer for the buffered-io stdio routines.
2012-08-10 13:07:08 -07:00
jdelong de276f2493 Use a stack-like allocation scheme for VarEnvs
Adds support for frames to ArenaImpl<>, which allows it to act
like a stack, and use them for the VarEnv, ExtraArgs, and associated
VarEnv allocations.
2012-08-10 13:07:08 -07:00
Drew Paroski 900b21abcc Fix COW bug with foreach by reference
There are some cases involving foreach by reference loops where COW is not
triggered when it should be. Here is an example:

  <?php
  function foo() {
    $arr = array(0,10,20,30);
    foreach ($arr as $k => &$v) {
      $v += 100;
      if ($k == 1 && !isset($arr2)) { $arr2 = $arr; }
    }
    unset($v);
    var_dump($arr2);
  }
  foo();

  === Current output under HipHop ===
  array(4) {
    [0]=>
    int(100)
    [1]=>
    int(110)
    [2]=>
    int(120)
    [3]=>
    int(130)
  }

In the example above, the 3rd and 4th elements of $arr2 were incorrectly
modified by the foreach by reference loop. The problem is that the strong
iterator only checks if the array's refcount is greater than 1 before the
first iteration of the loop, but it doesn't check the array's refcount for
subsequent iterations.

I fixed this by making the strong iterator check the array's refcount each
time the iterator is advanced. If the refcount is greater than 1, a copy is
made and the strong iterators are migrated from the original array to the
copy.

In the course of implementing this fix, I made VectorArray escalate to
ZendArray whenever it is used with foreach by reference. This helped avoid
complications in cases where a VectorArray would need to escalate to
ZendArray while a foreach by reference loop is iterating over it. I also
took the opportunity to clean up some of the logic that deals with
escalating an array when a foreach by reference loop begins.
2012-08-10 13:07:08 -07:00
andrewparoski 1b1d393d37 Raise warning when null, false, or empty string is promoted to a stdClass
Zend PHP 5.4 raises a warning when code such as "$x = null; $x->foo = 1;"
causes a null, false, or empty string value to be promoted to a stdClass.

This diff updates HipHop to raise this warning as well.
2012-08-10 13:00:19 -07:00
mwilliams a39e407d76 Make sure the TranslatorX64 is fully initialized
Parts of the runtime call TranslatorX64::Get(), which allocates
a TranslatorX64, but doesnt fully initialize it. Bad things happen
when we then delete it later.

This gets rid of the processInit call (which is kind of a misnomer
now anyway), and moves the code into the constructor.
2012-08-10 12:57:06 -07:00
mwilliams 80200e7b73 Dont crash on incorrect type assertions
Given something like:

  if ($this instanceof foo) {
  }

We can infer the type of this inside the if block to be foo, assuming
that foo is stronger than the known type of $this.

But if foo is a completely unrelated class, we shouldnt do that, because
we could generate incorrect code at compile time (of course, we could also
optimize out the if entirely - but currently dont).

The code to reconcile an actual type with an asserted type assumed the
actual type was passed first, but in one place, we passed the asserted
type first. This was only a problem if the assertion was impossible.
2012-08-10 12:57:06 -07:00
smith d1a46006a0 Streamline SmartAllocatorImpl::alloc()
* move common fields to beginning of SmartAllocatorImpl
* move body of overflow check out-of-line
2012-08-10 12:57:06 -07:00
Adam Simpkins 3f15840d43 fix socket error messages
Fix a couple error messages that contained "[%d] %s" in a string that
wasn't a printf-style format message.
2012-08-10 12:57:06 -07:00
jdelong aed0d878f5 Fix trimExtraArgs to register frame information
We might re-enter, and it will SEGV if tl_regState is DIRTY
and there's no fixup.
2012-08-09 14:16:20 -07:00
jdelong 2017af85a1 Throw exceptions through the TC instead of using EXCEPTION_GATEs
Registers information with gcc so we can throw exceptions
through TC frames.  Changes EMIT_CALL to only clean caller-saved
regs---the unwinder will let us clean dirty callee-saved regs during
an exception so the interpreter-based stack unwinding will work.
2012-08-09 14:16:20 -07:00
Sara Golemon d00b2101bc Sync trans-data.h protos with upstream 2012-08-08 17:57:07 -07:00
Paul Saab 77893a9209 Reduce mmap lock contention
mmap on Linux requires a write lock in the kernel which will
block page-faults as well as madvise.  gethostbyname will call mmap via
glibc when opening and doing IO on /etc/hosts, so keep /etc/hosts open
permanently by calling sethostent(1)
2012-08-08 17:54:11 -07:00
mwilliams 7982b6f132 Revert "Use huge pages for the TC."
This reverts commit bcef19e6b3

It appears to be totally broken if there arent enough huge
pages available to allocate. Needs a bit more work/tuning...
2012-08-08 12:27:42 -07:00
andrewparoski 89adcf6fcd Use shorter encoding for "mov imm32,reg32", and improve jmp() and call()
During a recent experiment I copied disassembly of some code generated by
HHVM into a .S file and compiled it, and I noticed that we were using a
6-byte encoding for "mov imm32,reg32" when a 5-byte encoding was possible.
This diff fixes the x64 assembler to take advantage of the better encoding
for "mov imm32,reg32".

I also noticed that the jmp() and call() methods in X64Assembler don't take
advantage of emitImmReg goodness, so I updated them appropriately.
2012-08-08 12:27:42 -07:00
Sara Golemon a26abcf58c Rename double-inclusion guard in HPHP's dwarf.h/elfwriter.h
Both HPHP and the system's versions of these headers
were using the same guard defines which means that
whichever version got included first, won.

Rename ours to _HPHP_DWARF_H_ and _HPHP_ELFWRITER_H_
2012-08-07 17:10:29 -07:00
kma bcef19e6b3 Use huge pages for the TC.
Linux makes it relatively easy these days to hint that 2MB pages
might be a good idea. Doing this seems to be good for about 5% CPU.
iTLB misses are down by about 30%.
2012-08-07 17:10:29 -07:00
mwilliams 8910bfd7f9 Fixes for is_subclass_of and friends
is_subclass_of('X', 'X') was returning true under hhvm.
is_subclass_of, method_exists, and get_class_methods were failing
to call __autoload appropriately.
2012-08-07 17:10:29 -07:00
mwilliams d33619e2aa madvise out the targetcache at the end of each request
That way, idle threads automatically have their targetcaches
purged. This matters, because typically we have a large number
of threads early on while the server warms up, and then considerably
fewer once everything settles down. With this change, we only pay
for the memory of the active threads, rather than all threads that
have ever been active.
2012-08-07 17:10:29 -07:00
Sara Golemon 2ba1e02a09 Use the correct struct member on FreeBSD for msgbuf Text 2012-08-07 15:31:42 -07:00
Sara Golemon 3e3f9a90ba Support slightly older versions of libtbb
concurrent priority queue is available in older
versions of libtbb, but only in "preview" mode.  Support
these by explicitly enabling the flag.
2012-08-07 15:31:42 -07:00
Sara Golemon b386ff0095 Remove OSS override of default CodeGeneration.IdPrefix option.
The underscore version of IdPrefix can currently never
work due to uses of $$ being baked into some extensions.

Remove this override for now pending macroization of label
mangling and a proper cmake detection script so that the OSS
build only falls back on other delimited when it has to.
2012-08-07 15:31:42 -07:00
Sara Golemon 51b1d4299a FreeBSD fixes for util/alloc
malloc_np for malloc_usable_size(),
stdlib for other malloc related calls.
Move cpp's include of alloc.h up to provide types
for later includes
2012-08-07 15:31:42 -07:00
Sara Golemon 1bc508565e Use non-sized get/setrlimit() calls for FreeBSD as well as APPLE 2012-08-07 15:31:42 -07:00
Sara Golemon 762b67648d Exlude *.ext_hhvm.cpp files from injections
Summary:
This script is slightly too eager to add
INSTANCE_METHOD_INJECTION hooks as it matches sections
like:

/*
void HPHP::c_XMLWriter::t___construct()
*/
TypedValue* tg_9XMLWriter___construct(HPHP::VM::ActRec *ar) {

as being the c_XMLWriter::t___construct() method from the
original file.

A proper fix would be to make the pattern more restrictive,
but since this over-eager matching is only problematic for
the ext_hhvm generated files, I'm inclined to solve this by
excluding those files, rather than making the regex more
complex and harder to maintain.
2012-08-07 15:31:42 -07:00
Sara Golemon 160489764a Fixes for FreeBSD
Explicitly include ucontext.h and define sighandler
Wrap access to the instruction pointer register in a macro
since mcontext_t is different on FreeBSD.
2012-08-07 15:31:42 -07:00
Sara Golemon 64ca125510 Explicitly cast thread ID to int64 to avoid compiler error
FBSD's gcc (and possibly others) doesn't like an implicit
conversion here.  Making it explicit.
2012-08-07 15:31:42 -07:00
Sara Golemon d16a81008f Explicit casting for pthread_t hash
This line uses a portion of the actual thread value.
Explicitly cast to avoid errors concerning loss of precision.
2012-08-07 15:31:41 -07:00
Sara Golemon 94740b8aff De-const first parameter to memcached_stat_get_keys()
libmemcached doesn't actually mutate this value,
it seems to just be an oversight by the library maintainers.

Regardless, it causes build failures on some platforms.
2012-08-07 15:31:41 -07:00
Sara Golemon 74adc59a4e Remove Server.UseZendArray from documention.
This option no longer exists.
2012-08-07 15:31:41 -07:00
smith 0e6f82009e Remove unused field MemoryManager::m_stopped
Looks left behind from an earlier refactoring.
2012-08-07 15:31:41 -07:00
mwilliams 2091081fc6 Dont leak the targetcache
Targetcache memory is allocated on thread startup, but was
never freed. http threads never die, so its not an issue there,
but eg ParallelQuery threads are created a freed on demand.
2012-08-06 18:15:45 -07:00
Sara Golemon 8cd0d8f44c Add null check on pdo persistent handle restore
g_persistentObjects->get() may (likely) return NULL,
skip trying to restore a non-existant connection
(and testing it for liveness) in that case.

If the connection is dead, don't mark it for saving in rshutdown.
2012-08-06 18:15:45 -07:00
Sara Golemon 1bdc6f58ef Sync dynamic_table_func.cpp with FB repo. 2012-08-04 14:26:13 -07:00
Sara Golemon 081baaf9bc Add missing license headers 2012-08-04 14:24:56 -07:00
Paul Saab faa274c5c2 Implement clock_gettime_ns
In Linux 3.2, the vdso implementation of clock_gettime/clock_gettime_ns is
extremely fast (faster than vtsc), so implement the infrastructure to
support using it.
2012-08-04 11:23:08 -07:00
kma f7d6c34bfc Get rid of bespoke recursive mutex in targetcache.cpp.
This mutex shouldn't be recursive, and it should play nicely with our
ranking system. While trolling through the mutexes, pack them a bit
more nicely and expose primitives for asserting ownership.
2012-08-03 07:00:48 -07:00
mwilliams 889021318b Dont drop pseudoMains from backtrace
We were dropping all pseudoMains from backtraces, making it hard
to figure out where things were breaking.
2012-08-03 07:00:29 -07:00
mwilliams 831b8aa801 Dont complain about continuation methods
When checking method overrides, we can ignore continuation
methods. Checking the original method suffices.
2012-08-03 06:59:33 -07:00
jdelong 65ac1e2382 Backup cycle collector/detector
A simple, slow, but hopefully functional backup cycle collector
and cyclic garbage detector.  Adds an entry point to collect cyclic
garbage, and one that will dump the cyclic garbage as GML without
collecting it.
2012-08-03 06:30:06 -07:00
Sara Golemon bafe9f229d Fix comment type from my previous commit
char**, not char*
2012-08-03 04:54:37 -07:00
Sara Golemon 3fff84532f Use ICONV_CONST define in ext_iconv for second parameter casting
libiconv sometimes defines the second parameter of its
main function as (char**), and sometimes as (const char**) but
provides no means to detect this.  For FB builds, we want (char**)
and explicitly cast as such already, for some OSS builds, this is
backwards.
2012-08-03 04:52:17 -07:00
Sara Golemon 7c1815e217 Explicitly cast thread id around the bitwise not
For platforms which don't implicitly cast pthread_t to int
2012-08-03 04:20:34 -07:00
Sara Golemon 51a35e7951 Add stdio.h to src/util/util.h headers to cover FILE* type
If you use a type, you should include the header
which defines it. :)
2012-08-03 04:20:34 -07:00
smith b566379654 VectorArray::sweep() needs to call m_strongIterators.clear()
Fix for very minor memory leak.
2012-08-03 04:20:34 -07:00
Sara Golemon 606690c010 Implement FBSD version of GetThreadPid()
FreeBSD has it's own syscall for SYS_gettid.
Implement the right calls in the appropriate ifdef checks.
2012-08-02 13:52:09 -07:00
Sara Golemon 49a527e4c2 Enforce dropping the isset macro from sys/param.h
builtin_functions.h can't compile on
platforms where sys/param.h gets included later
in the #include stack than builtin_functions.h

By explicitly including it here and clearing the
macro, we ensure it doesn't get reset.
2012-08-02 13:51:05 -07:00
smith 89ef4864c0 SmartAllocate the first four HphpArray size classes (8-64).
Using SmartAllocator instead of malloc for these auxilary buffers
reduces fragmentation of malloc's small-size arenas, and avoids
the need to free at request-end.

This diff factors allocData() out of reallocData(); allocData
is only for first-time allocations and reallocData is only for
growing the array buffer.  Each smart-allocated size class has
its own SmartAllocator, and allocating and freeing these requires
some branchy logic; I tried to keep the boilerplate to a minimum.
2012-08-02 13:50:59 -07:00
jdelong 0de1c886ee Remove m_halted from VMExecutionContext
Do the same thing using a HaltVM exception.
2012-08-02 13:50:54 -07:00
jdelong 48b0614b92 Fix a bug in nested VM exception handling
It was possible for C++ exceptions to propagate when setting
up a nested VM, but the nested VM didn't handle it and just let it fly
out to the containing VM.  The previously nested VM would end unwinding
after this first nested ActRec, and then popVMState as if it were the
nested VM.  The net result is we would unwind for all but the first VM
entry, because the m_nestedVMs state was off by one.

This fixes a test that crashed the JIT:  in that case, we were
re-entering to try to generate the 500 page, attaching the global VarEnv
to some random ActRec that should've been unwound, and then throwing again
(so this was noticed by seeing the VarEnv depth refcounts going wrong).
2012-08-02 13:50:15 -07:00
kma 3d64522067 Don't burn in request-scoped constants.
We burned in STDERR, which changes from request to request. We
also, amazingly, fail to correctly handle the first access to
(some?) system constants in a request when they happen from the JIT.
2012-08-02 13:50:09 -07:00
alikhtarov 5586dd1007 Function stubs for fb_compact_serialize
To make subsequent diffs smaller
2012-08-02 13:48:00 -07:00
bsimmers c5dbcf5621 Allow overriding the number of slow_tests jobs
Jenkins slow_tests runs keep having distcc problems and we
think lowering the parallelism of the test runs might help lessen the
load on the machines and keep things going more smoothly.
2012-07-30 22:21:42 -07:00
subodh dee60df4f3 Fix next (and step and continue) in hphpd
This commit changes the behavior of next in HHVM to be line aware.
1. Changes to the next command to skip lines
2. Changes to the breakpoint system to prevent re-execution of the
breakpoint when it returns from a function call.
2012-07-30 22:20:16 -07:00
bsimmers 43193887e9 Store condition flags in the targetcache under hhvm
This drops the check from two dependent loads and a test to
a single load/test. Code is visibly smaller, faster, better, etc. Also
fix BaseExecutionContext::setRequestMemoryBytes to not fall over when
given -1 from user code.
2012-07-30 22:16:04 -07:00
kma aa30fcc61b Don't dump core setting big string indices.
We had a flurry of failures trying to create implausibly large
strings. We had a user-provided 64-bit int used as an index, but a derived
32-bit int for its size.
2012-07-30 22:14:25 -07:00
smith c5b7f38f5b Inline-allocate up to 4 Bucket pointers in ZendArray
HphpArray and VectorArray benefit from inline-allocating
so lets do it in ZendArray.  This inline-allocates just
the bucket pointer array, up to four elements.

It also drops the m_nTableSize field since it's always
equal to m_nTableMask + 1, and shuffles fields in ZendArray
to put hot fields near the beginning of the object.
2012-07-30 22:14:17 -07:00
mwilliams 73ee329881 Fix input register allocation bugs
My recent optimization of input registers introduced a bug, where
inputs marked ArgAnyReg might not get allocated at all.
2012-07-30 22:14:11 -07:00
mwilliams df60a3a631 Fix instability in TestTypeAssertions
Due to a bug, in certain cases involving redeclared classes, type
inference was suboptimal unless a method required more than one
pass. For this case, the extra pass only happened very infrequently
(as a result of lock conflicts in the parallel inference algorithm).

Once the bug was fixed, the failure was consistent - because code gen
wasnt taking account of another rare occurrance relating to redeclared
classes. Fixed the code gen bug too.
2012-07-30 22:14:04 -07:00
mwilliams 86345dc8ac Fix an assertion in the emitter
Unreachable code could cause an assertion in the emitter.
Variables that get used in unreachable blocks got tagged as
uninited (why not?). But eg $this could also get tagged as
having a particular class, resulting in an assertion.

Also fix an HphpArray bug when jemalloc is disabled.
2012-07-30 22:12:04 -07:00
Sara Golemon eabf7272b4 FreeBSD cmake defines __FreeBSD__ not __FREEBSD__
Fix a bunch of places where we were using
the wrong ifdef check for FBSD platform.
2012-07-30 22:12:04 -07:00
mwilliams 4a24bcdad7 Better input register allocation
1) Modify allocInputReg to allow specifying a preferred register,
   and add a helper to target inputs to call-argument registers.

   Use the helper for CGetM and SetM and Same to get better register usage.

2) VerifyParamType doesnt read its input unless its an Object

3) Splitting a tracelet after a literal instruction causes the
   result to be spilled, and then tested/reloaded from the stack
   in the next tracelet. Avoid doing so where possible.
2012-07-30 22:12:04 -07:00
mwilliams 698402c8f2 If the ReqestInitDocument calls exit, dont run the page
This gives the init document a clean way to prevent any further
action (an existing but less satisfactory solution was to
throw an exception - which would be ignored).
2012-07-30 22:12:04 -07:00
mwilliams 4baf039171 Fix some issues with the array_setm helpers
The comments didnt match the behavior. In one case,
we weren't decRefing a key where we should have,
causing a (small) leak.

In addition, by adding a few more helpers, we can
merge the SetM with a following Pop, and often with
a preceding CGetL.
2012-07-30 22:12:04 -07:00
jdelong f9391d5a12 Turn C++11 back on
After agallagher upgraded to boost 1.48, the known issue went
away.  We're not sure why, but let's turn it on and see if anything else
goes wrong.
2012-07-27 19:37:20 -07:00
smith 59aeaa9a73 Inline small HphpArrays
HphpArray uses a minimum table size of 8 elements and always allocates using
malloc.  Instrumentation shows that 85% of arrays are <= 4 elements,
and if we make room for a 4-entry table (up to 3 elements) inline,
we can save a bunch of cycles and memory for small arrays.

Initially we use the inline table.  We also union the inline table with
a medium sized hashtable, but without slots, so for medium sized arrays,
we only need to malloc memory for the slots, not the hashtable.

This change also reduces MinLgTableSize from 3 to 2, to reflect the
smaller initial sizes we support, and fixes a small memory accounting
but where HphpArray::sweep() didn't call adjustUsageStats().
2012-07-27 19:37:20 -07:00
mwilliams 71f733730c More data flow analysis for hhvm
- Make the dataflow pass we were using more general;
   it was too specialized towards detecting "guarded"
   expressions such as X::foo(); ...; X::bar() where the
   X is known to exist in the call to bar, and didnt
   handle propagation of information about variables
   properly.
 - Mark type-hints as guaranteed non-null so we can
   avoid guarding on them
 - Mark definitely-not-inited variables
 - Mark definitely-not-reference-typed variables
 - Fix the emitter to handle setting meta-data on
   the inputs of SetL correctly.
2012-07-27 19:37:20 -07:00
smith aa638309c5 Ensure MemoryUsageStats.maxBytes is always valid
In SmartAllocator.alloc() we execute if (hhvm) .. if (m_stats.maxBytes > 0)
on every smart allocation, which is a very hot path.  We can eliminte this
check by just ensuring maxBytes is always valid (use MAX_INT64 instead of
0 or -1 to suppress the check).

Perflab says this saves about 1% CPU time, just above the noise
margin, but CPU instructions are measurably down and it's obviously
good to streamline the allocator hot path.
2012-07-27 19:37:20 -07:00
Sara Golemon 17dfa43dbc Merge branch 'vm' 2012-07-27 18:12:10 -07:00
Sara Golemon 3de465e4d3 Display useful error message when libexecinfo not found on FBSD 2012-07-27 17:29:13 -07:00
Sara Golemon 9fc3af1489 libc-client may also be known as libc-client4 2012-07-27 17:25:57 -07:00
Sara Golemon 33d6f97542 Fix detection of libmemcached >= 1.0 on certain distros 2012-07-27 16:39:29 -07:00
Sara Golemon f90a98da81 Use a function typedef on prop/class lookup/set helpers
Currently, gcc 4.6 is required to build hphp
due to earlier versions being unable to resolve the
function pointer from the template directly into a void*.

By explicitly typedefing these functions, gcc 4.4
(and possibly some earlier versions) can resolve the
function and allow builds to complete.
2012-07-27 11:39:33 -07:00
mwilliams 3b70e847d6 Ensure that Unit::m_mainReturn is static
When we pull a unit from the repo, Unit::m_mainReturn is
made static. But eval bypasses the repo so we need to ensure
its static at emission time too.
2012-07-27 11:39:30 -07:00
aravind 0fbc5c9814 Separate dwarf infor for a and astubs
gdb tends to get confused if we emit dwarf info
for a and astubs together in the same ELF file.
gdb assumes that all ELF files emitted contain
code addresses in contiguous range.
If a single ELF file contains dwarf file for both a and
astubs, gdb assumes all intermediate addresses must
also belong to this ELF file, and this causes
symbol name lookup in gdb to fail for intermediate
addresses that may be present in other ELF files.
2012-07-27 11:39:26 -07:00
Sara Golemon 5da0d4b0b3 Make set_exception_handler()'s return value consistent with PHP 5.3
set_exception_handler() currently can only return a string
which is fine if the prior exception handler was a normal
function.  However the following cases yield incorrect values:

* No prior exception handler set.
* Prior exception handler in array form:
  * array($class, $staticmethod)
  * array($object, $instancemethod)
* Prior exception handler invokable object instance (e.g. lambda)
2012-07-25 11:32:34 -07:00
smith 1bd2c79882 Qualify VectorArray internal calls to avoid indirection
Many code paths in VectorArray invoke ArrayData interface
methods when we know the target is VectorArray.  Qualify
these calls to avoid the indirect call.

Added an inline helper inRange(index, size) function and
use it instead of VectorArray::exists() in several places.
2012-07-25 11:31:02 -07:00
Sara Golemon 8e09ecc237 Fix bug where HphpArray::lvalPtr returned pointer to wrong data 2012-07-24 05:22:13 -07:00
Sara Golemon e2a825dd8e Ignore another Makefile that never should have been checked in. 2012-07-23 21:47:58 -07:00
Sara Golemon 5366fc671e Update pregen source for ext_string hhvm build. 2012-07-23 21:03:51 -07:00
Sara Golemon 4f83a43b7b Replace (DEPRECATED) pcre_info() call with pcre_fullinfo() 2012-07-23 18:13:21 -07:00
Sara Golemon e798e1248c Update strstr() to match PHP 5.3 behavior.
Added third parameter "before_needle" to return inverse of normal strstr() call.
2012-07-23 18:12:18 -07:00
Sara Golemon 14c0e15cbe Fix behavior of str_word_count() (format == 1 || 2) where no words found.
PHP returns an empty array() while HPHP was returning NULL.
Fix HPHP to match PHP's behavior.
2012-07-23 18:09:54 -07:00
Sara Golemon 9a62f804b2 Fix an iterator leak 2012-07-23 13:03:59 -07:00
Sara Golemon cf227f16f5 Fix a translation time type inference bug
The type of the result of SetM isnt always the same as
the type of the rhs. This was leading to incorrect
decrefs, and use-after-free issues.

If we cant prove its the same, mark it as predicted so
we insert a runtime check/side exit.
2012-07-23 13:01:52 -07:00
Sara Golemon 72346e7cd7 Fixup libcurl-7.22.1 patch 2012-07-20 08:31:49 -07:00
Sara Golemon db0b502241 Add libcurl patch file for cURL version 7.22.1 and later 2012-07-20 15:31:09 -07:00
Sara Golemon c58bd58c4e Fix misc array bugs
- array_setm treated all keys as strings if the array
  was not an HphpArray
- iter_value_cell_local, and iter_key_cell_local assumed
  the local was not a reference
2012-07-20 13:31:05 -07:00
Sara Golemon fcfe0638d5 Get rid of a dead helper. 2012-07-20 13:28:53 -07:00
Sara Golemon fa17ca27e5 Use "guarded" information for OpThis and RetC
Static analysis computes a "guarded" flag for various constructs
that can fatal (such as $this->) to indicate that such a construct
has already been seen.

We can use this flag in the translation of OpThis to avoid repeatedly
testing for null, and in the translation of OpRetC to unconditionally
decRef ar->m_this.

Also fixed some compiler generated byte code for closures that was
emitting strings for vector operations (rather than using literals
in the vectors).
2012-07-20 02:07:38 -07:00
Sara Golemon 0d75680885 NULL check in DebuggerProxyVM::getStackDepth()
This was causing a seg fault when DebuggerProxy::processInterrupt() is
called at request start (when m_fp was not set).
2012-07-20 01:49:26 -07:00
Sara Golemon 4fc56eeeb6 Merge FB changes.
Include malloc.h in util/alloc.h when jemalloc unavailable.
Fix bug when extra arguments are passed to a function that creates a Var
Use intrusive list instead of std::list to store VarEnvs chain
Use a freelist embedded inside the object in smart allocator
Fix a potential crash when toString doesnt exist
Garbage-collect the TC.
Fix some use-after-free issues
Fix a couple of fast_tests
Fix verification of static type inference
Dont generate unnecessary guards for type predictions
Enable syslog output.
[tc-print] Clean up types in tc-print
Re-enable the "MayUseVV" optimization
Blacklist a given function/method when hphpd evals inside it
Add missing check for NULL in VariableTable::getVariablePrefix()
[tc-print] Show bc-stats-event_name.txt as a generated file in tc-prod-p
[tc-print] Cosmetic changes to how we print translation summaries
Perform actual liveness check on pfsockopen()
Add an API to control whether exception backtraces include $this objects
Minor typo fix: Annote -> Annotate
[servicerouter] bump fbcode version
[tc-print] Use PEBS-supported events
[tc-print] Collect inclusive stats
Clean up method lookup
Streamline Unit::merge, and reduce size of Unit
2012-07-19 19:22:00 -07:00
Sara Golemon 07a9121d1d Ignore (and do not store) Makefiles which are generated by cmake 2012-07-19 13:15:54 -07:00
Sara Golemon 7492056c28 Define HHVM_PATH to empty string when not building for HHVM 2012-07-19 13:12:00 -07:00
Sara Golemon 96532ec5ec Merge pull request #499 from sebastianbergmann/master
Thanks, Sebastian!
2012-07-14 16:13:18 -07:00
Joel Pobar b0e1933e33 Another jemalloc related fix. 2012-07-13 15:57:45 -07:00
Joel Pobar 626209b786 Fix to make jemalloc work. 2012-07-13 14:56:37 -07:00
Joel Pobar 39415630e8 Latest bits from trunk:
Fix casting resources to strings in the translator
Add request_alloc(); use it for non-ObjectData instead of ALLOCOBJSZ
Take two at reverting short array notation
Make more requires "mergeable"
Fix TestCodeRun-Exit
Change VectorArray to allocate values contiguously
Force file removal in merge-me-to-rc and merge-rc-to-release.
Run all C++ tests on each hphp diff sent out
Fix uncompilable code gen
Move HPHP::VM::Verifier::Arena to HPHP::Arena
Add a TinyVector<> class that can replace some uses of vector; use it some
ServiceRouter: bump version in hphp after single host fix
HPHP: get building with gcc-4.7.1
HPHP extension for textGetHyperlinks
Export translation counters through the hardware counters interface
Fix Makefile
HphpArray methods don't need to be virtual, clean up inline decls.
Remove a few things we don't follow from coding_guideline
Fix bugs with attributes for closures and methods imported from traits
Remove some new using directives that crept in after earlier removal
Add a check for lowercase extension function names in gen_ext_hhvm.php
[tc-print] More detailed summary of events
[tc-print] Changes to tc-prod-collect
Allow COMPILER_ID to be overridden on the command line
Remove boolean args from HphpArray::addVal[WithRef]
Fix NameValueTable load factor check.
Reduce StringBuffer memory usage
Fix compilation errors
Update login for megabench test user
make zend array bucket smaller
Clean up HphpArray code
Fix parser to allow xhp classes as attribute type hints
Enable the use of static analysis types in RepoAuthoritative mode
Fix compilation errors in HphpArray without USE_JEMALLOC
Remove extra element alignment and casting in HphpArray
Revert "HPHP extension for textGetHyperlinks"
bump fbcode revision to include D507348
HPHP extension for textGetHyperlinks
Remove KindOfIndirect support from HphpArray, add new VarEnv implementation
Teach the hhas assembler about string and int vector immediates
Allow ':' to be followed by T_XHP_LABEL
[tc-print] Add top translations summary
Fix string buffer overflows and other issues
Make type-profiling name-driven, and fix bugs.
2012-07-13 14:44:23 -07:00
Jordan DeLong bebaa1ad08 Minor tweak to README.md
Summary: Change wording of intro sentence.
2012-06-28 23:14:55 -07:00
Joel Pobar ec56d1d90f Fix to the verify to prevent cmake build faiure when jemalloc isn't found 2012-06-27 10:10:43 -07:00
Joel Pobar b4a54e9205 Fix to cmake scripts 2012-06-27 09:38:07 -07:00
Joel Pobar 7623d660a8 Latest from HipHop trunk 2012-06-22 15:28:50 -07:00
Joel Pobar a4fbb08028 Adds another required generated file for hhvm 2012-06-07 18:07:26 -07:00
Joel Pobar 4009d7b408 Required generated files for HHVM
Summary: these files should be generated as part of the build process.
Committing for now to unblock build.
2012-06-07 17:23:00 -07:00
Joel Pobar d2fa958a57 Adds a missing file to the previous push 2012-06-07 16:30:57 -07:00
Joel Pobar dcd7a28fd4 Updated to the latest bits, fixed the cmake scripts so that hhvm compiles
Summary: Added plumbing to the cmake scripts to enable hhvm builds.
To build the VM, export USE_HHVM=1, and follow the wiki instructions
to do a clean build.
2012-06-07 15:55:49 -07:00
Sebastian Bergmann a455f654d7 Fugbix typo. 2012-04-02 07:10:35 +02:00
Scott MacVicar e20a731e11 Further vm push 2011-12-12 22:21:00 -08:00
Scott MacVicar 3b481737e9 Initial VM branch -code 2011-12-08 11:14:17 -08:00
9539 arquivos alterados com 991326 adições e 1000316 exclusões
+54 -48
Ver Arquivo
@@ -1,65 +1,71 @@
*.[oad]
*.hhbc
/bin*-g
/bin*-O
/bin/*.so
/bin/tainted_build
/bin/hphp_options
/bin/systemlib.php
.mkdir
hphp.log
/src/compiler/analysis/code_error.inc
/src/compiler/analysis/dependency.inc
/src/runtime/base/memory/smart_allocator.inc_gen
/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/test/test
/src/test/test_fast.inc
/src/test/test_mysql_info.inc
/src/test/test_suite.inc
/src/test/*.tmp
/hphp/runtime/tmp/Test*
/hphp/runtime/tmp/run
/hphp/runtime/tmp/run.sh
/hphp/runtime/tmp/libtest.so
/hphp/runtime/vm/repo_schema.h
/src/hphp/hphp
/hphp/hphpi/gen
/hphp/hphpi/hphpi
/src/runtime/tmp/Test*
/src/runtime/tmp/run
/src/runtime/tmp/run.sh
/src/runtime/tmp/libtest.so
/hphp/hhvm/gen
/hphp/hhvm/hhvm
/src/hphpi/gen
/src/hphpi/hphpi
/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
/facebook/autoload_files
/facebook/hotcold.hdf
/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
/facebook/extensions/*/*.so
/facebook/extensions/string/test_string
/facebook/extensions/photodna/test_photodna
/facebook/extensions/utils/test_utils
/facebook/extensions/fbobj_cache/test_fbobj_cache
/facebook/extensions/fbobj/test_fbobj
/local/*.mk
# Ignore all makefiles generated for fbcode's third-party repo
/bin/*.mk
!/bin/run.mk
CMakeFiles
CMakeCache.txt
cmake_install.cmake
/output_gd/
/hphp/TAGS
# Generated makefiles
/hphp/runtime/ext_hhvm/Makefile
/hphp/test/Makefile
/hphp/hphp/Makefile
/hphp/hhvm/Makefile
/hphp/compiler/Makefile
/hphp/Makefile
/Makefile
# eclipse files
.project
.cproject
.settings
+1 -1
Ver Arquivo
@@ -9,7 +9,7 @@ FIND_PATH(CCLIENT_INCLUDE_PATH
)
FIND_LIBRARY(CCLIENT_LIBRARY
NAMES c-client
NAMES c-client c-client4
PATHS /lib /usr/lib /usr/local/lib /usr/pkg/lib
)
+26
Ver Arquivo
@@ -0,0 +1,26 @@
#
# $Id$
#
# - Find libglog
# Find libglog
#
# LIBGLOG_INCLUDE_DIR - where to find glog/logging.h, etc.
# LIBGLOG_LIBRARY - List of libraries when using libglog.
# LIBGLOG_FOUND - True if libglog found.
IF (LIBGLOG_INCLUDE_DIR)
# Already in cache, be silent
SET(LIBGLOG_FIND_QUIETLY TRUE)
ENDIF ()
FIND_PATH(LIBGLOG_INCLUDE_DIR glog/logging.h)
FIND_LIBRARY(LIBGLOG_LIBRARY glog)
# handle the QUIETLY and REQUIRED arguments and set Libmemcached_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBGLOG DEFAULT_MSG LIBGLOG_LIBRARY LIBGLOG_INCLUDE_DIR)
MARK_AS_ADVANCED(LIBGLOG_LIBRARY LIBGLOG_INCLUDE_DIR)
+54
Ver Arquivo
@@ -0,0 +1,54 @@
# - Try to find libdwarf
# Once done this will define
#
# LIBDWARF_FOUND - system has libdwarf
# LIBDWARF_INCLUDE_DIRS - the libdwarf include directory
# LIBDWARF_LIBRARIES - Link these to use libdwarf
# LIBDWARF_DEFINITIONS - Compiler switches required for using libdwarf
#
# Locate libelf library at first
if (NOT LIBELF_FOUND)
find_package (LibElf REQUIRED)
endif (NOT LIBELF_FOUND)
if (LIBDWARF_LIBRARIES AND LIBDWARF_INCLUDE_DIRS)
set (LibDwarf_FIND_QUIETLY TRUE)
endif (LIBDWARF_LIBRARIES AND LIBDWARF_INCLUDE_DIRS)
find_path (DWARF_INCLUDE_DIR
NAMES
dwarf.h
PATHS
/usr/include
/usr/include/libdwarf
/usr/local/include
/opt/local/include
/sw/include
ENV CPATH) # PATH and INCLUDE will also work
if (DWARF_INCLUDE_DIR)
set (LIBDWARF_INCLUDE_DIRS ${DWARF_INCLUDE_DIR})
endif ()
find_library (LIBDWARF_LIBRARIES
NAMES
dwarf
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
ENV LIBRARY_PATH # PATH and LIB will also work
ENV LD_LIBRARY_PATH)
include (FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBDWARF_FOUND to TRUE
# if all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibDwarf DEFAULT_MSG
LIBDWARF_LIBRARIES
LIBDWARF_INCLUDE_DIRS)
mark_as_advanced(LIBDW_INCLUDE_DIR DWARF_INCLUDE_DIR)
mark_as_advanced(LIBDWARF_INCLUDE_DIRS LIBDWARF_LIBRARIES)
+55
Ver Arquivo
@@ -0,0 +1,55 @@
# - Try to find libelf
# Once done this will define
#
# LIBELF_FOUND - system has libelf
# LIBELF_INCLUDE_DIRS - the libelf include directory
# LIBELF_LIBRARIES - Link these to use libelf
# LIBELF_DEFINITIONS - Compiler switches required for using libelf
#
# Copyright (c) 2008 Bernhard Walle <bernhard.walle@gmx.de>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
if (LIBELF_LIBRARIES AND LIBELF_INCLUDE_DIRS)
set (LibElf_FIND_QUIETLY TRUE)
endif (LIBELF_LIBRARIES AND LIBELF_INCLUDE_DIRS)
find_path (LIBELF_INCLUDE_DIRS
NAMES
libelf.h
PATHS
/usr/include
/usr/include/libelf
/usr/local/include
/usr/local/include/libelf
/opt/local/include
/opt/local/include/libelf
/sw/include
/sw/include/libelf
ENV CPATH)
find_library (LIBELF_LIBRARIES
NAMES
elf
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
ENV LIBRARY_PATH
ENV LD_LIBRARY_PATH)
include (FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBELF_FOUND to TRUE if all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibElf DEFAULT_MSG
LIBELF_LIBRARIES
LIBELF_INCLUDE_DIRS)
mark_as_advanced(LIBELF_INCLUDE_DIRS LIBELF_LIBRARIES)
+3 -3
Ver Arquivo
@@ -12,14 +12,14 @@ endforeach()
find_path(LIBEVENT_INCLUDE_DIR event.h PATHS ${LibEvent_INCLUDE_PATHS})
find_library(LIBEVENT_LIB NAMES event PATHS ${LibEvent_LIB_PATHS})
if (LIBEVENT_LIB AND LIBEVENT_INCLUDE_DIR)
set(LibEvent_FOUND TRUE)
set(LIBEVENT_LIB ${LIBEVENT_LIB})
else ()
set(LibEvent_FOUND FALSE)
endif ()
if (LibEvent_FOUND)
if (NOT LibEvent_FIND_QUIETLY)
message(STATUS "Found libevent: ${LIBEVENT_LIB}")
@@ -30,7 +30,7 @@ else ()
endif ()
message(STATUS "libevent NOT found.")
endif ()
mark_as_advanced(
LIBEVENT_LIB
LIBEVENT_INCLUDE_DIR
+4
Ver Arquivo
@@ -0,0 +1,4 @@
find_path(LibXed_INCLUDE_DIR xed-interface.h)
find_library(LibXed_LIBRARY NAMES xed)
mark_as_advanced(LibXed_INCLUDE_DIR LibXed_LIBRARY)
+42
Ver Arquivo
@@ -0,0 +1,42 @@
#
# $Id$
#
# - Find libiconv
# Find libiconv
#
# LIBICONV_INCLUDE_DIR - where to find iconv.h, etc.
# LIBICONV_LIBRARY - List of libraries when using libiconv.
# LIBICONV_FOUND - True if libiconv found.
IF (LIBICONV_INCLUDE_DIR)
# Already in cache, be silent
SET(LIBICONV_FIND_QUIETLY TRUE)
ENDIF ()
FIND_PATH(LIBICONV_INCLUDE_DIR iconv.h)
FIND_LIBRARY(LIBICONV_LIBRARY iconv)
# handle the QUIETLY and REQUIRED arguments and set Libmemcached_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBICONV DEFAULT_MSG LIBICONV_LIBRARY LIBICONV_INCLUDE_DIR)
SET(LIBICONV_OLD_CMAKE_REQUIRED_LIBRARIES)
SET(CMAKE_REQUIRED_LIBRARIES iconv)
INCLUDE(CheckCXXSourceCompiles)
CHECK_CXX_SOURCE_COMPILES("#include <string.h>
#include <iconv.h>
int main() {
iconv_t cd = 0;
const char *in_p = \"testing\";
size_t in_left = strlen(in_p);
char out_p[20];
size_t out_left = sizeof(out_p);
iconv(cd, (const char **)&in_p, &in_left, (char **)&out_p, &out_left);
return 0;
}" LIBICONV_CONST)
SET(CMAKE_REQUIRED_LIBRARIES LIBICONV_OLD_CMAKE_REQUIRED_LIBRARIES)
MARK_AS_ADVANCED(LIBICONV_LIBRARY LIBICONV_INCLUDE_DIR LIBICONV_CONST)
+23
Ver Arquivo
@@ -0,0 +1,23 @@
#
# $Id$
#
# - Find libinotify
# Find libinotify
#
# LIBINOTIFY_INCLUDE_DIR - where to find sys/inotify.h
# LIBINOTIFY_LIBRARY - List of libraries when using libinotify
# LIBINOTIFY_FOUND - True if libinotify found.
if(LIBINOTIFY_INCLUDE_DIR)
# Already in cache, be silent
SET(LIBINOTIFY_FIND_QUIETLY TRUE)
endif()
FIND_PATH(LIBINOTIFY_INCLUDE_DIR sys/inotify.h)
FIND_LIBRARY(LIBINOTIFY_LIBRARY inotify)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBINOTIFY DEFAULT_MSG LIBINOTIFY_LIBRARY LIBINOTIFY_INCLUDE_DIR)
MARK_AS_ADVANCED(LIBINOTIFY_LIBRARY LIBINOTIFY_INCLUDE_DIR)
+7 -2
Ver Arquivo
@@ -27,8 +27,13 @@ SET(LIBMEMCACHED_VERSION 0)
IF(LIBMEMCACHED_FOUND)
if (EXISTS "${LIBMEMCACHED_INCLUDE_DIR}/libmemcached/configure.h")
FILE(READ "${LIBMEMCACHED_INCLUDE_DIR}/libmemcached/configure.h" _MEMCACHE_VERSION_CONENTS)
STRING(REGEX REPLACE ".*#define LIBMEMCACHED_VERSION_STRING \"([0-9.]+)\".*" "\\1" LIBMEMCACHED_VERSION "${_MEMCACHE_VERSION_CONENTS}")
FILE(READ "${LIBMEMCACHED_INCLUDE_DIR}/libmemcached/configure.h" _MEMCACHE_VERSION_CONTENTS)
endif()
if (EXISTS "${LIBMEMCACHED_INCLUDE_DIR}/libmemcached-1.0/configure.h")
FILE(READ "${LIBMEMCACHED_INCLUDE_DIR}/libmemcached-1.0/configure.h" _MEMCACHE_VERSION_CONTENTS)
endif()
if (_MEMCACHE_VERSION_CONTENTS)
STRING(REGEX REPLACE ".*#define LIBMEMCACHED_VERSION_STRING \"([0-9.]+)\".*" "\\1" LIBMEMCACHED_VERSION "${_MEMCACHE_VERSION_CONTENTS}")
endif()
ENDIF()
+28
Ver Arquivo
@@ -0,0 +1,28 @@
#
# $Id$
#
# - Find libunwind
# Find libunwind
#
# LIBUNWIND_INCLUDE_DIR - where to find unwind.h and libunwind.h
# LIBUNWIND_LIBRARY - List of libraries when using libunwind
# LIBUNWIND_FOUND - True if libunwind found.
if(LIBUNWIND_INCLUDE_DIR)
# Already in cache, be silent
SET(LIBUNWIND_FIND_QUIETLY TRUE)
endif()
FIND_PATH(LIBUNWIND_INCLUDE_DIR libunwind.h)
if(NOT EXISTS "${LIBUNWIND_INCLUDE_DIR}/unwind.h")
message(FATAL_ERROR "libunwind.h found without matching unwind.h")
SET(LIBUNWIND_INCLUDE_DIR "")
endif()
FIND_LIBRARY(LIBUNWIND_LIBRARY unwind)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUNWIND DEFAULT_MSG LIBUNWIND_LIBRARY LIBUNWIND_INCLUDE_DIR)
MARK_AS_ADVANCED(LIBUNWIND_LIBRARY LIBUNWIND_INCLUDE_DIR)
+89 -35
Ver Arquivo
@@ -19,15 +19,38 @@ 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})
# features.h
FIND_PATH(FEATURES_HEADER features.h)
if (FEATURES_HEADER)
add_definitions("-DHAVE_FEATURES_H=1")
endif()
# google-glog
find_package(Glog REQUIRED)
include_directories(${LIBGLOG_INCLUDE_DIR})
# inotify checks
find_package(Libinotify)
if (LIBINOTIFY_INCLUDE_DIR)
include_directories(${LIBINOTIFY_INCLUDE_DIR})
endif()
# unwind checks
find_package(Libunwind REQUIRED)
include_directories(${LIBUNWIND_INCLUDE_DIR})
# iconv checks
find_package(Libiconv REQUIRED)
include_directories(${LIBICONV_INCLUDE_DIR})
if (LIBICONV_CONST)
message(STATUS "Using const for input to iconv() call")
add_definitions("-DICONV_CONST=const")
endif()
# mysql checks
find_package(MySQL REQUIRED)
include_directories(${MYSQL_INCLUDE_DIR})
@@ -76,19 +99,25 @@ else ()
# nothing for now
endif()
find_package(LibXed)
if (LibXed_INCLUDE_DIR AND LibXed_LIBRARY)
include_directories(${LibXed_INCLUDE_DIR})
add_definitions(-DHAVE_LIBXED)
endif()
# CURL checks
find_package(CURL REQUIRED)
include_directories(${CURL_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES "${CURL_LIBRARIES}")
CHECK_FUNCTION_EXISTS("curl_multi_select" HAVE_CUSTOM_CURL)
if (NOT HAVE_CUSTOM_CURL)
unset(HAVE_CUSTOM_CURL CACHE)
unset(CURL_INCLUDE_DIR CACHE)
unset(CURL_LIBRARIES CACHE)
unset(CURL_FOUND CACHE)
message(FATAL_ERROR "Custom libcurl is required with the HipHop patch")
endif ()
CHECK_FUNCTION_EXISTS("curl_multi_select" HAVE_CURL_MULTI_SELECT)
CHECK_FUNCTION_EXISTS("curl_multi_wait" HAVE_CURL_MULTI_WAIT)
if (HAVE_CURL_MULTI_SELECT)
add_definitions("-DHAVE_CURL_MULTI_SELECT")
endif()
if (HAVE_CURL_MULTI_WAIT)
add_definitions("-DHAVE_CURL_MULTI_WAIT")
endif()
set(CMAKE_REQUIRED_LIBRARIES)
# LibXML2 checks
@@ -100,12 +129,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}/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")
FIND_LIBRARY(XHP_LIB xhp)
FIND_PATH(XHP_INCLUDE_DIR xhp_preprocess.hpp)
@@ -114,7 +146,7 @@ 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")
include_directories("${HPHP_HOME}/hphp/third_party/xhp/xhp")
endif()
# ICU
@@ -160,16 +192,8 @@ if (USE_JEMALLOC AND NOT GOOGLE_TCMALLOC_ENABLED
AND NOT CMAKE_BUILD_TYPE STREQUAL Debug)
FIND_LIBRARY(JEMALLOC_LIB jemalloc)
if (JEMALLOC_LIB)
CHECK_LIBRARY_EXISTS(jemalloc mallctl "" HAVE_JEMALLOC_FUN)
if (HAVE_JEMALLOC_FUN)
message(STATUS "Found jemalloc: ${JEMALLOC_LIB}")
set(JEMALLOC_ENABLED 1)
else()
message(STATUS "Found jemalloc at ${JEMALLOC_LIB}, but unable to find its API "
"(maybe the library was configured with a non-empty function prefix?)")
endif()
else()
message(STATUS "Can't find jemalloc")
message(STATUS "Found jemalloc: ${JEMALLOC_LIB}")
set(JEMALLOC_ENABLED 1)
endif()
endif()
@@ -203,11 +227,11 @@ endif()
# tbb libs
find_package(TBB REQUIRED)
if (${TBB_INTERFACE_VERSION} LESS 3016)
if (${TBB_INTERFACE_VERSION} LESS 5005)
unset(TBB_FOUND CACHE)
unset(TBB_INCLUDE_DIRS CACHE)
unset(TBB_LIBRARIES CACHE)
message(FATAL_ERROR "TBB is too old, please install a newer version")
message(FATAL_ERROR "TBB is too old, please install at least 3.0(5005), preferably 4.0(6000) or higher")
endif()
include_directories(${TBB_INCLUDE_DIRS})
link_directories(${TBB_LIBRARY_DIRS})
@@ -247,6 +271,12 @@ include_directories(${READLINE_INCLUDE_DIR})
find_package(CClient REQUIRED)
include_directories(${CCLIENT_INCLUDE_PATH})
find_package(LibDwarf REQUIRED)
include_directories(${LIBDWARF_INCLUDE_DIRS})
find_package(LibElf REQUIRED)
include_directories(${LIBELF_INCLUDE_DIRS})
CONTAINS_STRING("${CCLIENT_INCLUDE_PATH}/utf8.h" U8T_DECOMPOSE RECENT_CCLIENT)
if (NOT RECENT_CCLIENT)
unset(RECENT_CCLIENT CACHE)
@@ -304,6 +334,9 @@ endif()
if (FREEBSD)
FIND_LIBRARY (EXECINFO_LIB execinfo)
if (NOT EXECINFO_LIB)
message(FATAL_ERROR "You need to install libexecinfo")
endif()
endif()
#find_package(BISON REQUIRED)
@@ -313,8 +346,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)
@@ -332,11 +365,26 @@ macro(hphp_link target)
endif()
target_link_libraries(${target} ${Boost_LIBRARIES})
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} ${LIBEVENT_LIB})
target_link_libraries(${target} ${CURL_LIBRARIES})
target_link_libraries(${target} ${LIBGLOG_LIBRARY})
if (LibXed_LIBRARY)
target_link_libraries(${target} ${LibXed_LIBRARY})
endif()
if (LIBINOTIFY_LIBRARY)
target_link_libraries(${target} ${LIBINOTIFY_LIBRARY})
endif()
if (LIBICONV_LIBRARY)
target_link_libraries(${target} ${LIBICONV_LIBRARY})
endif()
if (LINUX)
target_link_libraries(${target} ${CAP_LIB})
@@ -380,6 +428,9 @@ endif()
target_link_libraries(${target} timelib)
target_link_libraries(${target} sqlite3)
target_link_libraries(${target} lz4)
target_link_libraries(${target} double-conversion)
target_link_libraries(${target} folly)
if (SKIP_BUNDLED_XHP)
target_link_libraries(${target} ${XHP_LIB})
@@ -398,4 +449,7 @@ endif()
target_link_libraries(${target} ${PAM_LIBRARY})
endif()
target_link_libraries(${target} ${LIBDWARF_LIBRARIES})
target_link_libraries(${target} ${LIBELF_LIBRARIES})
endmacro()
+16 -9
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 < 40300
#error Need GCC 4.3.0+
#if GCC_VERSION < 40400
#error Need GCC 4.4.0+
#endif
int main() { return 0; }" HAVE_GCC_43)
int main() { return 0; }" HAVE_GCC_44)
if(NOT HAVE_GCC_43)
message(FATAL_ERROR "Need at least GCC 4.3")
if(NOT HAVE_GCC_44)
message(FATAL_ERROR "Need at least GCC 4.4")
endif()
endif()
@@ -46,9 +46,15 @@ include(HPHPFunctions)
include(HPHPFindLibs)
add_definitions(-D_GNU_SOURCE -D_REENTRANT=1 -D_PTHREADS=1)
add_definitions(-DHHVM_LIB_PATH_DEFAULT="${HPHP_HOME}/bin")
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)
@@ -111,10 +117,10 @@ endif()
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-parentheses -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names")
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)
@@ -125,5 +131,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})
+9 -4
Ver Arquivo
@@ -20,10 +20,15 @@ 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(STATUS "------------")
message(STATUS "32-bit support is experimental, things may be broken")
message(STATUS "------------")
message(FATAL_ERROR "32-bit support is currently unsupported, check back with a later version of HipHop")
ENDIF()
if ("$ENV{USE_HHVM}" STREQUAL "1")
message("Building for HHVM")
endif()
if ("$ENV{USE_HPHPC}" STREQUAL "1")
message(FATAL_ERROR "Building HPHPc is no longer supported")
endif()
-66
Ver Arquivo
@@ -1,66 +0,0 @@
PROJECT_ROOT = .
include src/dirs.mk
TEST := $(if $(OUT_TOP),$(OUT_TOP),test/)test
TOBUILD := $(filter clean% clobber% both debug release, $(MAKECMDGOALS))
CLEAN := $(filter clean% clobber%,$(MAKECMDGOALS))
TOTEST := $(filter-out $(TOBUILD), $(MAKECMDGOALS))
ifeq ($(if $(TOBUILD),1)$(if $(TOTEST),1),11)
$(TOTEST) : $(TOBUILD)
endif
ifneq ($(filter fast_tests slow_tests $(FAST_TESTS) $(SLOW_TESTS) TestCodeRun%,$(MAKECMDGOALS)),)
# run all tests, even if some fail
MAKEFLAGS += k
.NOTPARALLEL:
endif
QuickTests = "" "" $@
TestExt = "" "" $@
FAST_TESTS := QuickTests TestExt TestCodeRunEval
SLOW_TESTS := TestCodeRun TestServer
all: fast_tests
tags: ctags etags
ctags:
-$(V)cd src && ct
etags:
-$(V)cd src && ct -e
.PHONY: tags ctags etags
$(FAST_TESTS) $(SLOW_TESTS) TestCodeRunStatic: % : setup
cd src && $(TEST) $(if $($@),$($@),$@)
setup: $(CLEAN)
$(MAKE) -C src
fast_tests: $(FAST_TESTS)
slow_tests: $(SLOW_TESTS)
.PHONY: $(FAST_TESTS) $(SLOW_TESTS) TestCodeRun%
TestCodeRun-% TestCodeRunEval-% TestCodeRunStatic-% TestServer-% : setup
cd src && $(TEST) $(patsubst %-$*,%,$@) Test$*
.PHONY: debug release both check_by_type fast_tests slow_tests setup
check_by_type: $(CLEAN)
@if [ -z "$$OUTDIR_BY_TYPE" ] ; then \
echo "You need to set OUTDIR_BY_TYPE to build both DEBUG and RELEASE into the same client"; \
exit 1; \
fi
release: check_by_type
$(MAKE) -Csrc RELEASE=1 DEBUG=
debug: check_by_type
$(MAKE) -Csrc RELEASE= DEBUG=1
both: debug release
clobber:
$(MAKE) -C src clobber
$(MAKE) -C facebook clobber
clean: clobber
+8 -3
Ver Arquivo
@@ -1,6 +1,6 @@
# HipHop for PHP
HipHop is a source code transformer which transforms PHP source code into highly optimized C++ and then compiles it using g++. Currently supported platforms are Linux and FreeBSD. There is no OS X support.
HipHop is a high performance PHP toolchain. Currently supported platforms are Linux and FreeBSD. There is no OS X support.
* [Developer Mailing List](http://groups.google.com/group/hiphop-php-dev)
* [Wiki](http://wiki.github.com/facebook/hiphop-php)
@@ -30,13 +30,18 @@ The latest information is available on the [wiki](http://wiki.github.com/faceboo
* libpcre
* libexpat
* libmemcached
* google-glog (http://code.google.com/p/google-glog/)
* libc-client2007
* libdwarf
* libelf
* libunwind
The following packages have had slight modifications added to them. Patches are provided and should be made against the current source copies.
* [libcurl](http://curl.haxx.se/download.html)
* src/third_party/libcurl.fb-changes.diff
* hphp/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
* hphp/third_party/libevent-1.4.14.fb-changes.diff
## Installation
-83
Ver Arquivo
@@ -1,83 +0,0 @@
#
# +----------------------------------------------------------------------+
# | 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. |
# +----------------------------------------------------------------------+
#
CMAKE_MINIMUM_REQUIRED(VERSION 2.6.4 FATAL_ERROR)
PROJECT(hphp C CXX)
IF("$ENV{HPHP_HOME}" STREQUAL "")
message(FATAL_ERROR "You should set the HPHP_HOME environmental")
ENDIF()
file(TO_CMAKE_PATH "$ENV{HPHP_HOME}" HPHP_HOME)
IF(NOT IS_DIRECTORY ${HPHP_HOME})
message(FATAL_ERROR "The value of HPHP_HOME does not exist")
ENDIF()
IF(NOT EXISTS "${HPHP_HOME}/LICENSE.PHP")
message(FATAL_ERROR "The value of HPHP_HOME in incorrect")
ENDIF()
SET(CMAKE_MODULE_PATH "${HPHP_HOME}/CMake" ${CMAKE_MODULE_PATH})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include(HPHPFunctions)
include(CheckFunctionExists)
include(HPHPSetup)
if ("${PROGRAM_NAME}" STREQUAL "")
set(PROGRAM_NAME program)
endif()
auto_sources(SOURCES "*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}")
add_executable(${PROGRAM_NAME} ${SOURCES})
foreach (SOURCE_FILE ${SOURCES})
if(${SOURCE_FILE} MATCHES ".no.cpp$")
SET_SOURCE_FILES_PROPERTIES(
${SOURCE_FILE}
PROPERTIES
COMPILE_FLAGS -O0
)
endif()
endforeach()
add_library(libhphp_runtime STATIC IMPORTED)
SET_PROPERTY(TARGET libhphp_runtime PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libhphp_runtime.a")
add_library(timelib STATIC IMPORTED)
SET_PROPERTY(TARGET timelib PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libtimelib.a")
add_library(sqlite3 STATIC IMPORTED)
SET_PROPERTY(TARGET sqlite3 PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libsqlite3.a")
if (NOT SKIP_BUNDLED_XHP)
add_library(xhp STATIC IMPORTED)
SET_PROPERTY(TARGET xhp PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libxhp.a")
endif()
add_library(afdt STATIC IMPORTED)
SET_PROPERTY(TARGET afdt PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libafdt.a")
add_library(mbfl STATIC IMPORTED)
SET_PROPERTY(TARGET mbfl PROPERTY IMPORTED_LOCATION "${HPHP_HOME}/bin/libmbfl.a")
target_link_libraries(${PROGRAM_NAME} libhphp_runtime)
hphp_link(${PROGRAM_NAME})
+1
Ver Arquivo
@@ -0,0 +1 @@
This file just exists to keep the bin/ directory in git.
-72
Ver Arquivo
@@ -1,72 +0,0 @@
#!/usr/local/bin/php
<?php
define('MSG_MAX_SIZE', 10 * 1024 * 1024);
$p = $argv[1];
$q = msg_get_queue(ftok($p, 'a'));
if ($q === false) {
die('failed to get the message queue at '.$p);
}
if (!msg_send($q, 2, "CRUTCH")) {
die('failed to send startup signal');
}
$Objects = array(); // All resources or objects we have created so far
$ObjectIndex = 1;
while (true) {
$msg = null;
if (msg_receive($q, 1, $type, MSG_MAX_SIZE, $msg)) {
if ($type <= 0) break;
$i = 0;
$func = $msg[$i++];
$schema = $msg[$i++];
$count = $msg[$i++];
$args = $msg[$i++];
if ($schema) {
foreach ($schema as $index => $param) {
if ($index >= 0 && $param[0] == 'O' && $args[$index]) {
$original_msg[$index] = $args[$index];
$args[$index] = $Objects[$args[$index]];
}
}
}
$expr = '$ret = $func(';
for ($i = 0; $i < $count; $i++) {
if ($i > 0) $expr .= ',';
$expr .= '$args['.$i.']';
}
$expr .= ');';
eval($expr);
if ($schema) {
$refs = array();
foreach ($schema as $index => $param) {
if ($param == 'R' /* Reference */) {
$refs[$index] = $args[$index];
} else if ($param == 'OO' /* Object/Resource Output */) {
if ($index < 0) {
if ($ret) {
$Objects[$ObjectIndex] = $ret;
$ret = $ObjectIndex++;
}
} else {
$newobj = $args[$index];
$oldobj = $Objects[$original_msg[$index]];
if ($newobj && $newobj !== $oldobj) {
$Objects[$ObjectIndex] = $newobj;
$refs[$index] = $ObjectIndex++;
}
}
}
}
}
$response = array($ret, $refs);
if (!msg_send($q, 2, $response)) break;
}
}
-35
Ver Arquivo
@@ -1,35 +0,0 @@
<?php
$file = isset($argv[1]) ? $argv[1] : '/tmp/distcc_timer.log';
$lines = array();
exec("cat $file", $lines);
$time = array();
$machines = array();
foreach ($lines as $line) {
preg_match('/([^ ]+) @ ([^ ]+)/', $line, $m);
$filename = $m[1];
$machine = $m[2];
if (!isset($machines[$machine])) $machines[$machine] = 0;
++$machines[$machine];
preg_match('/pp start: +([0-9]+)/', $line, $m); $pp0 = $m[1];
preg_match('/pp end: +([0-9]+)/', $line, $m); $pp1 = $m[1];
preg_match('/remote start: +([0-9]+)/', $line, $m); $cc0 = $m[1];
preg_match('/remote end: +([0-9]+)/', $line, $m); $cc1 = $m[1];
$preprocessing = $pp1 - $pp0;
$compiling = $cc1 - $cc0;
if ($preprocessing >= 10) {
echo "preprocessing: $preprocessing, compiling: $compiling --> $filename\n";
}
$time[$filename] = $compiling;
}
function cmp($a, $b) {
if ($a === $b) return 0;
return ($a > $b) ? 1 : -1;
}
uasort($time, 'cmp');
foreach ($time as $filename => $compiling) {
echo "compiling: $compiling --> $filename\n";
}
var_dump($machines);
-3
Ver Arquivo
@@ -1,3 +0,0 @@
drop table run;
drop table dep;
drop table err;
-28
Ver Arquivo
@@ -1,28 +0,0 @@
<?php
$server = $argv[1];
$password = @$argv[2];
$polling = isset($argv[3]) ? $argv[3] : 1;
$total = array();
$total[0] = $total[1] = $total[2] = $total[3] = $total[4] = 0;
while (true) {
$ret = shell_exec("GET http://$server/prof-exe?auth=$password");
$nums = json_decode($ret);
for ($i = 0; $i < count($nums); $i++) {
$num = $nums[$i];
if ($num == -1) break;
$total[$num] += $nums[++$i];
}
$sum = /* $total[1] + */ $total[2] + $total[3];
$out = '';
//$out .= sprintf("Server: %2d%%\t", (int)($total[1] * 100 / $sum));
$out .= sprintf("Extension: %2d%%\t", (int)($total[2] * 100 / $sum));
$out .= sprintf("User: %2d%%\n", (int)($total[3] * 100 / $sum));
echo $out;
sleep($polling);
}
-34
Ver Arquivo
@@ -1,34 +0,0 @@
<?php
chdir(preg_replace('#/bin/ext_injection.php$#', '/src', realpath(__FILE__)));
// parse all these files
$inputs = 'find . -name ext_*.cpp';
$files = array();
exec($inputs, $files);
foreach ($files as $file) {
$contents = file_get_contents($file);
if ($contents === false) {
exit("unable to read $file\n");
}
$pattern = '/c_(\w+)::t_(\w+)([^\{\}]*)\{([\n\t ]+)'.
'(?:\w+INJECTION(?:_BUILTIN|)\([\w:, ]+\);[\n\t ]+)?([^\}])/s';
$replace = "c_\${1}::t_\${2}\${3}{\n ".
"INSTANCE_METHOD_INJECTION_BUILTIN(\${1}, \${1}::\${2});\${4}\${5}";
$replaced = preg_replace($pattern, $replace, $contents);
$pattern = '/c_(\w+)::ti_(\w+)([^\{\}]*)\{([\n\t ]+)'.
'(?:\w+INJECTION(?:_BUILTIN|)\([\w:, ]+\);[\n\t ]+)?([^\}])/s';
$replace = "c_\${1}::ti_\${2}\${3}{\n ".
"STATIC_METHOD_INJECTION_BUILTIN(\${1}, \${1}::\${2});\${4}\${5}";
$replaced = preg_replace($pattern, $replace, $replaced);
if ($replaced && $replaced !== $contents) {
file_put_contents($file, $replaced);
print "updated $file\n";
}
}
-145
Ver Arquivo
@@ -1,145 +0,0 @@
<?php
/**
* The file is generated on a PHP 5.3 machine with one line of PHP code:
*
* <?php
* echo '<?php $php53 = ';
* var_export(get_defined_constants());
* echo ";\n";
*
*/
$php53 = array();
@include $argv[1];
$constants = get_defined_constants();
///////////////////////////////////////////////////////////////////////////////
// imap constants
$constants['NIL'] = 0;
$constants['IMAP_OPENTIMEOUT'] = 1;
$constants['IMAP_READTIMEOUT'] = 2;
$constants['IMAP_WRITETIMEOUT'] = 3;
$constants['IMAP_CLOSETIMEOUT'] = 4;
$constants['OP_DEBUG'] = 1;
$constants['OP_READONLY'] = 2;
$constants['OP_ANONYMOUS'] = 4;
$constants['OP_SHORTCACHE'] = 8;
$constants['OP_SILENT'] = 16;
$constants['OP_PROTOTYPE'] = 32;
$constants['OP_HALFOPEN'] = 64;
$constants['OP_EXPUNGE'] = 128;
$constants['OP_SECURE'] = 256;
$constants['CL_EXPUNGE'] = 32768;
$constants['FT_UID'] = 1;
$constants['FT_PEEK'] = 2;
$constants['FT_NOT'] = 4;
$constants['FT_INTERNAL'] = 8;
$constants['FT_PREFETCHTEXT'] = 32;
$constants['ST_UID'] = 1;
$constants['ST_SILENT'] = 2;
$constants['ST_SET'] = 4;
$constants['CP_UID'] = 1;
$constants['CP_MOVE'] = 2;
$constants['SE_UID'] = 1;
$constants['SE_FREE'] = 2;
$constants['SE_NOPREFETCH'] = 4;
$constants['SO_FREE'] = 8;
$constants['SO_NOSERVER'] = 16;
$constants['SA_MESSAGES'] = 1;
$constants['SA_RECENT'] = 2;
$constants['SA_UNSEEN'] = 4;
$constants['SA_UIDNEXT'] = 8;
$constants['SA_UIDVALIDITY'] = 16;
$constants['SA_ALL'] = 31;
$constants['LATT_NOINFERIORS'] = 1;
$constants['LATT_NOSELECT'] = 2;
$constants['LATT_MARKED'] = 4;
$constants['LATT_UNMARKED'] = 8;
$constants['LATT_REFERRAL'] = 16;
$constants['LATT_HASCHILDREN'] = 32;
$constants['LATT_HASNOCHILDREN'] = 64;
$constants['SORTDATE'] = 0;
$constants['SORTARRIVAL'] = 1;
$constants['SORTFROM'] = 2;
$constants['SORTSUBJECT'] = 3;
$constants['SORTTO'] = 4;
$constants['SORTCC'] = 5;
$constants['SORTSIZE'] = 6;
$constants['TYPETEXT'] = 0;
$constants['TYPEMULTIPART'] = 1;
$constants['TYPEMESSAGE'] = 2;
$constants['TYPEAPPLICATION'] = 3;
$constants['TYPEAUDIO'] = 4;
$constants['TYPEIMAGE'] = 5;
$constants['TYPEVIDEO'] = 6;
$constants['TYPEMODEL'] = 7;
$constants['TYPEOTHER'] = 8;
$constants['ENC7BIT'] = 0;
$constants['ENC8BIT'] = 1;
$constants['ENCBINARY'] = 2;
$constants['ENCBASE64'] = 3;
$constants['ENCQUOTEDPRINTABLE'] = 4;
$constants['ENCOTHER'] = 5;
// HPHP system constants
$constants['HPHP_TRIM_CHARLIST'] = " \n\r\t\v\0";
$constants['GLOBAL_STATE_IGNORE'] = 0;
$constants['GLOBAL_STATE_OVERWRITE'] = 1;
$constants['GLOBAL_STATE_SKIP'] = 2;
$constants['GLOBAL_SYMBOL_GLOBAL_VARIABLE'] = 0;
$constants['GLOBAL_SYMBOL_STATIC_VARIABLE'] = 1;
$constants['GLOBAL_SYMBOL_CLASS_STATIC'] = 2;
$constants['GLOBAL_SYMBOL_DYNAMIC_CONSTANT'] = 3;
$constants['GLOBAL_SYMBOL_FILE_INCLUDE'] = 4;
$constants['GLOBAL_SYMBOL_REDECLARED_FUNCTION'] = 5;
$constants['GLOBAL_SYMBOL_REDECLARED_CLASS'] = 6;
// extra constants
$constants['PHP_VERSION'] = '5.3.3.hiphop';
$constants['HPHP_VERSION'] = '1.0.0';
$constants['CLOCK_REALTIME'] = 0;
$constants['CLOCK_MONOTONIC'] = 1;
$constants['CLOCK_PROCESS_CPUTIME_ID'] = 2;
$constants['CLOCK_THREAD_CPUTIME_ID'] = 3;
$constants['INI_SCANNER_NORMAL'] = 0;
$constants['INI_SCANNER_RAW'] = 1;
// HPHP has different values for these
unset($php53['PHP_VERSION']);
// PHP 5.3 constants
foreach ($php53 as $name => $value) {
// hzhao: only updating token values for now
if (!preg_match('/^(E|T)_/', $name)) continue;
if (isset($constants[$name]) && $constants[$name] !== $value) {
error_log("PHP 5.3 change: $name: $constants[$name] => $value");
}
$constants[$name] = $value;
}
// sort by key
ksort($constants);
///////////////////////////////////////////////////////////////////////////////
print "<?php\n";
print "// @generated by gen_constants. Do NOT edit.\n\n";
foreach ($constants as $name => $value) {
if (is_resource($value)) continue;
if ($name == 'INF' || $name == 'NAN') continue;
if (is_string($value) && preg_match('|/usr/local/|', $value)) {
$value = '';
}
$str = var_export($value, true);
// PHP has a bug, turning "\0" incorrectly into '\000', not "\000"
if (is_string($value)) {
$str = '"' . substr($str, 1, strlen($str) - 2) . '"';
}
print "define('$name', $str);\n";
}
-88
Ver Arquivo
@@ -1,88 +0,0 @@
;; Better HDF read/write experience in emacs (9/25/09 hzhao@facebook.com)
(require 'font-lock)
(defvar hdf-mode-hook nil)
(add-to-list 'auto-mode-alist '("\\.hdf\\'" . hdf-mode))
(defvar hdf-indent-level 2
"Defines 2 spaces for HDF indentation.")
;; syntax coloring
;; http://www.gnu.org/software/emacs/elisp/html_node/Faces-for-Font-Lock.html
(defconst hdf-font-lock-keywords
(list
'("^[ \t]*\\([\\#\\-]include\\)[ \t]+\\(.*\\)"
(1 font-lock-keyword-face)
(2 font-lock-string-face)) ;; include
'("^[ \t]*#.*$" . font-lock-comment-face) ;; comments
'("^[ \t]*\\([a-z0-9_\\.\\*]+\\)[ \t]*\\(!=\\)[ \t]*\\(.*\\)"
(1 font-lock-variable-name-face)
(2 font-lock-function-name-face)) ;; shell commands
'("^[ \t]*\\([a-z0-9_\\.\\*]+\\)[ \t]*\\(:=\\)[ \t]*\\([a-z0-9\\.]+\\)[ \t]*$"
(1 font-lock-variable-name-face)
(2 font-lock-function-name-face)
(3 font-lock-variable-name-face)) ;; node copying
'("^[ \t]*\\([a-z0-9_\\.\\*]+\\)[ \t]*=[ \t]*\\(true\\|false\\|yes\\|no\\|on\\|off\\)[ \t]*$"
(1 font-lock-variable-name-face)
(2 font-lock-keyword-face)) ;; booleans
'("^[ \t]*\\([a-z0-9_\\.\\*]+\\)[ \t]*=[ \t]*\\([0-9]+\\)[ \t]*$"
(1 font-lock-variable-name-face)
(2 font-lock-constant-face)) ;; numbers
'("^[ \t]*\\([a-z0-9_\\.\\*]+\\)[ \t]*=[ \t]*\\(.*\\)"
(1 font-lock-variable-name-face)) ;; strings
'("^[ \t]*\\([a-z0-9_\\.\\*]+\\)[ \t]*[{=][ \t]*$"
(1 font-lock-variable-name-face)) ;; nodes
'("^[ \t]*\\([a-z0-9_\\.\\*]+\\)[ \t]*\\(:\\)[ \t]*\\([a-z0-9\\.]+\\)[ \t]*$"
(1 font-lock-variable-name-face)
(2 font-lock-function-name-face)
(3 font-lock-variable-name-face)) ;; node aliases
'("^[ \t]*\\(@\\)\\([a-z0-9_\\.]+\\)[ \t]*$"
(1 font-lock-function-name-face)
(2 font-lock-variable-name-face)) ;; node inheritance
)
"Hdf Keywords")
;; indentation
(defun hdf-indent-line ()
"Indent current line as HDF code."
(interactive)
(beginning-of-line)
(if (bobp)
(indent-line-to 0)
(progn
(if (looking-at "^[ \t]*}")
(save-excursion
(forward-line -1)
(while (and (not (bobp)) (looking-at "^[ \t]*$"))
(forward-line -1))
(if (looking-at "^[ \t]*\\([a-z0-9_\\.\\*]+\\)[ \t]*{")
(setq cur-indent (current-indentation))
(progn
(setq cur-indent (- (current-indentation) hdf-indent-level))
(if (< cur-indent 0)
(indent-line-to 0)))))
(save-excursion
(forward-line -1)
(while (and (not (bobp)) (looking-at "^[ \t]*$"))
(forward-line -1))
(if (looking-at "^[ \t]*\\([a-z0-9_\\.\\*]+\\)[ \t]*{")
(setq cur-indent (+ (current-indentation) hdf-indent-level))
(setq cur-indent (current-indentation)))))
(if cur-indent
(indent-line-to cur-indent)
(indent-line-to 0)))))
(defun hdf-mode ()
"Mode for editing HDF files"
(interactive)
(kill-all-local-variables)
(set (make-local-variable 'font-lock-defaults)
'(hdf-font-lock-keywords nil, 1))
(setq major-mode 'hdf-mode)
(setq mode-name "HDF")
(run-hooks 'hdf-mode-hook)
(set (make-local-variable 'indent-line-function) 'hdf-indent-line)
)
(provide 'hdf-mode)
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
-122
Ver Arquivo
@@ -1,122 +0,0 @@
<?php
define('STARTER_MARKER', "namespace hphp_impl_starter {}\n");
define('SPLITTER_MARKER', "namespace hphp_impl_splitter {}\n");
$inputDir = preg_replace('#/$#', '', $argv[1]); // stripping trailing slash
$files = array();
exec("cd $inputDir && find cpp -name *.cpp", $files);
$sizes = array();
$clusterSize = calculate_cluster_size($sizes, $inputDir, $files);
$merges = $splits = $noops = array();
compute_merge_splits($merges, $splits, $sizes, $clusterSize);
// hzhao: I didn't find merge helped that much, so output splits only
print "splits {\n";
foreach ($splits as $file => $count) {
print " * {\n";
print " name = $file\n";
print " count = $count\n";
print " }\n";
}
print "}\n";
///////////////////////////////////////////////////////////////////////////////
function calculate_cluster_size(&$sizes, $inputDir, $files) {
$total = 0;
$sizes = array();
foreach ($files as $file) {
$pp = shell_exec("make -C $inputDir $file.pp");
$pos = strpos($pp, STARTER_MARKER);
if ($pos === false) {
exit("Unable to find ImplStarter mark in $file\n");
}
$size = strlen($pp) - $pos;
$sizes[$file] = $size;
$total += $size;
}
exec("make -C $inputDir clobber");
return (int)($total / count($sizes));
}
function compute_merge_splits(&$merges, &$splits, $sizes, $clusterSize) {
$merge = array(); $merge_size = 0;
foreach ($sizes as $file => $size) {
if ($size >= $clusterSize) {
$splits[$file] = ceil($size / $clusterSize);
} else if ($size < $clusterSize) {
if ($merge_size + $size > $clusterSize) {
$merges[] = $merge;
$merge = array();
$merge_size = 0;
}
$merge[$file] = $size;
$merge_size += $size;
} else {
$noops[$file] = $size;
}
}
if ($merge) {
$merges[] = $merge;
}
}
function merge_files($inputDir, $merges) {
$i = 0;
foreach ($merges as $merge) {
if (count($merge) > 1) {
++$i;
$target = sprintf("cpp/merge.%03d.cpp", $i);
$f = fopen("$inputDir/$target", "w+");
$new_contents = '';
foreach ($merge as $file => $size) {
$content = file_get_contents("$inputDir/$file");
$pos = strpos($content, STARTER_MARKER);
fwrite($f, $content, $pos);
$new_contents .= substr($content, $pos + strlen(STARTER_MARKER));
}
fwrite($f, $new_contents);
fclose($f);
system("cd $inputDir && rm -f " . implode(' ', array_keys($merge)));
}
}
}
function split_files($inputDir, $splits) {
foreach ($splits as $file => $count) {
$content = file_get_contents("$inputDir/$file");
$header_size = $pos = strpos($content, STARTER_MARKER);
$pos0 = $pos + strlen(STARTER_MARKER);
$chunk_size = (int)((strlen($content) - $pos) / $count);
for ($i = 0; $i < $count; $i++) {
$pos = $pos0 + $chunk_size;
$pos = @strpos($content, SPLITTER_MARKER, $pos);
if ($pos == false) {
$pos = strlen($content);
}
$f = fopen("$inputDir/$file.$i.cpp", "w+");
fwrite($f, $content, $header_size);
if ($i > 0) fwrite($f, "namespace HPHP {\n");
fwrite($f, substr($content, $pos0, $pos - $pos0));
$pos0 = $pos + strlen(SPLITTER_MARKER);
if ($pos0 > strlen($content)) {
fclose($f);
break;
}
fwrite($f, "}\n");
fclose($f);
}
system("rm -f $inputDir/$file");
}
}
-49
Ver Arquivo
@@ -1,49 +0,0 @@
<?php
$server = $argv[1];
$top = $argv[2];
$translate = $argv[3];
if (!$top) $top = 20;
$ret = shell_exec("GET 'http://$server/stats.kvp?agg=*&keys=:mutex.*:'");
$stats = json_decode($ret);
if (!$stats) {
exit("No mutex profile data was found on server\n");
}
foreach ($stats as $name => $count) {
if (preg_match('/mutex.([0-9a-f:]+).(hit|time)/', $name, $m)) {
$stack = $m[1];
$type = $m[2];
if ($type == 'hit') {
$hits[$stack] = $count;
} else {
$times[$stack] = $count;
}
}
}
arsort($hits); $hits = array_slice($hits, 0, $top);
arsort($times); $times = array_slice($times, 0, $top);
$thits = array();
print str_repeat('=', 70)."\n";
foreach ($hits as $stack => $count) {
print $count ." x sampling hits:\n";
print $translate ? translate_stack($stack) : $stack."\n";
print str_repeat('-', 70)."\n";
}
$ttimes = array();
print str_repeat('=', 70)."\n";
foreach ($times as $stack => $count) {
print (int)($count/1000000) ." seconds:\n";
print $translate ? translate_stack($stack) : $stack."\n";
print str_repeat('-', 70)."\n";
}
function translate_stack($stack) {
global $server;
return shell_exec("GET http://$server/translate?stack=$stack");
}
-124
Ver Arquivo
@@ -1,124 +0,0 @@
<?php
define('PHP_ONLY', 1);
define('NON_PHP_ONLY', 2);
define('ALL_FILES', 3);
define('USE_DU', 4);
$arg = 0;
$dir = '.'; if ($argc > ++$arg) $dir = $argv[$arg];
$file_type = PHP_ONLY; if ($argc > ++$arg) $file_type = $argv[$arg];
$min_percentage = 2; if ($argc > ++$arg) $min_percentage = $argv[$arg];
$ascii = false; if ($argc > ++$arg) $ascii = $argv[$arg];
if ($ascii) {
define('CHAR_V', '|');
define('CHAR_H', '.');
define('CHAR_T', 'L');
define('CHAR_L', 'L');
define('LINE_INDENT', 4);
define('WORD_INDENT', 2);
} else {
define('CHAR_V', "\xe2\x94\x82");
define('CHAR_H', "\xe2\x94\x80");
define('CHAR_T', "\xe2\x94\x9c");
define('CHAR_L', "\xe2\x94\x94");
define('LINE_INDENT', 2);
define('WORD_INDENT', 2);
}
// main
du_dir(realpath($dir));
print "\nTotal Size: ".(int)($grand_total/1024 + 0.5)."M\n";
function du_dir($dir, $indent = array()) {
global $min_percentage, $grand_total;
if (!is_dir($dir)) return;
$total = 0;
$sizes = get_file_sizes($dir, $total);
if (empty($indent)) $grand_total = $total;
arsort($sizes);
$min_size = $grand_total * $min_percentage / 100;
$selected = array();
foreach ($sizes as $file => $size) {
if ($size > $min_size) {
$selected[$file] = $size;
}
}
$index = 0;
foreach ($selected as $file => $size) {
$last = (++$index == count($selected));
$percentage = (int)($size / $grand_total * 100 + 0.5);
$mb = (int)($size / 1024 + 0.5);
if (!empty($indent)) {
$first = true;
foreach ($indent as $vertical) {
if ($first) {
print str_repeat(' ', WORD_INDENT);
$first = false;
} else {
print ($vertical ? CHAR_V : ' ') .
str_repeat(' ', LINE_INDENT + WORD_INDENT);
}
}
print ($last ? CHAR_L : CHAR_T) . str_repeat(CHAR_H, LINE_INDENT);
}
print "$file: ${mb}M ($percentage%)\n";
$indent[] = !$last;
du_dir("$dir/$file", $indent);
array_pop($indent);
}
}
function get_file_sizes($dir, &$total) {
global $file_type;
if ($file_type == USE_DU) {
$lines = array();
exec('du -L --exclude="*/.svn*" --exclude="*/.git*" --max-depth=1 '.$dir,
$lines);
$sizes = array();
$total = 0;
foreach ($lines as $line) {
if (preg_match('/^([0-9]+)[ \t]+'.preg_quote($dir, '/').'\/(.*)$/',
$line, $m)) {
$size = $m[1]; $file = $m[2];
$sizes[$file] = $size;
$total += $size;
}
}
return $sizes;
}
$cmd = 'find -L '.$dir.' -type f'.
' -not -regex ".*/\.svn/.*" -not -regex ".*/\.git/.*"';
if ($file_type == PHP_ONLY) {
$cmd .= ' -regex ".*\.php" -o -regex ".*\.phpt"';
} else if ($file_type == NON_PHP_ONLY) {
$cmd .= ' -not -regex ".*\.php" -not -regex ".*\.phpt"';
}
$lines = array();
exec($cmd, $lines);
$sizes = array();
$total = 0;
foreach ($lines as $line) {
preg_match('#'.preg_quote($dir, '#').'/([^/]+)#', $line, $m);
$file = $m[1];
$size = filesize($line) / 1024;
if (isset($sizes[$file])) {
$sizes[$file] += $size;
} else {
$sizes[$file] = $size;
}
$total += $size;
}
return $sizes;
}
-72
Ver Arquivo
@@ -1,72 +0,0 @@
PROJECT_ROOT = $(HPHP_HOME)
ifndef PROJECT_NAME
PROJECT_NAME = program
endif
override OUTPUT_ROOT=
override OUTDIR_BY_TYPE=
# We want files to be sorted by size, so that larger files are dispatched by
# distcc earlier
RECURSIVE_SOURCES := $(shell find . -name "*.cpp")
CXX_NOOPT_SOURCES := $(filter %.no.cpp, $(RECURSIVE_SOURCES))
SIZE_SORTED_SOURCES := $(shell ls -S $(filter-out %.no.cpp, $(RECURSIVE_SOURCES)))
CXX_SOURCES := $(SIZE_SORTED_SOURCES)
ifdef RANDOMIZE_CXX_SOURCES
CXX_SOURCES := $(shell perl -MList::Util=shuffle \
-e'print join " ",shuffle @ARGV' $(CXX_SOURCES))
endif
-include sep_extensions.mk
ifdef HPHPI_THUNK
CPPFLAGS += -DTHUNK_FILENAME='"/.hphpi-thunk"'
endif
CPPFLAGS += -I. $(SEP_EXTENSION_INCLUDE_PATHS)
LIBS = $(SEP_EXTENSION_LIBS) $(HPHP_LIB)/libhphp_runtime.a $(ALL_LIBS)
include $(HPHP_HOME)/src/rules.mk
ifdef HPHP_BUILD_LIBRARY
EXTERNAL += $(HPHP_LIB)/libhphp_runtime.so
HPHP_OBJ_DIR = $(HPHP_HOME)
ifdef HPHP_BUILD_FFI
EXTERNAL += $(HPHP_LIB)/libhphp_java.so
endif
RUNTIME_DIRS := $(wildcard \
$(HPHP_LIB)/src/runtime/base \
$(HPHP_LIB)/src/runtime/ext \
$(HPHP_LIB)/src/runtime/eval \
$(HPHP_LIB)/src/system/gen \
$(HPHP_LIB)/src/system/lib \
$(HPHP_LIB)/src/util)
ifeq ($(strip $(RUNTIME_DIRS)),)
RUNTIME_DIRS = \
$(HPHP_OBJ_DIR)/src/runtime/base \
$(HPHP_OBJ_DIR)/src/runtime/ext \
$(HPHP_OBJ_DIR)/src/runtime/eval \
$(HPHP_OBJ_DIR)/src/system/gen \
$(HPHP_OBJ_DIR)/src/system/lib \
$(HPHP_OBJ_DIR)/src/util
endif
ADDITIONAL_OBJS += $(shell find $(RUNTIME_DIRS) -name "*.o" -\! -name "*.pic.o")
TARGETS = $(STATIC_LIB) $(SHARED_LIB)
else # HPHP_BUILD_LIBRARY
TARGETS = $(APP_TARGET)
endif
all: $(TARGETS)
%.pp: %
$(CXX) -E $(if $(OUT_TOP),-I$(OUT_TOP)src) $(CPPFLAGS) $(OPT) $(CXXFLAGS) $<
-14
Ver Arquivo
@@ -1,14 +0,0 @@
#!/bin/sh
#$1: output directory
#$2: program name
#$3: extra flags, for exmaple, RELEASE=1
#echo make -j $3 PROJECT_NAME=$2 TIME_LINK=1 -C $1
cp $HPHP_HOME/bin/CMakeLists.base.txt $1/CMakeLists.txt
cd $1
cmake -D PROGRAM_NAME:string=$2 . || exit $?
if [ -n "$HPHP_VERBOSE" ]; then
make $MAKEOPTS > /dev/tty || exit $?
else
make $MAKEOPTS || exit $?
fi
-53
Ver Arquivo
@@ -1,53 +0,0 @@
CREATE TABLE `hphp_run` (
`id` int(11) NOT NULL auto_increment,
`branch` varchar(255) NOT NULL default '',
`revision` int(11) NOT NULL default '0',
`file` int(11) NOT NULL default '0',
`line` int(11) NOT NULL default '0',
`byte` int(11) NOT NULL default '0',
`program` int(11) NOT NULL default '0',
`function` int(11) NOT NULL default '0',
`class` int(11) NOT NULL default '0',
`types` text NOT NULL,
`time` int(11) NOT NULL default '0',
`created` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`committed` tinyint(4) NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `hphp_dep` (
`id` int(11) NOT NULL auto_increment,
`run` int(11) NOT NULL default '0',
`program` varchar(255) NOT NULL default '',
`kind` varchar(255) NOT NULL default '',
`parent` varchar(255) NOT NULL default '',
`parent_file` varchar(255) NOT NULL default '',
`parent_line` int(11) NOT NULL default '0',
`child` varchar(255) NOT NULL default '',
`child_file` varchar(255) NOT NULL default '',
`child_line` int(11) NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `program` (`run`,`program`),
KEY `parent` (`run`,`kind`,`parent`,`child`),
KEY `child` (`run`,`kind`,`child`,`parent`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `hphp_err` (
`id` int(11) NOT NULL auto_increment,
`run` int(11) NOT NULL default '0',
`program` varchar(255) NOT NULL default '',
`kind` varchar(255) NOT NULL default '',
`construct` bigint(20) NOT NULL default '0',
`file1` varchar(255) NOT NULL default '',
`line1` int(11) NOT NULL default '0',
`file2` varchar(255) NOT NULL default '',
`line2` int(11) NOT NULL default '0',
`expected_type` int(11) NOT NULL default '0',
`actual_type` int(11) NOT NULL default '0',
`data` varchar(255) NOT NULL default '',
`suppressed` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `program` (`run`,`program`),
KEY `kind` (`run`,`kind`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+5579
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
-28
Ver Arquivo
@@ -1,28 +0,0 @@
<?php
$lines = file_get_contents($argv[1]);
$lines = preg_split('/\n/', $lines);
$times = array();
foreach ($lines as $line) {
if (preg_match('/^([0-9\.]+) .* ([^ ]+\.cpp|c)$/', $line, $matches)) {
$time = $matches[1];
$file = $matches[2];
$times[$file] = $time;
} else if (preg_match('/^([0-9\.]+) (g\+\+ -o|ar -crs)/', $line, $matches)) {
$linktime = $matches[1];
} else {
print "Unknown output: $line";
}
}
asort($times);
foreach ($times as $file => $time) {
print format_time($time)." compiling $file\n";
}
print format_time($linktime)." linking\n";
function format_time($time) {
return (int)($time / 60) . "'" .
(($time % 60) > 9 ? '':'0'). ($time % 60) . '"';
}
-160
Ver Arquivo
@@ -1,160 +0,0 @@
{
Socket-1
Memcheck:Param
write(buf)
fun:__write_nocancel
fun:_IO_file_write@@GLIBC_2.2.5
fun:_IO_do_write@@GLIBC_2.2.5
fun:_IO_file_close_it@@GLIBC_2.2.5
fun:fclose@@GLIBC_2.2.5
fun:RAND_write_file
fun:_ZN14SSLInitializerC1Ev
fun:_Z41__static_initialization_and_destruction_0ii
}
{
Socket-2
Memcheck:Param
socketcall.sendto(msg)
fun:__sendto_nocancel
fun:__check_pf
fun:getaddrinfo
}
{
pthread-1
Memcheck:Leak
fun:calloc
fun:_dl_allocate_tls
fun:pthread_create@@GLIBC_2.2.5
}
{
backtrace-1
Memcheck:Param
msync(start)
obj:/lib64/libpthread-2.3.5.so
fun:access_mem
}
{
FBML-2
Memcheck:Leak
fun:*
fun:*
fun:_ZN10nsHTMLTags11AddRefTableEv
}
{
FBML-3
Memcheck:Leak
fun:*
fun:*
fun:*
fun:_ZN10nsHTMLTags11AddRefTableEv
}
{
FBML-4
Memcheck:Leak
fun:*
fun:*
fun:*
fun:*
fun:_ZN10nsHTMLTags11AddRefTableEv
}
{
FBML-5
Memcheck:Leak
fun:*
fun:*
fun:*
fun:*
fun:*
fun:_ZN10nsHTMLTags11AddRefTableEv
}
{
FBML-6
Memcheck:Leak
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:_ZN10nsHTMLTags11AddRefTableEv
}
{
FBML-7
Memcheck:Leak
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:*
fun:_ZN10nsHTMLTags11AddRefTableEv
}
{
FBML-8
Memcheck:Leak
fun:malloc
fun:PL_NewHashTable
fun:_ZN11nsHTMLAttrs11AddRefTableEv
}
{
hdf-1
Memcheck:Leak
fun:calloc
fun:uListInit
fun:nerr_init
fun:hdf_init
}
{
hdf-2
Memcheck:Leak
fun:realloc
fun:check_resize
fun:uListAppend
fun:nerr_register
fun:nerr_init
fun:hdf_init
}
{
SharedMemroyInit-1
Memcheck:Leak
fun:_Znwm
fun:_ZN4HPHP19SharedMemoryManager4InitEib
}
{
inet_ntoa-1
Memcheck:Leak
fun:malloc
fun:inet_ntoa
}
{
pthread-2
Memcheck:Leak
fun:*
fun:*
fun:pthread_once
}
{
boost-1
Memcheck:Leak
fun:*
fun:*
fun:*
obj:*
fun:*
obj:/usr/local/lib/libboost_program_options-gcc40-mt-1_35.so.1.35.0
}
{
mcrypt-1
Memcheck:Overlap
fun:memcpy
fun:mcrypt_dlsym
}
{
zlib-1
Memcheck:Cond
fun:deflate_slow
fun:deflate
}
-24
Ver Arquivo
@@ -1,24 +0,0 @@
help:
@echo "'make daemon' to start up doc server daemon"
@echo "'make server' to start up doc server"
@echo "'make clobber' to clean up directory"
daemon:
sudo ../src/hphpi/hphpi -m daemon -v "Server.DefaultDocument=index.php" -v "Server.SourceRoot=`pwd`"
server:
sudo ../src/hphpi/hphpi -m server -v "Server.DefaultDocument=index.php"
DEBUGGER_CMDS = a b c d e f g h i j k l m n o p q r step thread u v w x y z "\&" "!"
# update debugger docs
debugger:
@../src/hphpi/hphpi -m debug --debug-cmd "help start" > debugger.start
@../src/hphpi/hphpi -m debug --debug-cmd "help" > debugger.cmds
@../src/hphpi/hphpi -m debug \
$(patsubst %, --debug-cmd "'h %'", $(DEBUGGER_CMDS)) > debugger.refs
clean: clobber
clobber:
@rm -f *~
-93
Ver Arquivo
@@ -1,93 +0,0 @@
<h2>Various Commands for Developing HipHop</h2>
= Learning "make"
"make" is used extensively for different commands throughout the project. The
most common way is,
cd {directory}
make {target}
This can be simplied to,
make -C {directory} {target}
Throughout this doc, we will use -C form to show which directory under hphp/
the target is at, but you may always change to the directory to run "make
{target}" directly.
= Building the project
Just do a simple,
make -C src
For verbose outputs,
SHOW_COMPILE=1 make -C src # show all compilation commands
SHOW_LINK=1 make -C src # show all linking commands
V= make -C src # show all commands
= Separate build directories
The default build puts all the files into the source tree. This makes it hard
to keep both DEBUG and RELEASE builds up to date, and also leaves a lot of
unversioned files in amongst your versioned files.
To solve this, there are a couple of environment variables you can use.
Setting OUTPUT_ROOT explicitly tells make where to put the generated files. You
can put them anywhere.
Setting OUTDIR_BY_TYPE will append -g or -O to the OUTPUT_ROOT depending on
whether its a DEBUG, or RELEASE build. If you set OUTDIR_BY_TYPE without
setting OUTPUT_ROOT, OUTPUT_ROOT defaults to $(PROJECT_ROOT)/bin, and so the
generated files will all go in $(PROJECT_ROOT)/bin-g or $(PROJECT_ROOT)/bin-O.
If you set OUTDIR_BY_TYPE, the targets debug, release, and both are available
in the top-level makefile.
make debug # debug build into $(PROJECT_ROOT)/bin-g
make release # release build into $(PROJECT_ROOT)/bin-O
make both # build both
When OUTPUT_ROOT, or OUTDIR_BY_TYPE is set, all executables, static libs and
shared libs are built into the top level output directory; so you should
point HPHP_LIB and PATH at that directory.
= "make clean" or "make clobber"
Whenever you want to remove all intermediate files, you can run "make clean"
or "make clobber" from almost every directory. These two commands are the same,
although historically, "make clean" leaves built targets or binaries while
deleting all intermediate files, whereas "make clobber" removes everything. In
our case, they will both remove everything.
= Monitoring build status
This command can bring up "top" like screen to show you which .cpp files are
being built by distcc:
make -C src top
= Running a unit test
These commands are available to run some unit tests:
cd src/
test/test
test/test TestExtFile
test/test TestExtFile test_fseek
test/test TestExtFile::test_fseek
make fast_tests # 2 minutes to finish, required for every check-in
make slow_tests # hours to finish, required for in-depth changes
= Running a benchmark
We have "benchmark" directory set up, and you can simply throw in a PHP file
and run it under benchmark mode,
make -C benchmark {test.run} # if the file name is "test.php"
-38
Ver Arquivo
@@ -1,38 +0,0 @@
<h2>Useful gdb Commands</h2>
info threads
thread apply [threadno] [all] args
set follow-fork-mode parent
set detach-on-fork on
set print pretty
handle SIGPIPE nostop noprint pass
dump binary memory [filename] [start_addr] [end_addr]
symbol-file [un-stripped binary OR symbol file from strip]
= b main.no.cpp:55
If you get "Couldn't get registers" error when starting a program with gdb,
instead of attaching to a running process, this is because gdb has a bug,
not able to switch to the main thread/process when it forks:
[Thread debugging using libthread_db enabled]
[New Thread 46912496246512 (LWP 30324)]
[New Thread 1084229952 (LWP 30327)]
[Thread 1084229952 (LWP 30327) exited]
Couldn't get registers: No such process.
Set a break point at line 55 of main.no.cpp, then "r", you will get this,
[Thread debugging using libthread_db enabled]
[New Thread 46912496246512 (LWP 30632)]
[New Thread 1084229952 (LWP 30636)]
[Thread 1084229952 (LWP 30636) exited]
<b>[Switching to Thread 46912496246512 (LWP 30632)]</b>
Breakpoint 1, main (argc=3, argv=0x7fff41b5b138) at sys/main.no.cpp:55
55 return HPHP::execute_program(argc, argv);
(gdb) c
Magically, gdb is able to switch to main thread, attaching to it, then it will
be able to debug it, even if it forks afterwards.
-167
Ver Arquivo
@@ -1,167 +0,0 @@
<h2>How to add new extension functions/classes</h2>
There are 2 types of extensions: separable extensions and non-separable
extensions. Most of existing extensions were written in a way that's not quite
easy to remove/detach/separate from the runtime. Separable extension is a new
framework that's just added to allow people to work in its own directory
without any modifications to main project files, thus easy to add/remove an
extension from the core runtime.
<h2>How to add new separable extension functions/classes</h2>
1. Find the right extension name
Find a unique extension name, for example, "mhash". Use the name to create a
directory. For example, runtime/ext/sep/mhash. This would be home directory
of the extension, and all new files will be created under this directory.
2. Create a new IDL
For example, mhash.idl.php. Add function/class prototypes to the IDL file.
Follow existing ones for formats. Most of them are straightforward. Possible
types are listed in idl/base.php.
3. Auto-generate files from IDL
Create a Makefile like runtime/ext/sep/mhash/Makefile, by specifying
PROJECT_ROOT and including runtime/ext/sep/rules.mk.
If it is a new IDL file, run
make create
Otherwise, run
make update
4. Manual editing
Modify these files to implement the extension.
ext_[name].h
ext_[name].cpp
5. Unit tests
Modify these files to add unit tests.
test_ext_[name].h
test_ext_[name].cpp
6. Create the extension and unit test program.
make
7. Provide the extension to the compiler.
The compiler needs to know about these new functions/classes, while compiling
PHP code. To do this, prepare a configuration HDF file like this,
SepExtensions {
mhash {
# optional: default to lib[name].so
soname = libmhash.so
# optional: default to $(PROJECT_ROOT)/src/runtime/ext/sep/[name]
include = /var/users/hzhao/hphp2/src/runtime/ext/sep/mhash
# optional: default to use LD_LIBRARY_PATH or ldconfig to locate the .so
libpath = /var/users/hzhao/hphp2/src/runtime/ext/sep/mhash
# optional: default to "false", using static libraries for linking
shared = true
}
}
Then give this file to the compiler like this,
hphp/hphp test.php -c config.hdf
The compiler will extract extension symbols from the .so file.
8. Run compiled program with the new extension.
Newly compiled program will depend on the new extension's .a or .so (depending
on config's "shared" setting. If static linking is used, the compiler will
locate the .a file automatically and link with it. No more runtime setup is
needed. Otherwise, the .so file becomes a runtime dependency and it has to
be located by the compiled program at runtime, perhaps with ldconfig or any
other ways.
<h2>How to add new non-separable extension functions/classes</h2>
All commands and directories are from src/ in this guide.
1. Find the right extension name
Find the best "extension" under idl/*.idl.php to add your function(s) to.
runtime/ext/README has a good list of categorized extension names. If nothing
fits, create a new IDL file with a good name.
2. Update IDL
Add function/class prototypes to the IDL file. Follow existing ones for
formats. Most of them are straightforward. Possible types are listed in
idl/base.php.
3. Auto-generate files from IDL
If it is a new IDL file, run
EXT=[new extension name] make -C idl install
For example,
EXT=my_extension make -C idl install
This will add several files to different places.
Otherwise, run
EXT=[existing extension name] make -C idl update
For example,
EXT=string make -C idl update
This will modify several files with the new function/classes.
4. Manual editing
Some files are not automatically updated, including
runtime/ext/ext_[name].h
runtime/ext/ext_[name].cpp
They are created under idl/ to serve as templates that one can copy portions
of them manually. These are the two files that you will add implementation to.
5. Unit tests
The "EXT=name make update" does the following for test files:
creates test/test_ext_[name].h -- entry points for this unit test, don't modify
updates test/test_ext.inc -- to invoke the test, don't modify
creates idl/test_ext_[name].cpp -- A template to be modified.
You will have to add new unit tests to
test/test_ext_[name].cpp
into both the list of RUN_TEST() at top portion of the file and a real
unit test function like this,
void TestExt[Name]::test_ext_[function] () { ... }
6. How to modify existing extension functions/classes
Modify the IDL file. Then run
EXT=existing make -C idl update
Follow all steps after step 3 at above.
7. After compiling once, do this to update compiler with the latest functions:
make -C system
-89
Ver Arquivo
@@ -1,89 +0,0 @@
<h2>How to Use HipHop Compiled Libraries in C++</h2>
There are several functions that have to be called correctly to make sure
HipHop compiled binaries work in a C++ environment:
1. Without Memory Manager
(1) hphp_process_init() and hphp_process_exit()
The 1st function initializes all static variables a PHP library contains. This
function is only needed to be called just ONCE before calling any other HipHop
functions. Please call this function from process level (the "main thread")
before starting any threads.
Call hphp_process_exit() as the last HipHop function call when program exits.
(2) hphp_session_init() and hphp_session_exit()
If a PHP library does not have cycles in object references, one can call
hphp_session_init() at the beginning of a "session" and then call
hphp_session_exit() at the end of the session to free up all memory.
Both functions have to be called on per-thread basis.
2. With Memory Manager
If memory leak is detected, it may mean the PHP library has objects or arrays
forming cycles when referring to each other. This is problematic to reference
counting based memory deallocation, but it can be solved by using
MemoryManager that can sweep dangling memory periodically.
To enable MemorManager, this has to be set at program startup time, and it
cannot be turned off afterwards:
HPHP::RuntimeOption::EnableMemoryManager = true;
MemoryManager::TheMemoryManager()->enable();
(1) hphp_process_init()
(same as above)
(2) Taking a checkpoint
The memory manager is powerful enough to take a snapshot of the memory at any
time by doing
hphp_session_init(); // required, same as above
// optionally update more global states
MemoryManager::TheMemoryManager()->checkpoint();
We only recommend to take checkpoint just once on per-thread basis, because
we have not tested what will happen when multiple checkpoint() is called.
(3) Rollback periodically
Call this once per end of "session":
hphp_session_exit();
Please make sure there is no stack variables that are still alive when calling
rollback(). Otherwise, rollback() will release the memory to the pool, causing
that stack variable's destructor to work on collected memory.
3. Thread Local Memory Management
Almost all variables are thread-local. If you want to share those variables
between threads, you will run into trouble. Instead, copy them into your own
object classes to do so. Alternatively, use <b>apc_fetch()</b> and
<b>apc_store()</b>.
4. Execution Context
Execution context controls where PHP's stdout goes to, whether to execute
shutdown or postsend functions, etc.. It is optional to use it, but it's highly
recommended to avoid calling functions that are not "pure".
(1) At beginning of a session, set up execution context like this,
ExecutionContext *context = hphp_context_init();
(2) At end of a session, tear down execution context like this,
hphp_context_exit(context, true);
For the 2nd parameter, if true, post-send processing (PSP) will be performed,
if false, all PSP functions will be ignored.
-236
Ver Arquivo
@@ -1,236 +0,0 @@
<h2>Inconsistencies between PHP and HipHop</h2>
These are the known inconsistencies between current HipHop and PHP.
1. Operators
(1) Arithmetic
In PHP, the addition, subtraction, or multiplication of two integers will
produce a floating-point value if the result overflows the integer type. In
Hiphop, the addition, subtraction, or multiplication of two integers will
always produce an integer value; if the result overflows the integer type, the
upper bits of the result will be truncated.
(2) Foreach by value
In PHP, foreach by value will modify the array's internal cursor under certain
circumstances. In HipHop, foreach by value will never modify the array's
internal cursor.
(3) Foreach by reference
In PHP, if during a foreach by reference loop the next element of the array is
unset, the foreach loop may fail to visit all of the elements in the array.
Under HipHop, foreach by references loops that do not break early make the
following guarantees:
a) If an original element is not deleted, the loop will visit it exactly
once.
b) If an element is appended and is not deleted, the loop will visit it
exactly once.
c) An original element or an appended element will not be visited if it is
deleted during a previous iteration.
d) The loop will visit all elements in order, original elements first
followed by appended elements.
(4) instanceof
In PHP, [constant] instanceof [class name] will cause a fatal.
In HipHop, there is no special case for constants and the expression's value is
false.
(5) Internal array cursors
In PHP, if an array's internal cursor points past the last element and then a
copy of the array is made, the copy will have its internal cursor reset to
point at the first element. In HipHop, when a copy of an array is made, the
copy's internal cursor will always point to the same element that the original
array's internal cursor pointed to.
(6) Next free integer key for arrays
Arrays contain a hidden field called the "NextFreeElement" field that tracks
what integer key should be used when a new element is appended. In PHP, when an
array is copied the NextFreeElement field of the new array is recomputed based
on the keys it currently contains. In HipHop, when an array is copied the new
array's NextFreeElement field is set to the same value as the original array's
NextFreeElement field.
2. Classes and objects
(1) Exceptions thrown from destructors
In HipHop, exceptions and fatals thrown from destructors will be swallowed
while logging an error. Effectively, there is a try/catch enclosing the body
of the __destruct method. These exceptions are catchable in PHP outside of the
__destruct method.
(2) Global variable's destructor
In HipHop, global variables are not destructed at end of web requests or
program execution if memory manager is enabled (default). They are garbage
collected by memory sweeping as a whole for performance reason and for
preventing memory leaks if circular reference exists between two or more
global variables. So destructors of global objects are not called.
In PHP, global variables are destructed before a web page responds. Therefore,
output from their destrcutors will be part of the HTTP response.
(3) Exceptions thrown from __toString()
PHP doesn't allow them. HipHop does. Also, PHP doesn't allow __toString() to
return anything other than a string. HipHop will just convert return value to
string.
(4) unset
In PHP, a data member that is unset will not appear at all in vardump or
serialize. Also, unsetting a data member and then resetting it will alter its
order in foreach iterations.
In HipHop, it will still appear in vardump or serialize as null. It will
not appear in foreach iteration, so it's consistent with PHP. When unsetting
a data member and then resetting it, it's order is not altered in foreach
iteration. When unsetting then resetting to NULL, HipHop will be confused to
think the property is still not present (bug).
(5) $this handling of static method
In PHP, $this may be passed into an unrelated class's static method. Here's an
example,
<?php
class b {
public function bar() {
var_dump($this); // <-- $this is actually class "c" object
$this->baz();
}
}
class c { // <-- note that "c" has nothing to do with "b"
public $x = 2;
public function foo() {
b::bar();
}
public function baz() {
echo "Hello!\n";
}
}
$obj = new c;
$obj->foo();
In HipHop, $this will be NULL when doing this.
(6) __call/__callStatic() handling
These 2 examples give inconsistent results in PHP 5.3:
<?php
class B {
}
class G extends B {
function __call($name, $arguments) { var_dump('G');}
function f4missing($a) {
B::f4missing(5); // __call checking happened at B
}
}
$g = new G();
$g->f4missing(3);
<?php
class B {
function __call($name, $arguments) { var_dump('B');}
}
class G extends B {
function __call($name, $arguments) { var_dump('G');}
function f4missing($a) {
B::f4missing(5); // G::__call() was called actually!
}
}
$g = new G();
$g->f4missing(3);
In HipHop, both checking and invocation of __call() happen on class G.
3. Eval Issues
(1) eval
Is only supported in limited circumstances.
Example unsupported case: phpt...bug21960
(2) create_function
is only supported with literal arguments
Example unsupported case: phpt...bug22690
(3) preg_replace /e
is only supported in limited cases.
Example unsupported case: phpt...bug24403
4. $GLOBALS is not an ordinary variable:
In php you can assign to $GLOBALS
$GLOBALS = 0;
$x = $GLOBALS - 5;
$g = $GLOBALS;
$g['x'] = 3;
In HipHop, this is not allowed or not working.
5. Constants
(1) Dynamically declared constants
These are not supported, e.g.
define($name, $value);
(2) Case-insensitive constants
These are not supported, e.g.
define('FOO', 123, true);
6. Misc
(1) get_defined_vars() and get_declared_classes()
Can return variables/classes in different order from PHP's.
(2) uninitialized variables
If an uninitialized variable is being used before it's assigned with a value,
and this variable is inferred as integers, it will be 0, instead of null.
(3) call_user_func() and call_user_func_array()
PHP doesn't respect pass-by-reference parameters and return value. HipHop does.
PHP doesn't allow func_get_args() to be used as arguments of these two
functions. HipHop does.
(4) XMLWriter
In PHP, XMLWriter class and its functions returned different types of objects,
<?php
function foo(XMLWriter $w) {}
$obj = new XMLWriter();
foo($obj); // <-- this one is actually okay
$obj2 = xmlwriter_open_memory(); // <-- just not this one
var_dump($obj, $obj2);
foo($obj2);
In HipHop, they are the same.
(5) GOTO statement
In PHP, jumping to a GOTO label across try/catch blocks is allowed. In HipHop,
it isn't.
(6) ReflectionProperty::setAccessible() is not supported.
-23
Ver Arquivo
@@ -1,23 +0,0 @@
<h2>Inconsistencies between HipHop compiler and interpreter</h2>
These are the known inconsistencies between running a compiled program and
running it through hphpi interpreter.
1. class_exists($clsname) may give different results. This is because compiled
version has all classes declared by default, unless it is marked as "volatile",
either by a configuration file, or automatically by the compiler recognizing
a class name literal is used as in, for example, class_exists('MyClass').
2. get_defined_vars() may return different members, as hphpi prepares the list
by collecting variables that are declared so far, versus compiled version
always include all variables visible to the scope.
3. Compiled version cannot give "undefined variable" notices.
4. Some of the syntax errors that are reported by hphpi will be compiled just
fine without any warnings. For examples, repeating same modifiers for a class
or its method or property: "public private function foo() {}".
5. Some of the coding errors that are reported by hphpi will be compiled into
runtime errors or swallowed if PHP does the same. For examples, calling a
function with wrong number of arguments.
-169
Ver Arquivo
@@ -1,169 +0,0 @@
<?php
$topics =
array(
'Compiler' => array(
'Command line options' => 'command.compiler',
'Configurable options' => 'options.compiler',
),
'Compiled Program' => array(
'Command line options' => 'command.compiled',
'Configurable options' => 'options.compiled',
'Administrative commands' => 'command.admin_server',
'Server Status' => 'server.status',
'Server Statistics' => 'server.stats',
),
'Debugger' => array(
'Getting Started' => 'debugger.start',
'All Commands' => 'debugger.cmds',
'Command A-Z' => 'debugger.refs',
),
'HTTP Server' => array(
'Rewrite Rules' => 'server.rewrite_rules',
'SSL Setup' => 'server.ssl',
),
'Inconsistencies' => array(
'PHP vs. HipHop' => 'inconsistencies',
'HipHop Compiler vs. Interpreter' => 'inconsistencies.hphpi',
),
'New Features' => array(
'New functions' => 'extension.new_functions',
'Parallel execution' => 'threading',
'Server documents' => 'server.documents',
'RPC server' => 'server.rpc_server',
'Xbox server' => 'server.xbox_server',
'Dangling server' => 'server.dangling_server',
),
'Foreign Function Interfaces' => array(
'C++' => 'ffi.c++',
'Java' => 'ffi.java',
'Python' => 'ffi.python',
),
'Debugging' => array(
'Server' => 'debug.server',
'CPU Profiling' => 'debug.profile',
'Memory leak detection' => 'debug.leak',
'Mutex contention' => 'debug.mutex',
'Useful gdb commands' => 'debug.gdb',
'Useful Linux commands' => 'debug.linux',
),
'Development' => array(
'Coding guidelines' => 'coding_guideline',
'Type system' => 'runtime.type_system',
'Memory model' => 'runtime.memory_model',
'Writing new extensions' => 'extension.development',
'Useful commands' => 'command.project',
),
'References' => array(
'Configuration file format' => 'hdf',
),
);
///////////////////////////////////////////////////////////////////////////////
// main
$css = 'style'; // default
if (isset($_GET['css'])) $css = $_GET['css'];
echo "<link type='text/css' rel='stylesheet' href='$css.css' />";
$file = 'coding_guideline';
if (isset($_GET['file'])) $file = $_GET['file'];
$doc = file_get_contents(realpath(dirname(__FILE__))."/$file");
echo '<table cellpadding=0 cellspacing=0 border=0>';
echo '<tr><td valign=top width=200>';
echo format_index($file);
echo '</td><td valign=top bgcolor=white width=640>';
if (preg_match('/^debugger\./', $file)) {
echo format_debugger_doc($doc);
} else {
echo format_document($doc);
}
echo '</td></tr></table>';
///////////////////////////////////////////////////////////////////////////////
// helpers
function format_index($file) {
global $topics;
$found_files = array();
exec('find . -type f', $found_files);
$files = array();
foreach ($found_files as $f) {
$f = substr($f, 2); // skipping "./"
if (!preg_match('/(~|Makefile|index\.php|style\.css|www\.pid)/', $f)) {
$files[$f] = $f;
}
}
foreach ($topics as $topic => $group) {
foreach ($group as $name => $f) {
unset($files[$f]);
}
}
if (!empty($files)) {
$topics['New Topics'] = $files;
}
echo '<table cellpadding=1 cellspacing=3 border=1 bgcolor=white>';
echo '<tr><td colspan=2 class="hphp">HipHopDoc</td></tr>';
echo '<tr><td colspan=2>&nbsp;</td></tr>';
foreach ($topics as $topic => $group) {
echo "<tr><td colspan=2 class='topic'>";
echo "<nobr>$topic</nobr></a></td></tr>";
foreach ($group as $name => $f) {
unset($files[$f]);
echo '<tr><td width=5></td><td><nobr>';
$class = $f == $file ? 'current_file' : 'file';
echo "<span class='$class'><a href='index.php?file=".
urlencode($f)."'>$name</a></span>";
echo '</nobr></td></tr>';
}
}
echo '</table>';
}
function format_document($doc) {
$doc = preg_replace('/\n= (.*?)\n/',
"<h3>\\1</h3>\n", $doc); // h3 headers
$doc = preg_replace('/\n([0-9]+\. )(.*?)\n/',
"<h3>\\1\\2</h3>\n", $doc); // 1. 2. 3.
$doc = preg_replace('/\n(\([0-9]+\) )(.*?)\n/',
"\n\\1<u>\\2</u>\n", $doc); // (1) (2) (3)
$doc = preg_replace('/((?:\n- [^\n]*(?:\n [^\n]+)*)+)/',
"\n<ul>\\1</ul>\n", $doc); // lists
$doc = preg_replace('/\n- /', "\n<li>", $doc); // list items
$doc = preg_replace('/((?:\n( |\t)[^\n]*)+)/',
"\n<pre>\\1</pre>\n", $doc); // code blocks
$doc = preg_replace('/(<li>[^\n]*)\n<pre>(.*?)<\/pre>/s',
"\\1 \\2", $doc); // fix list item's 2nd lines
$doc = preg_replace('/\n([^ \t]+): (.*)/',
"<br><b class=item_header>\\1</b>: ".
"<span class=item_details>\\2</span>",
$doc); // item: details
$doc = preg_replace('/\n\n/', '<p>', $doc); // paragraphs
$doc = preg_replace('/<T>/', '&lt;T&gt;', $doc); // C++ templates
$doc = preg_replace('/<\?/', '&lt;?', $doc); // PHP start tags
$doc = preg_replace('/\[\[[ \n]*(.*?)[ \n]*\|[ \n]*(.*?)[ \n]*\]\]/s',
'<a href="\\1">\\2</a>',$doc); // links
// copyright notice
$doc .= '<p>&nbsp;<table width="100%"><tr><td class="footer" align=right>'.
'Facebook &copy; 2009</td></tr></table>';
return $doc;
}
function format_debugger_doc($doc) {
$doc = preg_replace('/</', '&lt;', $doc);
$doc = preg_replace('/ *(?:\xe2\x94\x80|\-){5,}(.*) '.
'(?:\xe2\x94\x80|\-){5,}/',
'<h2>$1</h2>', $doc);
$doc = preg_replace("/('\[.*?')/", '<b>$1</b>', $doc);
$doc = preg_replace("/(\{.*?\})/", '<i>$1</i>', $doc);
return format_document($doc);
}
-116
Ver Arquivo
@@ -1,116 +0,0 @@
<h2>Memory Model</h2>
In HipHop, there are several different types of variables, depending on how
their lifetime is controled and how they allocate and deallocate memories.
1. Process Memory Variables
(1) APC Variables
APC stands for Alternative PHP Cache in PHP/Zend terminology, and they are
shared by multiple processes in pre-forking Apache environment. In HipHop,
APC's semantics is kept by two different implementations, depending on how
program is configured:
- If HipHop is configured to run as one single process with multiple threads,
APC variables are merely the ones that are shared by all threads. They are
accessed through apc_store() and apc_fetch() functions by name-value lookups.
In this model, APC variables are implemented with plain memory, allocated and
deallocated through malloc/free calls. Then, granularity locking is
implemented to ensure access from multiple threads are safe and efficient.
- If HipHop is configured to run with shared memory for APC, those variables
are allocated and deallocated through boost::inter_process classes, which
operate on real shared memory regions that multiple processes can attach to.
In this model, we used the same type of granularity locking for safe reads
and writes of these variables.
(2) C++ Static Variables
Regular C++ static variables will be accessible from multiple threads
automatically. Proper locking is needed for thread-safety.
2. Thread Local Variables
(1) ThreadLocal<T>
HipHop implemented ThreadLocal<T> template class that wraps any C++ data
structures to make them thread local. A ThreadLocal<T> object is only intended
to be accessed by a single thread, thus avoiding mutex locking.
(2) Persistent Objects
In PHP extensions, some objects are persistent across multiple requests, and
HipHop has also implemented this type of variables for resource data. They are
thread local, therefore, each thread has its own persistent object storage.
They are also accessed by names, just like how PHP/Zend has implemented it.
3. Request Local Variables
A request local variable is automatically thread local. In addition, they also
have initialization and shutdown processes at beginning and end of each
HTTP request.
(1) PHP Variables
All variables from user PHP code are request local variables. These variables
will go out of scope when a request is finished, even if it was a global
variable.
These variables can be pritimive types, String, Array, Object or Variant. They
are allocated and deallocated through smart allocators and linear allocators.
(2) RequestLocal<T>
HipHop also implemented RequestLocal<T> template class to allow PHP extensions
to properly initialize and uninitialize certain request local variables.
The template class simply implemented requestInit() and requestShutdown()
virtual functions that will be called by execution engine at startup and
shutdown time of an HTTP request.
<h2>Memory Allocators</h2>
Two speciailized memory allocators are implemented in HipHop, in addition to
the general purpose tcmalloc we used for replacing glic's malloc/free.
1. SmartAllocator<T>
A SmartAllocator simply allocates one slab of multiple objects with the same
size a time. Then it will use replacement new (macro-ed as NEW in HipHop code
base) for any caller to allocate a new one from the slab.
When an object is deallocated, it will be pushed to a free list maintained by
the allocator. Such free list is first consulted when a new allocation is
requested.
By doing so, many malloc/free calls otherwise will turn into push/pop
operations on the free list, with some rare malloc/free calls for slabs.
The tradeoff is, each object will take an extra 64-bit pointer storage in
free list.
2. LinearAllocator
HipHop supports memory state check points, so that on subsequent requests,
certain user PHP code doesn't have to be executed again, if its sole purpose
is to initialize global states to certain values.
To support this feature, we also implemented a so-called "linear allocator"
to allocate variable-sized objects during backup time of doing a checkpoint.
For example, a String class wraps StringData that's in fixed size. So
StringData may use SmartAllocator for its allocation/deallocation. But
StringData may internally keep a char pointer that has a variable size. This
string pointer will be allocated through general purpose malloc/free initially,
but it will be copied into linear allocator, if it is allocated before a
check point is taken. When we restore a checkpoint, we then don't have to
make a new copy of the string any more, as all we have to do is to copy over
the string pointer that's always valid, as long as we hold the linear allocator
memory for the entire life.
By doing so, we can memcpy entire linear allocator's memory each time we
restore a checkpoint, thus making it cheaper than many smaller malloc/free
calls.
-103
Ver Arquivo
@@ -1,103 +0,0 @@
<h2>Server Documents</h2>
This flow is implemented in hphp/src/cpp/base/server/http_server.cpp:
+-------------+
| APC Priming |
+------+------+
|
V
+-----------------+
| StartupDocument |
+--------+--------+
|
V
+---------------------------------+
| |
V V
+============================+ +=================+
| Worker Thread | | Service Threads |
|____________________________| |_________________|
| | | |
| +----------------+ | | ThreadDocuments |
| | WarmupDocument | | | |
| +-------+--------+ | +=================+
| | |
| +-----> (chekpoint) | ...
| | | |
| | V |
| | +----------------+ |
| | | RequestInit | |
| | +----------------+ |
| | | backup |
| | +----------+ |
| | V | |
| | +----------------+ R |
| | | URL Handling | P |
| | +----------------+ C |
| | | | |
| | +-restore--+ |
| | | |
| +-(rollback)-+ |
| |
+============================+
1. StartupDocument
This file is executed when web server starts, and it is executed before any
thread gets started but after APC is primed. Example use:
* bootstrapping server
* preparing parameters for service threads (see below): in this case, we have
to use APC to pass those parameters into service threads.
2. ThreadDocuments
Each one of these files will be executed in its own thread, and they don't
share variables with any other threads. Therefore, if we need to pass data
between them, we have to use APC.
There is a system function "hphp_service_thread_started" that needs to be
called at certain point. This function tells the engine that this thread has
finished any initialization sequences that have to happen before any HTTP
request is handled. Even if a service thread doesn't have any work to do
before HTTP requests, hphp_service_thread_started() is still needed for engine
to proceed without infinite waiting for service threads to start.
There is also another variant of these threads, called ThreadLoopDocuments, that
differs from normal ThreadDocuments in that it executes the document in an
infinite loop, and doesn't have any requirements of hphp_service_thread_started
being called. It can be useful to recover memory after different execution of
the document.
3. WarmupDocument
A warmup document is executed during a worker thread's startup time, and it's
only executed just once for the entire life of a worker thread. Right after
this warmup document is run, a worker thread takes a checkpoint of its memory
state. Then the worker thread will start its request handling loop. At end of
each request handling, it will rollback its memory state to the checkpoint.
A warmup document can prepare global variables and other persistent data that
are request neutral. This way we can avoid running the same initialization
sequence for every single request.
4. RequestInit Function/Document
This function or document is executed after every checkpoint, so to initialize
certain states or request specific coding. Both can be specified, and
RequestInitDocument is executed ahead of RequestInitFunction.
5. RPCRequestHandler
RPCRequestHandler will call ExecutionContext::backupSession() right after
RequestInit function/document, and it will call ExecutionContext::
restoreSession() right after it finishes one request processing and it goes
back to a state right after RequestInit is executed.
RPCRequestHandler will also reset itself from time to time, either after
processing certain number of requests or after certain amount of time. When
this happens, it will go back to checkpoint and re-execute RequestInit
function/document.
-159
Ver Arquivo
@@ -1,159 +0,0 @@
<h2> Multi-Tasking and Multi-Threading Support</h2>
To perform parallel execution in PHP without forking a new process, we can
choose one of these 3 new facilities:
1. Pagelet Server
This is already implemented. A pagelet server is similar to a CURL call to
localhost. Look for "Pagelet Server" in compiled program's options for how to
set it up. The new pagelet server functions work like this,
// This starts a pagelet server thread to process the URL just as if
// it's a new web request with specified headers and post data.
// The request method would be GET if the post data is empty.
$task = <b>pagelet_server_task_start</b>($url, $headers, $post_data);
// Main thread can now do extra work while pagelet server is processing.
...
// Optionally make this non-blocking call any time to check status.
$status = <b>pagelet_server_task_status</b>($task);
...
// Finally, we make a blocking call to wait for pagelet server's result,
// which is the entire output of the web page, with response headers and
// status code.
$headers = array(); $code = 0;
$result = <b>pagelet_server_task_result</b>($task, $headers, $code);
2. Xbox Tasks
This is already implemented. An xbox system is designed for cross-box messaging
that's described in "server.xbox_server" documentation. But when it runs
locally, it provides parallel execution in a separate thread.
// We start an xbox task by sending to localhost a message.
$task = <b>xbox_task_start</b>($message);
// Main thread can now do extra work while xbox task is processing.
...
// Optionally make this non-blocking call any time to check status.
$status = <b>xbox_task_status</b>($task);
...
// Finally, we make a blocking call to check message processing returns.
$ret = null;
$code = <b>xbox_task_result</b>($task, $timeout_ms, $ret);
On message processing side, one has to implement a PHP function like this,
function <b>xbox_process_message</b>($msg) {
...
return $ret;
}
Please note that an xbox thread starts its execution with its own global
states without sharing anything with main thread, other than $msg and $ret that
are passed between these threads at enter and exit points. To share states,
please read on for call_user_func_async() series.
3. call_user_func_async() and call_user_func_array_async()
<b>Note: This functionality is deprecated. Please use one of the alternative
forms of concurrency delineated above.</b>
"Fork" program into 2 or more threads at any time point of the execution from
the same set of global states, then "join" when thread finishes its execution.
// This is non-blocking, and global states will be duplicated here.
$handle = <b>call_user_func_async</b>($func, $param1, $param2, ...);
// Main thread can now do extra work while the other thread is running.
do_main_thread_jobs();
$ret = <b>end_user_func_async</b>($handle, $default_strategy,
$additional_strategies);
Please note that global states will be duplicated when call_user_func_async()
is called, so that each thread (the main thread and the new thread) will have
its own copy of the states. From then on, they never share anything (other than
APC). When end_user_func_async() is called, the global state of the new
thread will be "merged" back into main thread's depending on how strategies are
specified.
$default_strategy can be,
(1) GLOBAL_STATE_IGNORE (default)
In this case, new thread's modifications of global states will be thrown away.
(2) GLOBAL_STATE_OVERWRITE
In this case, new thread's modifications of global states will entirely
replace main thread's. Do so ONLY when you are sure main thread's global states
can be lost during this overwrite. Otherwise, please use GLOBAL_STATE_IGNORE
and use function output parameters to pass back global states that need to
be copied back to main thread.
(3) GLOBAL_STATE_SKIP
In this case, new thread's modifications of global states will be merged into
main thread's, and when there is a conflict, new thread's state will not be
merged at all. "Conflict" is currently only defined as an array having the same
first level key with different values. Then the new value under the key will
be skipped. For example, if main thread has array('a' => 1, 'b' => 2) and
new thread has array('a' => 3, 'b' => 4), after merge it would become
array('a' => 1, 'b' => 4). Note that this is NOT recursive and it only applies
to first level keys.
$additional_strategies can be used to specify finer granularity rules:
array({global symbol type} => array({name} => {strategy}, ...), ...);
where {global symbol type} can be any one of these,
- GLOBAL_SYMBOL_GLOBAL_VARIABLE
- GLOBAL_SYMBOL_STATIC_VARIABLE
- GLOBAL_SYMBOL_CLASS_STATIC
- GLOBAL_SYMBOL_DYNAMIC_CONSTANT
- GLOBAL_SYMBOL_FILE_INCLUDE
- GLOBAL_SYMBOL_REDECLARED_FUNCTION
- GLOBAL_SYMBOL_REDECLARED_CLASS
For example,
end_user_func_async($handle, GLOBAL_STATE_IGNORE,
array(GLOBAL_SYMBOL_GLOBAL_VARIABLE =>
array('CACHE' => GLOBAL_STATE_SKIP)));
This will ignore all modifications from a new thread, except $GLOBALS['CACHE'],
which will merge any values under $GLOBALS['CACHE'][$key] that are not present
in main thread.
NOTE: if the asynchronously invoked function has pass-by-ref parameters, at the
time of end_user_func_async() call, their values will overwrite those in the
main thread. This also applies to $this, which is essentially a special
pass-by-ref parameter.
For example,
class A {
var $a = 1;
function f(&$a, $b) { $this->a = 2; $a = 2; $b = 2; }
}
$obj = new A;
$a = 1;
$b = 1;
$h = call_user_func_async(array($obj, 'f'), $a, $b);
end_user_func_async($h);
After the end_user_func_async() call, $obj->a and $a will be 2, but $b will
remain 1.
Check status of the async job(s):
mixed check_user_func_async(mixed $handles, int $timeout = -1);
This function takes one or multiple handles and check whether the job(s) have
finished. If taking a single handle, it will return TRUE or FALSE to indicate
whether the job has finished. If taking an array, it will return an array of
finished jobs.
The parameter timeout is in milliseconds. If -1 is specified, it is
non-blocking. If 0 is specified, it blocks until some of the specified jobs
are done.
+113
Ver Arquivo
@@ -0,0 +1,113 @@
#
# +----------------------------------------------------------------------+
# | 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/eval runtime/ext runtime/vm system 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})
endforeach(dir ${RECURSIVE_SOURCE_SUBDIRS})
# Disable hardware counters off of Linux
if(NOT LINUX)
add_definitions(-DNO_HARDWARE_COUNTERS)
list(REMOVE_ITEM CXX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/runtime/base/hardware_counter.cpp)
endif()
# remove ext_hhvm, util/tests, and runtime/vm/translator/test
foreach (file ${CXX_SOURCES})
if (${file} MATCHES "ext_hhvm")
list(REMOVE_ITEM CXX_SOURCES ${file})
endif()
if (${file} MATCHES "util/test")
list(REMOVE_ITEM CXX_SOURCES ${file})
endif()
if (${file} MATCHES "runtime/vm/translator/test")
list(REMOVE_ITEM CXX_SOURCES ${file})
endif()
if (${file} MATCHES "runtime/vm/translator/hopt/test")
list(REMOVE_ITEM CXX_SOURCES ${file})
endif()
endforeach(file ${CXX_SOURCES})
# remove ext/sep for hhvm
foreach (file ${CXX_SOURCES})
if (${file} MATCHES "ext/sep")
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")
if (NOT SKIP_BUNDLED_XHP)
add_subdirectory(third_party/xhp/xhp)
endif()
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 runtime/vm/repo_schema.h
COMMAND hphp/tools/generate_repo_schema.sh
DEPENDS ${CXX_SOURCES} ${C_SOURCES}
WORKING_DIRECTORY ${HPHP_HOME}
COMMENT "Generating Repo Schema ID"
VERBATIM)
ADD_LIBRARY(hphp_runtime_static STATIC runtime/vm/repo_schema.h ${CXX_SOURCES} ${C_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(compiler)
add_subdirectory(runtime/ext_hhvm)
add_subdirectory(hhvm)
if (NOT "$ENV{HPHP_NOTEST}" STREQUAL "1")
add_subdirectory(test)
endif ()
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
@@ -219,7 +219,7 @@ class AliasManager {
void beginInExpression(StatementPtr parent, ExpressionPtr kid);
void endInExpression(StatementPtr requestor);
bool isInExpression() const {
ASSERT((m_exprIdx >= 0 && m_exprParent) ||
assert((m_exprIdx >= 0 && m_exprParent) ||
(m_exprIdx == -1 && !m_exprParent));
return m_exprIdx != -1;
}
@@ -251,6 +251,7 @@ class AliasManager {
std::string m_returnVar;
int m_nrvoFix;
int m_inCall;
bool m_inlineAsExpr;
bool m_noAdd;
bool m_preOpt;
@@ -265,6 +266,7 @@ class AliasManager {
ControlFlowGraph *m_graph;
std::map<std::string,int> m_gidMap;
std::map<std::string,SimpleVariablePtr> m_objMap;
ExpressionPtr m_expr;
int m_exprIdx;
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+598
Ver Arquivo
@@ -0,0 +1,598 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 __ANALYSIS_RESULT_H__
#define __ANALYSIS_RESULT_H__
#include <compiler/code_generator.h>
#include <compiler/analysis/code_error.h>
#include <compiler/option.h>
#include <compiler/analysis/block_scope.h>
#include <compiler/analysis/symbol_table.h>
#include <compiler/analysis/function_container.h>
#include <compiler/package.h>
#include <util/string_bag.h>
#include <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:
Locker(const AnalysisResult *ar) :
m_ar(const_cast<AnalysisResult*>(ar)),
m_mutex(m_ar->getMutex()) {
m_mutex.lock();
}
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 loadBuiltinFunctions();
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;
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;
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;
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();
/**
* Checks circular class derivations that can cause stack overflows for
* subsequent analysis. Also checks to make sure no two redundant parents.
*/
void checkClassDerivations();
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:
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:
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
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
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 // __ANALYSIS_RESULT_H__
@@ -18,7 +18,6 @@
#include <compiler/statement/statement.h>
using namespace HPHP;
using namespace boost;
///////////////////////////////////////////////////////////////////////////////
@@ -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);
@@ -80,26 +80,26 @@ BitSetBlock BitSetVec::getBlock(int block) {
BitOps::Bits *BitSetVec::getTempBits(int id) const {
size_t offset = id * m_rowSize;
assert(offset < m_blockSize);
always_assert(offset < m_blockSize);
return add(m_bits, offset);
}
BitOps::Bits *BitSetBlock::getRow(int row) const {
size_t offset = m_owner->rowOffset(row);
assert(offset != (size_t)-1);
always_assert(offset != (size_t)-1);
return BitSetVec::add(m_bits, offset);
}
void BitSetBlock::setBit(int row, int id, bool v) {
BitOps::Bits *bits = getRow(row);
assert((unsigned)id < m_owner->width());
always_assert((unsigned)id < m_owner->width());
BitOps::set_bit(id, bits, v);
}
bool BitSetBlock::getBit(int row, int id) const {
BitOps::Bits *bits = getRow(row);
assert((unsigned)id < m_owner->width());
always_assert((unsigned)id < m_owner->width());
return BitOps::get_bit(id, bits);
}
@@ -14,12 +14,12 @@
+----------------------------------------------------------------------+
*/
#ifndef __BIT_SET_VEC_H__
#define __BIT_SET_VEC_H__
#ifndef incl_HPHP_BIT_SET_VEC_H_
#define incl_HPHP_BIT_SET_VEC_H_
#include <limits.h>
#include <stddef.h>
#include <assert.h>
#include "util/assertions.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -142,7 +142,7 @@ class BitSetVec {
BitSetBlock getBlock(int block);
size_t width() const { return m_width; }
size_t rowOffset(int row) const {
assert((unsigned)row < (unsigned)m_maxId);
always_assert((unsigned)row < (unsigned)m_maxId);
size_t offset = m_idOffsets[row];
return offset - 1;
}
@@ -26,7 +26,6 @@
#include <compiler/analysis/file_scope.h>
using namespace HPHP;
using namespace boost;
///////////////////////////////////////////////////////////////////////////////
@@ -62,7 +61,7 @@ void BlockScope::incLoopNestedLevel() {
}
void BlockScope::decLoopNestedLevel() {
ASSERT(m_loopNestedLevel > 0);
assert(m_loopNestedLevel > 0);
m_loopNestedLevel--;
}
@@ -101,26 +100,23 @@ ClassScopeRawPtr BlockScope::getContainingClass() {
return ClassScopeRawPtr((HPHP::ClassScope*)bs);
}
ClassScopePtr BlockScope::findExactClass(const std::string &className) {
if (ClassScopePtr currentCls = getContainingClass()) {
if (!strcasecmp(className.c_str(), currentCls->getName().c_str())) {
ClassScopeRawPtr BlockScope::findExactClass(ClassScopeRawPtr cls) {
if (ClassScopeRawPtr currentCls = getContainingClass()) {
if (cls->getName() == currentCls->getName()) {
return currentCls;
}
}
if (FileScopePtr currentFile = getContainingFile()) {
StatementList &stmts = *currentFile->getStmt();
for (int i = stmts.getCount(); i--; ) {
StatementPtr s = stmts[i];
if (s && s->is(Statement::KindOfClassStatement)) {
ClassScopePtr scope =
static_pointer_cast<ClassStatement>(s)->getClassScope();
if (!strcasecmp(className.c_str(), scope->getName().c_str())) {
return scope;
}
}
}
return currentFile->resolveClass(cls);
}
return ClassScopePtr();
return ClassScopeRawPtr();
}
FunctionScopeRawPtr BlockScope::findExactFunction(FunctionScopeRawPtr func) {
if (FileScopePtr currentFile = getContainingFile()) {
return currentFile->resolveFunction(func);
}
return FunctionScopeRawPtr();
}
bool BlockScope::hasUser(BlockScopeRawPtr user, int useKinds) const {
@@ -160,7 +156,7 @@ void BlockScope::addUse(BlockScopeRawPtr user, int useKinds) {
m_orderedUsers.push_back(&*val.first);
user->m_orderedDeps.push_back(
std::make_pair(BlockScopeRawPtr(this), &(val.first->second)));
ASSERT(user->getMark() != BlockScope::MarkReady &&
assert(user->getMark() != BlockScope::MarkReady &&
user->getMark() != BlockScope::MarkWaiting);
} else {
val.first->second |= useKinds;
@@ -169,7 +165,7 @@ void BlockScope::addUse(BlockScopeRawPtr user, int useKinds) {
}
void BlockScope::addUpdates(int f) {
ASSERT(f > 0);
assert(f > 0);
if (inTypeInference()) {
// we *must* have the mutex
getInferTypesMutex().assertOwnedBySelf();
@@ -194,7 +190,7 @@ void BlockScope::addUpdates(int f) {
}
void BlockScope::announceUpdates(int f) {
ASSERT(f > 0);
assert(f > 0);
if (inTypeInference()) {
// If this scope is currently being processed by this thread, don't bother
// adding it to the updated map. otherwise, add it
@@ -229,7 +225,9 @@ 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;
if (d1) return d1;
return strcasecmp(p1->getName().c_str(), p2->getName().c_str());
}
@@ -132,12 +132,14 @@ public:
};
/* Assert the size and bit-consecutiveness of UseKindNonStaticRef */
CT_ASSERT(BitCount<UseKindNonStaticRef>::value == 16);
CT_ASSERT(BitPhase<UseKindNonStaticRef>::value <= 2);
static_assert(BitCount<UseKindNonStaticRef>::value == 16,
"UseKindNonStaticRef should have 16 bits set");
static_assert(BitPhase<UseKindNonStaticRef>::value <= 2,
"UseKindNonStaticRef set bits should be consecutive");
static int GetNonStaticRefUseKind(unsigned int hash) {
int res = ((int)UseKindNonStaticRef0) << (hash % 16);
ASSERT(res >= ((int)UseKindNonStaticRef0) &&
assert(res >= ((int)UseKindNonStaticRef0) &&
res <= ((int)UseKindNonStaticRef15));
return res;
}
@@ -152,6 +154,17 @@ public:
MarkProcessed
};
class ScopeCompare {
public:
bool operator()(const BlockScopeRawPtr &p1,
const BlockScopeRawPtr &p2) const {
return cmp(p1,p2) < 0;
}
int cmp(const BlockScopeRawPtr &p1, const BlockScopeRawPtr &p2) const;
};
typedef std::set<BlockScopeRawPtr, ScopeCompare> BlockScopeSet;
friend class ScopeCompare;
BlockScope(const std::string &name, const std::string &docComment,
StatementPtr stmt, KindOf kind);
virtual ~BlockScope() {}
@@ -171,7 +184,9 @@ public:
}
FileScopeRawPtr getContainingFile();
AnalysisResultRawPtr getContainingProgram();
ClassScopePtr findExactClass(const std::string &className);
ClassScopeRawPtr findExactClass(ClassScopeRawPtr cls);
FunctionScopeRawPtr findExactFunction(FunctionScopeRawPtr func);
bool hasUser(BlockScopeRawPtr user, int useFlags) const;
void addUse(BlockScopeRawPtr user, int useFlags);
@@ -201,12 +216,11 @@ public:
void inferTypes(AnalysisResultPtr ar);
/**
* Generate constant and variable declarations.
* Code gen
*/
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual bool inPseudoMain() {
virtual bool inPseudoMain() const {
return false;
}
@@ -269,7 +283,7 @@ public:
InferTypesMutex &getInferTypesMutex() { return m_inferTypesMutex; }
void setNumDepsToWaitFor(int n) {
ASSERT(n >= 0);
assert(n >= 0);
m_numDepsToWaitFor = n;
}
int getNumDepsToWaitFor() const {
@@ -279,7 +293,7 @@ public:
return ++m_numDepsToWaitFor;
}
int decNumDepsToWaitFor() {
ASSERT(m_numDepsToWaitFor > 0);
assert(m_numDepsToWaitFor > 0);
return --m_numDepsToWaitFor;
}
@@ -296,11 +310,11 @@ public:
m == MarkProcessing) {
waiting++;
} else {
ASSERT(m == MarkProcessed);
assert(m == MarkProcessed);
}
}
// >= b/c of cycles
ASSERT(waiting >= getNumDepsToWaitFor());
assert(waiting >= getNumDepsToWaitFor());
#endif /* HPHP_DETAILED_TYPE_INF_ASSERT */
}
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+492
Ver Arquivo
@@ -0,0 +1,492 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 __CLASS_SCOPE_H__
#define __CLASS_SCOPE_H__
#include <compiler/analysis/block_scope.h>
#include <compiler/analysis/function_container.h>
#include <compiler/statement/class_statement.h>
#include <compiler/statement/method_statement.h>
#include <compiler/statement/trait_prec_statement.h>
#include <compiler/statement/trait_alias_statement.h>
#include <compiler/expression/user_attribute.h>
#include <util/json.h>
#include <util/case_insensitive.h>
#include <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 needsEnableDestructor(AnalysisResultConstPtr ar) const;
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;
mutable unsigned m_needsEnableDestructor:2;
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 // __CLASS_SCOPE_H__
@@ -23,8 +23,6 @@
#include <util/lock.h>
using namespace HPHP::JSON;
using namespace std;
using namespace boost;
namespace HPHP { namespace Compiler {
///////////////////////////////////////////////////////////////////////////////
@@ -81,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/code_error.inc"
#include "compiler/analysis/core_code_error.inc"
#undef CODE_ERROR_ENTRY
}
return ErrorTexts;
@@ -97,7 +95,7 @@ void CodeErrors::clear() {
}
void CodeErrors::record(ErrorInfoPtr errorInfo) {
ASSERT(errorInfo->m_error >= 0 && errorInfo->m_error < ErrorCount);
assert(errorInfo->m_error >= 0 && errorInfo->m_error < ErrorCount);
Lock lock(m_mutex);
m_errors[errorInfo->m_error][errorInfo->m_construct1] = errorInfo;
}
@@ -163,7 +161,7 @@ void CodeErrors::serialize(JSON::CodeError::OutputStream &out) const {
void CodeErrors::saveToFile(AnalysisResultPtr ar,
const char *filename,
bool varWrapper) const {
ofstream f(filename);
std::ofstream f(filename);
if (f) {
JSON::CodeError::OutputStream o(f, ar);
if (varWrapper) f << "var CodeErrors = ";
@@ -180,6 +178,7 @@ void ClearErrors() {
}
void Error(ErrorType error, ConstructPtr construct) {
if (!Option::RecordErrors) return;
ErrorInfoPtr errorInfo(new ErrorInfo());
errorInfo->m_error = error;
errorInfo->m_construct1 = construct;
@@ -188,6 +187,7 @@ void Error(ErrorType error, ConstructPtr construct) {
}
void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
if (!Option::RecordErrors) return;
ErrorInfoPtr errorInfo(new ErrorInfo());
errorInfo->m_error = error;
errorInfo->m_construct1 = construct1;
@@ -197,6 +197,7 @@ void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
}
void Error(ErrorType error, ConstructPtr construct, const std::string &data) {
if (!Option::RecordErrors) return;
ErrorInfoPtr errorInfo(new ErrorInfo());
errorInfo->m_error = error;
errorInfo->m_construct1 = construct;
@@ -215,7 +216,7 @@ void SaveErrors(AnalysisResultPtr ar,
}
void DumpErrors(AnalysisResultPtr ar) {
JSON::CodeError::OutputStream o(cerr, ar);
JSON::CodeError::OutputStream o(std::cerr, ar);
s_code_errors.serialize(o);
}
@@ -31,9 +31,10 @@ namespace Compiler {
enum ErrorType {
#define CODE_ERROR_ENTRY(x) x,
#include "compiler/analysis/code_error.inc"
#include "compiler/analysis/core_code_error.inc"
#undef CODE_ERROR_ENTRY
ErrorCount
ErrorCount,
NoError
};
/**
+253
Ver Arquivo
@@ -0,0 +1,253 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 <compiler/analysis/constant_table.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/type.h>
#include <compiler/code_generator.h>
#include <compiler/expression/expression.h>
#include <compiler/expression/scalar_expression.h>
#include <compiler/option.h>
#include <util/util.h>
#include <util/hash.h>
#include <compiler/analysis/class_scope.h>
#include <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());
}
}
}
@@ -81,22 +81,6 @@ public:
* Generate all constant declarations for this symbol table.
*/
void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
bool newline = true) const;
void getCPPDynamicDecl(CodeGenerator &cg, AnalysisResultPtr ar,
Type2SymbolSetMap &type2names);
void outputCPPDynamicImpl(CodeGenerator &cg, AnalysisResultPtr ar);
bool outputSingleConstant(CodeGenerator &cg, AnalysisResultPtr ar,
const std::string &name) const;
void collectCPPGlobalSymbols(StringPairSet &symbols, CodeGenerator &cg,
AnalysisResultPtr ar);
/**
* Generate all class constants in class info map.
*/
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar,
bool last = true);
bool isRecursivelyDeclared(AnalysisResultConstPtr ar,
const std::string &name) const;
@@ -106,6 +90,7 @@ public:
const std::string &name,
ClassScopePtr &defClass) const;
void cleanupForError(AnalysisResultConstPtr ar);
private:
bool m_hasDynamic;
@@ -114,10 +99,6 @@ private:
ClassScopeRawPtr findBase(AnalysisResultConstPtr ar,
const std::string &name,
const std::vector<std::string> &bases) const;
bool outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
const Symbol *sym) const;
void outputCPPConstantSymbol(CodeGenerator &cg, AnalysisResultPtr ar,
Symbol *sym);
};
///////////////////////////////////////////////////////////////////////////////
@@ -32,15 +32,13 @@
#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 <boost/graph/depth_first_search.hpp>
using namespace std;
using namespace boost;
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -66,8 +64,8 @@ typedef hphp_hash_map<ConstructRawPtr, ControlBlock*,
class ControlFlowBuilder : public FunctionWalker {
public:
ControlFlowBuilder(ControlFlowGraph *g) :
m_graph(g), m_pass(0), m_cur(0), m_head(0) {}
ControlFlowBuilder(ControlFlowGraph *g, bool isGenerator) :
m_graph(g), m_pass(0), m_isGenerator(isGenerator), m_cur(0), m_head(0) {}
int before(ConstructRawPtr cp);
int after(ConstructRawPtr cp);
@@ -103,9 +101,9 @@ private:
void addEdge(ConstructRawPtr cp_from, ConstructLocation l_from,
ConstructRawPtr cp_to, ConstructLocation l_to) {
assert(cp_from);
assert(cp_to);
assert(l_from < 2);
always_assert(cp_from);
always_assert(cp_to);
always_assert(l_from < 2);
ControlFlowInfo &from(cfi(cp_from));
ControlFlowInfo &to(cfi(cp_to));
@@ -117,9 +115,20 @@ private:
cfi(cp).m_noFallThrough = true;
}
void setEdge(ConstructRawPtr cp_from, ConstructLocation l_from,
ConstructRawPtr cp_to, ConstructLocation l_to) {
always_assert(cp_from);
always_assert(cp_to);
always_assert(l_from < 2);
ControlFlowInfo &from(cfi(cp_from));
from.m_targets[l_from].clear();
addEdge(cp_from, l_from, cp_to, l_to);
}
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) {
@@ -129,7 +138,7 @@ private:
size_t depth() const { return m_state.size(); }
ConstructRawPtr top(size_t n = 0) {
size_t ix = m_state.size();
assert(ix > n);
always_assert(ix > n);
ix -= n + 1;
return m_state[ix].cp;
}
@@ -152,7 +161,7 @@ private:
ControlFlowGraph *m_graph;
AstWalkerStateVec m_state;
int m_pass;
bool m_isGenerator;
ControlBlock *m_cur;
ControlBlock *m_head;
@@ -233,21 +242,20 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
if (ret == WalkContinue) {
if (m_pass == 1) {
if (StatementPtr s = dynamic_pointer_cast<Statement>(cp)) {
if (FunctionWalker::SkipRecurse(s)) assert(false);
if (FunctionWalker::SkipRecurse(s)) not_reached();
Statement::KindOf stype = s->getKindOf();
switch (stype) {
case Statement::KindOfUseTraitStatement:
case Statement::KindOfTraitPrecStatement:
case Statement::KindOfTraitAliasStatement:
assert(false);
break;
not_reached();
case Statement::KindOfStaticStatement:
addEdge(s, BeforeConstruct, s, AfterConstruct);
break;
case Statement::KindOfClassVariable:
assert(false);
break;
not_reached();
case Statement::KindOfClassConstant:
case Statement::KindOfGlobalStatement:
@@ -261,6 +269,7 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
TryStatementPtr t = static_pointer_cast<TryStatement>(s);
StatementListPtr catches = t->getCatches();
StatementPtr body = t->getBody();
FinallyStatementPtr finally = static_pointer_cast<FinallyStatement>(t->getFinally());
if (body) {
for (int n = catches->getCount(), j = 0; j < n; ++j) {
addEdge(body, BeforeConstruct,
@@ -268,6 +277,10 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
addEdge(body, AfterConstruct,
(*catches)[j], BeforeConstruct);
}
if (finally) {
addEdge(body, BeforeConstruct, finally, BeforeConstruct);
addEdge(body, AfterConstruct, finally, BeforeConstruct);
}
addEdge(body, AfterConstruct, t, AfterConstruct);
noFallThrough(body);
}
@@ -289,6 +302,9 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
break;
}
case Statement::KindOfFinallyStatement:
break;
case Statement::KindOfCatchStatement:
break;
@@ -396,10 +412,29 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
break;
}
case Statement::KindOfReturnStatement:
addEdge(s, AfterConstruct, root(), AfterConstruct);
noFallThrough(s);
case Statement::KindOfReturnStatement: {
setEdge(s, AfterConstruct, root(), AfterConstruct);
if (!m_isGenerator) noFallThrough(s);
/*
* Since almost anything in php /might/ throw, we
* approximate, and add edges from the beginning and
* end of a try block. But if there's a return, that
* would kill the edge from the end of the block.
* Explicitly add them here if the return is in a try
*/
size_t d = depth();
for (size_t i = 1; i < d; i++) {
TryStatementPtr t = dynamic_pointer_cast<TryStatement>(top(i));
if (t) {
StatementListPtr catches = t->getCatches();
for (int n = catches->getCount(), j = 0; j < n; ++j) {
addEdge(s, AfterConstruct, (*catches)[j], BeforeConstruct);
}
break;
}
}
break;
}
case Statement::KindOfBreakStatement:
case Statement::KindOfContinueStatement: {
@@ -433,9 +468,9 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
kid = l->getNthKid(DoStatement::CondExpr);
break;
default:
assert(0);
always_assert(0);
}
assert(kid);
always_assert(kid);
addEdge(s, AfterConstruct, kid, BeforeConstruct);
}
}
@@ -455,7 +490,7 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
break;
default:
assert(false);
not_reached();
}
} else {
ExpressionPtr e(dynamic_pointer_cast<Expression>(cp));
@@ -468,8 +503,8 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
ConstructPtr trueBranch, falseBranch;
ConstructLocation tLoc, fLoc;
getTrueFalseBranches(0, trueBranch, tLoc, falseBranch, fLoc);
ASSERT(trueBranch);
ASSERT(falseBranch);
assert(trueBranch);
assert(falseBranch);
if (b->isLogicalOrOperator()) {
addEdge(e->getNthExpr(0), AfterConstruct, trueBranch, tLoc);
} else {
@@ -517,7 +552,7 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
}
}
ControlBlock *bb = m_ccbpMap[BeforeConstruct][cp];
assert(bb);
always_assert(bb);
if (bb != m_cur) {
if (m_cur) {
addCFEdge(m_cur, bb);
@@ -528,7 +563,7 @@ int ControlFlowBuilder::before(ConstructRawPtr cp) {
ConstructPtrLocMap &beforeTargets =
c->m_targets[BeforeConstruct];
if (beforeTargets.size()) {
assert(hb);
always_assert(hb);
addCFEdge(hb, bb);
ConstructPtrLocMap::iterator it =
beforeTargets.begin(), end = beforeTargets.end();
@@ -565,7 +600,7 @@ void ControlFlowBuilder::getTrueFalseBranches(
} else if (kid == s->getNthKid(ForStatement::IncExpr)) {
; // just do the default case
} else {
ASSERT(false);
assert(false);
}
}
break;
@@ -619,7 +654,7 @@ void ControlFlowBuilder::getTrueFalseBranches(
level + 1, trueBranch, tLoc,
falseBranch, fLoc);
}
ASSERT(trueBranch && falseBranch);
assert(trueBranch && falseBranch);
if (level == 0 ||
b->getExp1() == top(level - 1)) {
falseBranch = b->getExp2();
@@ -632,7 +667,7 @@ void ControlFlowBuilder::getTrueFalseBranches(
level + 1, trueBranch, tLoc,
falseBranch, fLoc);
}
ASSERT(trueBranch && falseBranch);
assert(trueBranch && falseBranch);
if (level == 0 ||
b->getExp1() == top(level - 1)) {
trueBranch = b->getExp2();
@@ -663,7 +698,7 @@ void ControlFlowBuilder::getTrueFalseBranches(
break;
case Expression::KindOfQOpExpression:
{
ASSERT(level > 0);
assert(level > 0);
QOpExpressionPtr qop(
static_pointer_cast<QOpExpression>(e));
if (qop->getCondition() == top(level - 1)) {
@@ -688,7 +723,7 @@ void ControlFlowBuilder::getTrueFalseBranches(
break;
}
}
ASSERT(level > 0);
assert(level > 0);
if (!trueBranch) {
trueBranch = top(level - 1);
tLoc = AfterConstruct;
@@ -708,7 +743,7 @@ void ControlFlowBuilder::addCFEdge(ControlBlock *b1, ControlBlock *b2) {
void ControlFlowBuilder::addCFEdge(ControlBlock *b1,
ConstructRawPtr c2, ConstructLocation l2) {
ControlBlock *b2 = m_ccbpMap[l2][c2];
assert(b2);
always_assert(b2);
if (l2 == AfterConstruct) b2 = b2->next();
addCFEdge(b1, b2);
}
@@ -731,7 +766,7 @@ int ControlFlowBuilder::after(ConstructRawPtr cp) {
}
if (m_pass == 2) {
ControlBlock *ab = m_ccbpMap[AfterConstruct][cp];
assert(ab);
always_assert(ab);
if (ab != m_cur) {
if (m_cur) {
addCFEdge(m_cur, ab);
@@ -780,14 +815,15 @@ void ControlBlock::dump(int spc, AnalysisResultConstPtr ar,
{
ControlFlowGraph::graph_traits::in_edge_iterator i, end;
for (tie(i, end) = in_edges(this, *graph); i != end; ++i) {
for (boost::tie(i, end) = in_edges(this, *graph); i != end; ++i) {
ControlBlock *t = source(*i, *graph);
printf(" <- %08llx\n", (unsigned long long)t);
}
}
{
ControlFlowGraph::graph_traits::out_edge_iterator i, end;
for (tie(i, end) = out_edges(this, *graph); i != end; ++i) {
for (boost::tie(i, end) = out_edges(this, *graph);
i != end; ++i) {
ControlBlock *t = target(*i, *graph);
printf(" -> %08llx\n", (unsigned long long)t);
}
@@ -816,11 +852,11 @@ ControlFlowGraph *ControlFlowGraph::buildControlFlow(MethodStatementPtr m) {
ControlFlowGraph *graph = new ControlFlowGraph;
graph->m_stmt = m;
ControlFlowBuilder cfb(graph);
ControlFlowBuilder cfb(graph, m->getOrigGeneratorFunc());
cfb.run(m->getStmts());
graph->m_nextDfn = 1;
depth_first_visit(*graph, cfb.head(),
dfn_assign(), get(vertex_color, *graph));
dfn_assign(), get(boost::vertex_color, *graph));
return graph;
}
@@ -858,7 +894,7 @@ void ControlFlowGraph::dfnAdd(ControlBlock *cb) {
void ControlFlowGraph::allocateDataFlow(size_t width, int rows, int *rowIds) {
m_bitSetVec.alloc(m_nextDfn, width, rows, rowIds);
graph_traits::vertex_iterator i,e;
for (tie(i, e) = vertices(*this); i != e; ++i) {
for (boost::tie(i, e) = vertices(*this); i != e; ++i) {
ControlBlock *cb = *i;
cb->setBlock(m_bitSetVec.getBlock(cb->getDfn()));
}
@@ -866,5 +902,6 @@ void ControlFlowGraph::allocateDataFlow(size_t width, int rows, int *rowIds) {
void ControlFlowGraph::dump(AnalysisResultConstPtr ar) {
printf("Dumping control flow: %s\n", m_stmt->getName().c_str());
depth_first_search(*this, dfs_dump(ar), get(vertex_color, *this));
boost::depth_first_search(*this, dfs_dump(ar),
get(boost::vertex_color, *this));
}
@@ -17,8 +17,9 @@
#ifndef __CONTROL_FLOW_H__
#define __CONTROL_FLOW_H__
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/adjacency_iterator.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <compiler/hphp.h>
@@ -66,6 +67,14 @@ struct graph_traits<HPHP::ControlFlowGraph> {
typedef std::list<HPHP::ControlEdge*>::size_type degree_size_type;
};
template<>
struct property_traits<vertex_color_t> {
typedef default_color_type value_type;
typedef HPHP::ControlBlock *key_type;
typedef default_color_type &reference;
typedef lvalue_property_map_tag category;
};
///////////////////////////////////////////////////////////////////////////////
}
@@ -112,6 +121,7 @@ public:
edge_iterator eend() const { return m_edges.end(); }
ControlBlock *add_vertex(AstWalkerStateVec &s);
ControlEdge *add_edge(ControlBlock *a, ControlBlock *b);
MethodStatementPtr getMethod() { return m_stmt; }
private:
MethodStatementPtr m_stmt;
BitSetVec m_bitSetVec;
@@ -137,8 +147,8 @@ public:
int getDfn() const { return m_dfn; }
BitOps::Bits *getRow(int row) { return m_bitBlock.getRow(row); }
void setBit(int row, int id) {
m_bitBlock.setBit(row, id, true);
void setBit(int row, int id, bool flag = true) {
m_bitBlock.setBit(row, id, flag);
}
bool getBit(int row, int id) const {
return m_bitBlock.getBit(row, id);
@@ -190,128 +200,111 @@ private:
};
///////////////////////////////////////////////////////////////////////////////
}
namespace boost {
///////////////////////////////////////////////////////////////////////////////
inline graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor
source(graph_traits<HPHP::ControlFlowGraph>::edge_descriptor e,
const HPHP::ControlFlowGraph& g) {
inline boost::graph_traits<ControlFlowGraph>::vertex_descriptor
source(boost::graph_traits<ControlFlowGraph>::edge_descriptor e,
const ControlFlowGraph& g) {
return e->first;
}
inline graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor
target(graph_traits<HPHP::ControlFlowGraph>::edge_descriptor e,
const HPHP::ControlFlowGraph& g) {
inline boost::graph_traits<ControlFlowGraph>::vertex_descriptor
target(boost::graph_traits<ControlFlowGraph>::edge_descriptor e,
const ControlFlowGraph& g) {
return e->second;
}
inline std::pair<
graph_traits<HPHP::ControlFlowGraph>::vertex_iterator,
graph_traits<HPHP::ControlFlowGraph>::vertex_iterator>
vertices(const HPHP::ControlFlowGraph &g) {
boost::graph_traits<ControlFlowGraph>::vertex_iterator,
boost::graph_traits<ControlFlowGraph>::vertex_iterator>
vertices(const ControlFlowGraph &g) {
return std::make_pair(g.vbegin(), g.vend());
}
inline std::pair<
graph_traits<HPHP::ControlFlowGraph>::edge_iterator,
graph_traits<HPHP::ControlFlowGraph>::edge_iterator>
edges(const HPHP::ControlFlowGraph &g) {
boost::graph_traits<ControlFlowGraph>::edge_iterator,
boost::graph_traits<ControlFlowGraph>::edge_iterator>
edges(const ControlFlowGraph &g) {
return std::make_pair(g.ebegin(), g.eend());
}
inline std::pair<
graph_traits<HPHP::ControlFlowGraph>::out_edge_iterator,
graph_traits<HPHP::ControlFlowGraph>::out_edge_iterator>
boost::graph_traits<ControlFlowGraph>::out_edge_iterator,
boost::graph_traits<ControlFlowGraph>::out_edge_iterator>
in_edges(
graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor u,
const HPHP::ControlFlowGraph &g) {
boost::graph_traits<ControlFlowGraph>::vertex_descriptor u,
const ControlFlowGraph &g) {
return std::make_pair(u->ibegin(), u->iend());
}
inline std::pair<
graph_traits<HPHP::ControlFlowGraph>::out_edge_iterator,
graph_traits<HPHP::ControlFlowGraph>::out_edge_iterator>
boost::graph_traits<ControlFlowGraph>::out_edge_iterator,
boost::graph_traits<ControlFlowGraph>::out_edge_iterator>
out_edges(
graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor u,
const HPHP::ControlFlowGraph &g) {
boost::graph_traits<ControlFlowGraph>::vertex_descriptor u,
const ControlFlowGraph &g) {
return std::make_pair(u->obegin(), u->oend());
}
inline std::pair<
graph_traits<HPHP::ControlFlowGraph>::adjacency_iterator,
graph_traits<HPHP::ControlFlowGraph>::adjacency_iterator>
boost::graph_traits<ControlFlowGraph>::adjacency_iterator,
boost::graph_traits<ControlFlowGraph>::adjacency_iterator>
adjacent_vertices(
graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor u,
const HPHP::ControlFlowGraph &g) {
boost::graph_traits<ControlFlowGraph>::vertex_descriptor u,
const ControlFlowGraph &g) {
return std::make_pair(u->abegin(g), u->aend(g));
}
inline std::pair<
graph_traits<HPHP::ControlFlowGraph>::inv_adjacency_iterator,
graph_traits<HPHP::ControlFlowGraph>::inv_adjacency_iterator>
boost::graph_traits<ControlFlowGraph>::inv_adjacency_iterator,
boost::graph_traits<ControlFlowGraph>::inv_adjacency_iterator>
inv_adjacent_vertices(
graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor u,
const HPHP::ControlFlowGraph &g) {
boost::graph_traits<ControlFlowGraph>::vertex_descriptor u,
const ControlFlowGraph &g) {
return std::make_pair(u->iabegin(g), u->iaend(g));
}
inline std::pair<
graph_traits<HPHP::ControlFlowGraph>::edge_descriptor, bool>
edge(graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor a,
graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor b,
const HPHP::ControlFlowGraph &g) {
graph_traits<HPHP::ControlFlowGraph>::edge_descriptor e = a->find_to(b);
boost::graph_traits<ControlFlowGraph>::edge_descriptor, bool>
edge(boost::graph_traits<ControlFlowGraph>::vertex_descriptor a,
boost::graph_traits<ControlFlowGraph>::vertex_descriptor b,
const ControlFlowGraph &g) {
boost::graph_traits<ControlFlowGraph>::edge_descriptor e = a->find_to(b);
return std::make_pair(e, e != 0);
}
inline void add_edge(graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor a,
graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor b,
HPHP::ControlFlowGraph &g) {
inline void add_edge(boost::graph_traits<ControlFlowGraph>::vertex_descriptor a,
boost::graph_traits<ControlFlowGraph>::vertex_descriptor b,
ControlFlowGraph &g) {
g.add_edge(a, b);
}
inline int in_degree(graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor a,
const HPHP::ControlFlowGraph &g) {
inline int in_degree(boost::graph_traits<ControlFlowGraph>::vertex_descriptor a,
const ControlFlowGraph &g) {
return a->in_size();
}
inline int out_degree(graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor a,
const HPHP::ControlFlowGraph &g) {
inline int out_degree(boost::graph_traits<ControlFlowGraph>::vertex_descriptor a,
const ControlFlowGraph &g) {
return a->out_size();
}
template <typename P>
inline P get(P p, HPHP::ControlFlowGraph &g) {
inline P get(P p, ControlFlowGraph &g) {
return p;
}
template<>
struct property_traits<vertex_color_t> {
typedef default_color_type value_type;
typedef HPHP::ControlBlock *key_type;
typedef default_color_type &reference;
typedef lvalue_property_map_tag category;
};
inline default_color_type get(
vertex_color_t c,
graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor a) {
inline boost::default_color_type get(
boost::vertex_color_t c,
boost::graph_traits<ControlFlowGraph>::vertex_descriptor a) {
return a->get_color();
}
inline void put(vertex_color_t c,
graph_traits<HPHP::ControlFlowGraph>::vertex_descriptor a,
default_color_type value) {
inline void put(boost::vertex_color_t c,
boost::graph_traits<ControlFlowGraph>::vertex_descriptor a,
boost::default_color_type value) {
a->set_color(value);
}
///////////////////////////////////////////////////////////////////////////////
}
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
class ControlFlowGraphWalker : public FunctionWalker {
@@ -320,7 +313,7 @@ public:
template <class T>
void walk(T &t) {
std::pair<ControlFlowGraph::vertex_iterator,
ControlFlowGraph::vertex_iterator> v(boost::vertices(m_graph));
ControlFlowGraph::vertex_iterator> v(vertices(m_graph));
while (v.first != v.second) {
ControlBlock *b = *v.first;
m_block = b;
@@ -11,8 +11,10 @@ CODE_ERROR_ENTRY(UnknownObjectMethod)
CODE_ERROR_ENTRY(InvalidMagicMethod)
CODE_ERROR_ENTRY(UnknownFunction)
CODE_ERROR_ENTRY(BadConstructorCall)
CODE_ERROR_ENTRY(DeclaredMethodTwice)
CODE_ERROR_ENTRY(DeclaredVariableTwice)
CODE_ERROR_ENTRY(DeclaredConstantTwice)
CODE_ERROR_ENTRY(DeclaredAttributeTwice)
CODE_ERROR_ENTRY(BadDefine)
CODE_ERROR_ENTRY(RequiredAfterOptionalParam)
CODE_ERROR_ENTRY(RedundantParameter)
@@ -26,13 +28,12 @@ CODE_ERROR_ENTRY(MoreThanOneDefault)
CODE_ERROR_ENTRY(InvalidArrayElement)
CODE_ERROR_ENTRY(InvalidDerivation)
CODE_ERROR_ENTRY(InvalidOverride)
CODE_ERROR_ENTRY(ReassignThis)
CODE_ERROR_ENTRY(MissingAbstractMethodImpl)
CODE_ERROR_ENTRY(BadPassByReference)
CODE_ERROR_ENTRY(ConditionalClassLoading)
CODE_ERROR_ENTRY(GotoUndefLabel)
CODE_ERROR_ENTRY(GotoInvalidBlock)
CODE_ERROR_ENTRY(AbstractProperty)
CODE_ERROR_ENTRY(InvalidAttribute)
CODE_ERROR_ENTRY(UnknownTrait)
CODE_ERROR_ENTRY(MethodInMultipleTraits)
CODE_ERROR_ENTRY(UnknownTraitMethod)
@@ -41,3 +42,5 @@ CODE_ERROR_ENTRY(CyclicDependentTraits)
CODE_ERROR_ENTRY(InvalidTraitStatement)
CODE_ERROR_ENTRY(RedeclaredTrait)
CODE_ERROR_ENTRY(InvalidInstantiation)
CODE_ERROR_ENTRY(InvalidYield)
CODE_ERROR_ENTRY(BadDefaultValueType)
@@ -23,7 +23,6 @@
using namespace HPHP;
using std::pair;
using namespace boost;
///////////////////////////////////////////////////////////////////////////////
@@ -60,8 +59,7 @@ void DataFlow::ComputeForwards(T func, const ControlFlowGraph &g,
for (int i = 1; i <= num; i++) {
ControlBlock *b = g.getDfBlock(i);
std::pair<in_edge_iterator, in_edge_iterator> vi =
in_edges(b, g);
std::pair<in_edge_iterator, in_edge_iterator> vi = in_edges(b, g);
BitOps::Bits *ain = b->getRow(inAttr);
if (vi.first != vi.second) {
@@ -113,8 +111,7 @@ void DataFlow::ComputeBackwards(T func, const ControlFlowGraph &g,
for (int i = num; i ; i--) {
ControlBlock *b = g.getDfBlock(i);
std::pair<out_edge_iterator, out_edge_iterator> vi =
out_edges(b, g);
std::pair<out_edge_iterator, out_edge_iterator> vi = out_edges(b, g);
BitOps::Bits *aout = b->getRow(outAttr);
if (vi.first != vi.second) {
@@ -193,6 +190,13 @@ void DataFlow::ComputePartialNeeded(const ControlFlowGraph &g) {
DataFlow::PObjIn, DataFlow::PObjOut);
}
void DataFlow::ComputePartialInited(const ControlFlowGraph &g) {
DataFlow::ComputeForwards(
BitOps::bit_or, g,
DataFlow::Inited, DataFlow::Killed,
DataFlow::PInitIn, DataFlow::PInitOut);
}
void DataFlow::ComputeUsed(const ControlFlowGraph &g) {
int num = g.getNumBlocks();
size_t width = g.bitWidth();
@@ -316,8 +320,8 @@ void DataFlowWalker::processAccessChainLA(ListAssignmentPtr la) {
}
void DataFlowWalker::process(ExpressionPtr e, bool doAccessChains) {
if (e->getContext() & (Expression::AssignmentLHS|Expression::OprLValue) ||
!doAccessChains && e->hasContext(Expression::AccessContext)) {
if ((e->getContext() & (Expression::AssignmentLHS|Expression::OprLValue)) ||
(!doAccessChains && e->hasContext(Expression::AccessContext))) {
return;
}
@@ -31,6 +31,7 @@ DECLARE_BOOST_TYPES(ListAssignment);
x(Altered,0), \
x(Available,0), \
x(Referenced,0), \
x(Inited,0), \
x(Killed,0), \
x(Object,0), \
x(NotObject,0), \
@@ -44,6 +45,8 @@ DECLARE_BOOST_TYPES(ListAssignment);
x(PAvailOut,0), \
x(PRefIn,0), \
x(PRefOut,0), \
x(PInitIn,0), \
x(PInitOut,0), \
x(PObjIn,0), \
x(PObjOut,0), \
x(PAntIn,0), \
@@ -74,6 +77,7 @@ public:
static void ComputePartialNeeded(const ControlFlowGraph &g);
static void ComputeUsed(const ControlFlowGraph &g);
static void ComputePartialDying(const ControlFlowGraph &g);
static void ComputePartialInited(const ControlFlowGraph &g);
private:
template <typename T>
static void ComputeForwards(T func, const ControlFlowGraph &g,
@@ -89,7 +93,8 @@ class DataFlowWalker : public ControlFlowGraphWalker {
public:
DataFlowWalker(ControlFlowGraph *g) : ControlFlowGraphWalker(g) {}
void walk() { ControlFlowGraphWalker::walk(*this); }
template<class T>
void walk(T &t) { ControlFlowGraphWalker::walk(t); }
int after(ConstructRawPtr cp);
int afterEach(ConstructRawPtr cur, int i, ConstructRawPtr kid);
@@ -142,7 +142,7 @@ public:
void collectOrdering(BlockScopeRawPtrQueue &queue,
BlockScopeRawPtr scope) {
ASSERT(scope->getMark() != BlockScope::MarkProcessingDeps);
assert(scope->getMark() != BlockScope::MarkProcessingDeps);
scope->setMark(BlockScope::MarkProcessingDeps);
const BlockScopeRawPtrFlagsPtrVec &deps = scope->getDeps();
for (BlockScopeRawPtrFlagsPtrVec::const_iterator it = deps.begin(),
@@ -170,11 +170,11 @@ public:
BlockScopeRawPtr scope = *it;
if (!first) {
if (scope->getMark() != BlockScope::MarkWaiting) {
assert(scope->getMark() == BlockScope::MarkProcessed);
always_assert(scope->getMark() == BlockScope::MarkProcessed);
continue;
}
} else {
ASSERT((*it)->getNumDepsToWaitFor() == 0);
assert((*it)->getNumDepsToWaitFor() == 0);
}
scope->setMark(BlockScope::MarkWaitingInQueue);
numSetMarks++;
@@ -188,7 +188,7 @@ public:
collectOrdering(buffer, *it);
}
}
ASSERT((int)buffer.size() == numSetMarks);
assert((int)buffer.size() == numSetMarks);
#ifdef HPHP_DETAILED_TYPE_INF_ASSERT
// verify:
@@ -197,7 +197,7 @@ public:
for (BlockScopeRawPtrQueue::const_iterator it = scopes.begin();
it != scopes.end(); ++it) {
int m = (*it)->getMark();
ASSERT(m == BlockScope::MarkProcessingDeps ||
assert(m == BlockScope::MarkProcessingDeps ||
m == BlockScope::MarkProcessed);
}
#endif /* HPHP_DETAILED_TYPE_INF_ASSERT */
@@ -215,7 +215,7 @@ public:
}
// assert that we will make some progress in this iteration
ASSERT(!ret || !enqueued.empty());
assert(!ret || !enqueued.empty());
return ret;
}
@@ -22,7 +22,6 @@
#include <compiler/statement/statement_list.h>
using namespace HPHP;
using namespace boost;
using std::vector;
///////////////////////////////////////////////////////////////////////////////
@@ -67,7 +66,7 @@ void Dictionary::record(ExpressionPtr e) {
void Dictionary::beginBlock(ControlBlock *b) {
ControlFlowGraph *g = m_am.graph();
assert(g);
always_assert(g);
m_width = g->bitWidth();
m_altered = b->getRow(DataFlow::Altered);
@@ -61,6 +61,7 @@ public:
AttributeTagger(ControlFlowGraph *g, Dict &d) :
DataFlowWalker(g), m_dict(d) {}
void walk() { DataFlowWalker::walk(*this); }
void processAccess(ExpressionPtr e) {
m_dict.updateAccess(e);
}
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+682
Ver Arquivo
@@ -0,0 +1,682 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 __COMPILER_EMITTER_H__
#define __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 <runtime/vm/func.h>
#include <runtime/vm/unit.h>
#include <util/hash.h>
namespace HPHP {
DECLARE_BOOST_TYPES(ClosureExpression);
DECLARE_BOOST_TYPES(MethodStatement);
DECLARE_BOOST_TYPES(InterfaceStatement);
DECLARE_BOOST_TYPES(ListAssignment);
DECLARE_BOOST_TYPES(FunctionScope);
DECLARE_BOOST_TYPES(FileScope);
DECLARE_BOOST_TYPES(FunctionCall);
DECLARE_BOOST_TYPES(SimpleFunctionCall);
DECLARE_BOOST_TYPES(SwitchStatement);
DECLARE_BOOST_TYPES(ForEachStatement);
class StaticClassName;
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;
// Helper for creating unit MetaInfo.
struct MetaInfoBuilder {
void add(int pos, Unit::MetaInfo::Kind kind,
bool mVector, int arg, Id data);
void addKnownDataType(DataType dt,
bool dtPredicted,
int pos,
bool mVector,
int arg);
void deleteInfo(Offset bcOffset);
void setForUnit(UnitEmitter&) const;
private:
typedef std::vector<Unit::MetaInfo> Vec;
typedef std::map<Offset,Vec> Map;
Map m_metaMap;
};
class Emitter {
public:
Emitter(ConstructPtr node, UnitEmitter& ue, EmitterVisitor& ev)
: m_node(node), m_ue(ue), m_ev(ev) {}
UnitEmitter& getUnitEmitter() { return m_ue; }
ConstructPtr getNode() { return m_node; }
EmitterVisitor& getEmitterVisitor() { return m_ev; }
void setTempLocation(LocationPtr loc) { m_tempLoc = loc; }
LocationPtr getTempLocation() { return m_tempLoc; }
void incStat(int counter, int value) {
if (RuntimeOption::EnableEmitterStats) {
IncStat(counter, value);
}
}
struct StrOff {
StrOff(Id s, Label* d) : str(s), dest(d) {}
Id str;
Label* dest;
};
#define O(name, imm, pop, push, flags) \
void name(imm);
#define NA
#define ONE(typ) \
typ a1
#define TWO(typ1, typ2) \
typ1 a1, typ2 a2
#define THREE(typ1, typ2, typ3) \
typ1 a1, typ2 a2, typ3 a3
#define FOUR(typ1, typ2, typ3, typ4) \
typ1 a1, typ2 a2, typ3 a3, typ4 a4
#define MA std::vector<uchar>
#define BLA std::vector<Label*>&
#define SLA std::vector<StrOff>&
#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*
#define BA Label&
#define OA unsigned char
OPCODES
#undef O
#undef NA
#undef ONE
#undef TWO
#undef THREE
#undef FOUR
#undef MA
#undef BLA
#undef SLA
#undef IVA
#undef HA
#undef IA
#undef I64A
#undef DA
#undef SA
#undef AA
#undef BA
#undef OA
private:
ConstructPtr m_node;
UnitEmitter& m_ue;
EmitterVisitor& m_ev;
LocationPtr m_tempLoc;
};
struct SymbolicStack {
enum ClassBaseType {
CLS_INVALID,
CLS_LATE_BOUND,
CLS_UNNAMED_LOCAL, // loc is an unnamed local
CLS_NAMED_LOCAL, // loc is a normal program local
CLS_STRING_NAME, // name is the string to use
CLS_SELF,
CLS_PARENT
};
enum MetaType {
META_NONE,
META_LITSTR,
META_DATA_TYPE
};
private:
/**
* Symbolic stack (m_symStack)
*
* The symbolic stack is used to keep track of the flavor descriptors
* of values along with other contextual information. Each position in
* the symbolic stack can encode a "symbolic flavor" and a "marker".
* Most symbolic flavors correspond with flavor descriptors in the HHBC
* spec, but some symbolic flavors used in the symbolic stack (ex. "L")
* do not correspond with a flavor descriptor from the spec. Markers
* provide contextual information and are used by the emitter in various
* situations to determine the appropriate bytecode instruction to use.
*
* Note that not all positions on the symbolic stack correspond to a
* value on the actual evaluation stack as described in the HHBC spec.
*/
struct SymEntry {
explicit SymEntry(char s = 0)
: sym(s)
, metaType(META_NONE)
, notRef(false)
, notNull(false)
, dtPredicted(false)
, className(nullptr)
, intval(-1)
, unnamedLocalStart(InvalidAbsoluteOffset)
, clsBaseType(CLS_INVALID)
{}
char sym;
MetaType metaType;
bool notRef:1;
bool notNull:1;
bool dtPredicted:1;
union {
const StringData* name; // META_LITSTR
DataType dt; // META_DATA_TYPE
} metaData;
const StringData* className;
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
// fault funclet for).
Offset unnamedLocalStart;
// When class bases are emitted, we need to delay class lookup for
// evaluation order reasons, but may have to do some evaluation
// early. How this works depends on the type of class base---see
// emitResolveClsBase for details.
ClassBaseType clsBaseType;
};
std::vector<SymEntry> m_symStack;
/**
* Actual stack (m_actualStack)
*
* The actual stack represents the evaluation stack as described in the
* HHBC spec. Each position in m_actualStack contains the index of the
* corresponding symbolic value in m_symStack.
*/
std::vector<int> m_actualStack;
// The number of Func descriptors (in HHVM terms, ActRecs) currently on the
// stack.
int m_fdescCount;
public:
int* m_actualStackHighWaterPtr;
int* m_fdescHighWaterPtr;
SymbolicStack() : m_fdescCount(0) {}
std::string pretty() const;
void push(char sym);
void setInt(int64_t v);
void setString(const StringData* s);
void setKnownCls(const StringData* s, bool nonNull);
void setNotRef();
bool getNotRef() const;
void setKnownType(DataType dt, bool predicted = false);
void cleanTopMeta();
DataType getKnownType(int index = -1, bool noRef = true) const;
void setClsBaseType(ClassBaseType);
void setUnnamedLocal(int index, int localId, Offset startOffset);
void pop();
char top() const;
char get(int index) const;
const StringData* getName(int index) const;
const StringData* getClsName(int index) const;
bool isCls(int index) const;
bool isTypePredicted(int index = -1 /* stack top */) const;
void set(int index, char sym);
unsigned size() const;
bool empty() const;
void clear();
/*
* Erase a stack element depth below the top. This is used for some
* instructions that pull elements out of the middle, and for our
* ClassBaseType virtual elements.
*/
void consumeBelowTop(int depth);
int getActualPos(int vpos) const;
char getActual(int index) const;
void setActual(int index, char sym);
void insertAt(int depth, char sym);
int sizeActual() const;
ClassBaseType getClsBaseType(int index) const;
int getLoc(int index) const;
int64_t getInt(int index) const;
Offset getUnnamedLocStart(int index) const;
void pushFDesc();
void popFDesc();
};
class Label {
public:
Label() : m_off(InvalidAbsoluteOffset) {}
Label(Emitter& e) : m_off(InvalidAbsoluteOffset) {
set(e);
}
Offset getAbsoluteOffset() const { return m_off; }
// Sets the Label to the bytecode offset of given by e,
// fixes up any instructions that have already been
// emitted that reference this Label, and fixes up the
// EmitterVisitor's jump target info
void set(Emitter& e);
// If a Label is has not been set, it is the Emitter's
// resposibility to call bind on the Label each time it
// prepares to emit an instruction that uses the Label
void bind(EmitterVisitor& ev, Offset instrAddr, Offset offAddr);
bool isSet() { return m_off != InvalidAbsoluteOffset; }
bool isUsed();
private:
Offset m_off;
std::vector<std::pair<Offset, Offset> > m_emittedOffs;
// m_evalStack is used to store the eval stack of the
// first forward jump we see that references this label
SymbolicStack m_evalStack;
};
class Thunklet {
public:
virtual ~Thunklet();
virtual void emit(Emitter& e) = 0;
};
class Funclet {
public:
Funclet(Thunklet* body, Label* entry) : m_body(body), m_entry(entry) {}
Thunklet* m_body;
Label* m_entry;
};
class EmitterVisitor {
friend class UnsetUnnamedLocalThunklet;
public:
EmitterVisitor(UnitEmitter& ue);
~EmitterVisitor();
bool visit(ConstructPtr c);
bool visitImpl(ConstructPtr c);
void visitKids(ConstructPtr c);
void visit(FileScopePtr file);
void assignLocalVariableIds(FunctionScopePtr fs);
void fixReturnType(Emitter& e, FunctionCallPtr fn,
bool isBuiltinCall = false);
typedef std::vector<int> IndexChain;
void visitListAssignmentLHS(Emitter& e, ExpressionPtr exp,
IndexChain& indexChain,
std::vector<IndexChain*>& chainList);
void visitIfCondition(ExpressionPtr cond, Emitter& e, Label& tru, Label& fals,
bool truFallthrough);
const SymbolicStack& getEvalStack() const { return m_evalStack; }
SymbolicStack& getEvalStack() { return m_evalStack; }
void setEvalStack(const SymbolicStack& es) {
m_evalStack = es;
m_evalStackIsUnknown = false;
}
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 popEvalStackLMany();
void popEvalStackMany(int len, char symFlavor);
void pushEvalStack(char symFlavor);
void peekEvalStack(char symFlavor, int depthActual);
void pokeEvalStack(char symFlavor, int depthActual);
void prepareEvalStack();
void recordJumpTarget(Offset target, const SymbolicStack& evalStack);
void recordJumpTarget(Offset target) {
recordJumpTarget(target, m_evalStack);
}
void restoreJumpTargetEvalStack();
bool isJumpTarget(Offset target);
void setPrevOpcode(Opcode op) { m_prevOpcode = op; }
Opcode getPrevOpcode() const { return m_prevOpcode; }
bool currentPositionIsReachable() {
return (m_ue.bcPos() == m_curFunc->base()
|| isJumpTarget(m_ue.bcPos())
|| (instrFlags(getPrevOpcode()) & TF) == 0);
}
class IncludeTimeFatalException : public Exception {
public:
ConstructPtr m_node;
IncludeTimeFatalException(ConstructPtr node, const char* fmt, ...)
: Exception(), m_node(node) {
va_list ap; va_start(ap, fmt); format(fmt, ap); va_end(ap);
}
virtual ~IncludeTimeFatalException() throw() {}
EXCEPTION_COMMON_IMPL(IncludeTimeFatalException);
};
enum IterKind {
KindOfIter = 0,
KindOfMIter = 1
};
void pushIterScope(Id id, bool itRef = false) {
IterKind itKind = itRef ? KindOfMIter : KindOfIter;
m_pendingIters.push_back(std::pair<Id,IterKind>(id,itKind));
}
void popIterScope() { m_pendingIters.pop_back(); }
private:
typedef std::pair<StringData*, bool> ClosureUseVar; // (name, byRef)
typedef std::vector<ClosureUseVar> ClosureUseVarVec;
typedef std::vector<std::pair<Id,IterKind> > PendingIterVec;
class PostponedMeth {
public:
PostponedMeth(MethodStatementPtr m, FuncEmitter* fe, bool top,
ClosureUseVarVec* useVars)
: m_meth(m), m_fe(fe), m_top(top), m_closureUseVars(useVars) {}
MethodStatementPtr m_meth;
FuncEmitter* m_fe;
bool m_top;
ClosureUseVarVec* m_closureUseVars;
};
class PostponedCtor {
public:
PostponedCtor(InterfaceStatementPtr is, FuncEmitter* fe)
: m_is(is), m_fe(fe) {}
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,
NonScalarVec* v)
: m_is(is), m_fe(fe), m_vec(v) {}
void release() {
delete m_vec;
}
InterfaceStatementPtr m_is;
FuncEmitter* m_fe;
NonScalarVec* m_vec;
};
class PostponedClosureCtor {
public:
PostponedClosureCtor(ClosureUseVarVec& v, ClosureExpressionPtr e,
FuncEmitter* fe)
: m_useVars(v), m_expr(e), m_fe(fe) {}
ClosureUseVarVec m_useVars;
ClosureExpressionPtr m_expr;
FuncEmitter* m_fe;
};
class ControlTargets {
public:
ControlTargets(Id itId, bool itRef, Label& brkTarg, Label& cntTarg,
Label& brkHand, Label& cntHand) :
m_itId(itId), m_itRef(itRef), m_brkTarg(brkTarg), m_cntTarg(cntTarg),
m_brkHand(brkHand), m_cntHand(cntHand) {}
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, bool itRef, Label& brkTarg,
Label& cntTarg, Label& brkHand, Label& cntHand) : m_e(e) {
e->m_contTargets.push_front(ControlTargets(itId, itRef, brkTarg, cntTarg,
brkHand, cntHand));
}
~ControlTargetPusher() {
m_e->m_contTargets.pop_front();
}
private:
EmitterVisitor* m_e;
};
class ExnHandlerRegion {
public:
ExnHandlerRegion(Offset start, Offset end) : m_start(start),
m_end(end) {}
~ExnHandlerRegion() {
for (std::vector<std::pair<StringData*, Label*> >::const_iterator it =
m_catchLabels.begin(); it != m_catchLabels.end(); it++) {
delete it->second;
}
}
Offset m_start;
Offset m_end;
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) {}
Offset m_start;
Offset m_end;
Id m_iterId;
Label m_func;
};
class FPIRegion {
public:
FPIRegion(Offset start, Offset end, Offset fpOff)
: m_start(start), m_end(end), m_fpOff(fpOff) {}
Offset m_start;
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_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
int nonZeroI;
int defI;
};
static const size_t kMinStringSwitchCases = 8;
UnitEmitter& m_ue;
FuncEmitter* m_curFunc;
FileScopePtr m_file;
Opcode m_prevOpcode;
std::deque<PostponedMeth> m_postponedMeths;
std::deque<PostponedCtor> m_postponedCtors;
std::deque<PostponedNonScalars> m_postponedPinits;
std::deque<PostponedNonScalars> m_postponedSinits;
std::deque<PostponedNonScalars> m_postponedCinits;
std::deque<PostponedClosureCtor> m_postponedClosureCtors;
PendingIterVec m_pendingIters;
typedef std::map<const StringData*, Label*, string_data_lt> LabelMap;
LabelMap m_methLabels;
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;
std::deque<Funclet> m_funclets;
std::deque<ExnHandlerRegion*> m_exnHandlers;
std::deque<FaultRegion*> m_faultRegions;
std::deque<FPIRegion*> m_fpiRegions;
std::vector<HphpArray*> m_staticArrays;
std::set<std::string,stdltistr> m_hoistables;
LocationPtr m_tempLoc;
std::map<StringData*, Label, string_data_lt> m_gotoLabels;
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;
int scanStackForLocation(int iLast);
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);
void emitCGet(Emitter& e);
void emitVGet(Emitter& e);
void emitIsset(Emitter& e);
void emitIsNull(Emitter& e);
void emitIsArray(Emitter& e);
void emitIsObject(Emitter& e);
void emitIsString(Emitter& e);
void emitIsInt(Emitter& e);
void emitIsDouble(Emitter& e);
void emitIsBool(Emitter& e);
void emitEmpty(Emitter& e);
void emitUnset(Emitter& e);
void emitSet(Emitter& e);
void emitSetOp(Emitter& e, int op);
void emitBind(Emitter& e);
void emitIncDec(Emitter& e, unsigned char cop);
void emitPop(Emitter& e);
void emitConvertToCell(Emitter& e);
void emitFreePendingIters(Emitter& e);
void emitConvertToCellIfVar(Emitter& e);
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);
DataType analyzeSwitch(SwitchStatementPtr s, SwitchState& state);
void emitIntegerSwitch(Emitter& e, SwitchStatementPtr s,
std::vector<Label>& caseLabels, Label& done,
const SwitchState& state);
void emitStringSwitch(Emitter& e, SwitchStatementPtr s,
std::vector<Label>& caseLabels, Label& done,
const SwitchState& state);
void markElem(Emitter& e);
void markNewElem(Emitter& e);
void markProp(Emitter& e);
void markSProp(Emitter& e);
void markName(Emitter& e);
void markNameSecond(Emitter& e);
void markGlobalName(Emitter& e);
void emitNameString(Emitter& e, ExpressionPtr n, bool allowLiteral = false);
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 = nullptr);
void postponeCtor(InterfaceStatementPtr m, FuncEmitter* fe);
void postponePinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
void postponeSinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
void postponeCinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
void emitPostponedMeths();
void emitPostponedCtors();
void emitPostponedPSinit(PostponedNonScalars& p, bool pinit);
void emitPostponedPinits();
void emitPostponedSinits();
void emitPostponedCinits();
void emitPostponedClosureCtors();
enum CallUserFuncFlags {
CallUserFuncNone = -1,
CallUserFuncPlain = 0,
CallUserFuncArray = 1,
CallUserFuncSafe = 2,
CallUserFuncReturn = 4,
CallUserFuncForward = 8,
CallUserFuncSafeArray = CallUserFuncSafe | CallUserFuncArray,
CallUserFuncSafeReturn = CallUserFuncSafe | CallUserFuncReturn,
CallUserFuncForwardArray = CallUserFuncForward | CallUserFuncArray
};
bool emitCallUserFunc(Emitter& e, SimpleFunctionCallPtr node);
bool canEmitBuiltinCall(FunctionCallPtr fn, 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,
bool byRef);
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,
IterKind itKind = KindOfIter);
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);
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,
TraitAliasStatementPtr rule);
void emitClassUseTrait(PreClassEmitter* pce, UseTraitStatementPtr useStmt);
};
void emitAllHHBC(AnalysisResultPtr ar);
extern "C" {
Unit* hphp_compiler_parse(const char* code, int codeLen, const MD5& md5,
const char* filename);
Unit* hphp_build_native_func_unit(const HhbcExtFuncInfo* builtinFuncs,
ssize_t numBuiltinFuncs);
Unit* hphp_build_native_class_unit(const HhbcExtClassInfo* builtinClasses,
ssize_t numBuiltinClasses);
}
///////////////////////////////////////////////////////////////////////////////
}
}
#endif // __COMPILER_EMITTER_H__
@@ -15,7 +15,6 @@
*/
#include <compiler/analysis/alias_manager.h>
//#include <compiler/analysis/control_flow.h>
#include <compiler/analysis/expr_dict.h>
#include <compiler/expression/expression.h>
@@ -25,7 +24,6 @@
#include <compiler/statement/method_statement.h>
using namespace HPHP;
using namespace boost;
using std::vector;
///////////////////////////////////////////////////////////////////////////////
@@ -51,7 +49,7 @@ void ExprDict::build(MethodStatementPtr m) {
}
TypePtr ExprDict::extractTypeAssertion(ExpressionPtr e) const {
ASSERT(e);
assert(e);
return e->isTypeAssertion() ? e->getAssertedType() : TypePtr();
}
@@ -83,8 +81,8 @@ void ExprDict::getAllEntries(int id, TypePtrIdxPairVec &types) {
template <class T>
void ExprDict::getEntries(int id, TypePtrIdxPairVec &entries, T func) {
ASSERT(m_canonIdMap.size() == m_canonTypeMap.size());
ASSERT(id >= 0 && id < (int) m_canonTypeMap.size());
assert(m_canonIdMap.size() == m_canonTypeMap.size());
assert(id >= 0 && id < (int) m_canonTypeMap.size());
TypePtrIdxPair cur = m_canonTypeMap[id];
if (func(cur)) entries.push_back(TypePtrIdxPair(cur.first, id));
@@ -98,11 +96,11 @@ void ExprDict::getEntries(int id, TypePtrIdxPairVec &entries, T func) {
bool ExprDict::containsAssertion(TypePtr assertion,
const TypePtrIdxPairVec &types,
TypePtrIdxPair &entry) const {
ASSERT(assertion);
assert(assertion);
for (TypePtrIdxPairVec::const_iterator it = types.begin();
it != types.end(); ++it) {
const TypePtrIdxPair &cur = *it;
ASSERT(cur.first);
assert(cur.first);
if (Type::SameType(cur.first, assertion)) {
entry = cur;
return true;
@@ -112,7 +110,7 @@ bool ExprDict::containsAssertion(TypePtr assertion,
}
void ExprDict::visit(ExpressionPtr e) {
ASSERT(m_canonIdMap.size() == m_canonTypeMap.size());
assert(m_canonIdMap.size() == m_canonTypeMap.size());
if (m_am.insertForDict(e)) {
// we've never seen e's structure before, so record it
record(e);
@@ -125,7 +123,7 @@ void ExprDict::visit(ExpressionPtr e) {
m_canonIdMap[e->getCanonID()] = e->getCanonID();
} else if (e->isTypeAssertion()) {
TypePtrIdxPairVec types;
ASSERT(isCanonicalStructure(e->getCanonID()));
assert(isCanonicalStructure(e->getCanonID()));
getTypes(e->getCanonID(), types);
TypePtrIdxPair entry;
if (containsAssertion(e->getAssertedType(), types, entry)) {
@@ -133,7 +131,7 @@ void ExprDict::visit(ExpressionPtr e) {
} else {
// new type assertion seen, record it
int oldId = e->getCanonID();
ASSERT(isCanonicalStructure(oldId));
assert(isCanonicalStructure(oldId));
record(e);
// insert it into the list
if (e->getCanonID() >= m_canonTypeMap.size()) {
@@ -189,8 +187,8 @@ void ExprDict::endBlock(ControlBlock *b) {
if (ExpressionPtr e = m_avlExpr[ix]) {
if (e->isAvailable()) {
int i = e->getKidCount();
ASSERT(((int)e->getCanonID()) == ix);
ASSERT(isCanonicalStructure(ix));
assert(((int)e->getCanonID()) == ix);
assert(isCanonicalStructure(ix));
while (true) {
if (!i--) {
BitOps::set_bit(ix, m_available, true);
@@ -239,7 +237,7 @@ void ExprDict::endBlock(ControlBlock *b) {
}
void ExprDict::setStructureOps(int idx, BitOps::Bits *bits, bool flag) {
ASSERT(isCanonicalStructure(idx));
assert(isCanonicalStructure(idx));
TypePtrIdxPairVec entries;
getAllEntries(idx, entries);
for (TypePtrIdxPairVec::const_iterator it = entries.begin();
@@ -310,7 +308,7 @@ void ExprDict::updateAccess(ExpressionPtr e) {
if (m_am.checkAnyInterf(e, a, isLoad, depth, effects) !=
AliasManager::DisjointAccess) {
int aid = a->getCanonID();
ASSERT(isCanonicalStructure(aid));
assert(isCanonicalStructure(aid));
if (eid != aid || cls == Expression::Load) {
BitOps::set_bit(aid, m_altered, true);
}
@@ -359,7 +357,7 @@ void ExprDict::updateAccess(ExpressionPtr e) {
while (cur) {
ExpressionPtr next = cur->getCanonLVal();
int cid = cur->getCanonID();
ASSERT(isCanonicalStructure(cid));
assert(isCanonicalStructure(cid));
if ((cid != eid || cls == Expression::Load) &&
(BitOps::get_bit(cid, m_altered) ||
m_am.checkAnyInterf(e, cur, isLoad, depth, effects) !=
@@ -380,11 +378,11 @@ void ExprDict::updateAccess(ExpressionPtr e) {
TypePtr ExprDict::reduceToSingleAssertion(const TypePtrIdxPairVec &types)
const {
ASSERT(m_available);
assert(m_available);
TypePtr ret;
for (TypePtrIdxPairVec::const_iterator it = types.begin();
it != types.end(); ++it) {
ASSERT(it->first);
assert(it->first);
if (!BitOps::get_bit(it->second, m_available)) continue;
if (!ret) ret = it->first;
else if (!Type::SameType(ret, it->first)) {
@@ -403,7 +401,7 @@ TypePtr ExprDict::reduceToSingleAssertion(const TypePtrIdxPairVec &types)
void ExprDict::beforePropagate(ControlBlock *b) {
ControlFlowGraph *g = m_am.graph();
assert(g);
always_assert(g);
m_width = size();
m_available = g->rowExists(DataFlow::AvailIn) ?
@@ -413,7 +411,7 @@ void ExprDict::beforePropagate(ControlBlock *b) {
vector<ExpressionRawPtr>(size()).swap(m_avlExpr);
vector<TypePtr>(size()).swap(m_avlTypes);
assert(m_available && m_anticipated);
always_assert(m_available && m_anticipated);
if (b->getDfn()) {
for (size_t i = 1; i < m_width; i++) {
if (!BitOps::get_bit(i, m_available)) continue;
@@ -424,7 +422,7 @@ void ExprDict::beforePropagate(ControlBlock *b) {
AssignmentExpressionPtr ae(
static_pointer_cast<AssignmentExpression>(e));
ExpressionPtr var(ae->getVariable());
ASSERT(isCanonicalStructure(var->getCanonID()));
assert(isCanonicalStructure(var->getCanonID()));
if (BitOps::get_bit(var->getCanonID(), m_anticipated)) {
ExpressionPtr val(ae->getValue());
if (val->isScalar()) {
@@ -67,9 +67,9 @@ private:
inline bool isCanonicalStructure(int i) const { return id(i) == i; }
int id(int i) const {
ASSERT(i >= 0 && i < (int) m_canonIdMap.size());
assert(i >= 0 && i < (int) m_canonIdMap.size());
int ret = m_canonIdMap[i];
ASSERT(ret != -1);
assert(ret != -1);
return ret;
}
+493
Ver Arquivo
@@ -0,0 +1,493 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 <compiler/analysis/file_scope.h>
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/class_scope.h>
#include <compiler/statement/statement_list.h>
#include <compiler/statement/exp_statement.h>
#include <compiler/option.h>
#include <compiler/analysis/constant_table.h>
#include <compiler/analysis/function_scope.h>
#include <sys/stat.h>
#include <compiler/parser/parser.h>
#include <util/logger.h>
#include <util/util.h>
#include <util/base.h>
#include <compiler/expression/expression_list.h>
#include <compiler/statement/function_statement.h>
#include <compiler/analysis/variable_table.h>
#include <compiler/expression/simple_function_call.h>
#include <compiler/expression/include_expression.h>
#include <compiler/expression/user_attribute.h>
#include <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", 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(),
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();
}
+211
Ver Arquivo
@@ -0,0 +1,211 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 __FILE_SCOPE_H__
#define __FILE_SCOPE_H__
#include <compiler/analysis/block_scope.h>
#include <compiler/analysis/function_container.h>
#include <compiler/analysis/code_error.h>
#include <compiler/code_generator.h>
#include <boost/graph/adjacency_list.hpp>
#include <util/json.h>
#include <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
IgnoreRedefinition = 0x4000,// ignore redefinition of builtin function
};
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);
/**
* 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;
FunctionScopePtr createPseudoMain(AnalysisResultConstPtr ar);
void setFileLevel(StatementListPtr stmt);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // __FILE_SCOPE_H__
@@ -0,0 +1,80 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 <compiler/analysis/function_container.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/analysis/class_scope.h>
#include <compiler/analysis/file_scope.h>
#include <compiler/analysis/code_error.h>
#include <compiler/statement/statement_list.h>
#include <compiler/option.h>
#include <util/util.h>
#include <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- 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 __FUNCTION_CONTAINER_H__
#define __FUNCTION_CONTAINER_H__
#include <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 // __FUNCTION_CONTAINER_H__
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
@@ -17,6 +17,7 @@
#ifndef __FUNCTION_SCOPE_H__
#define __FUNCTION_SCOPE_H__
#include <compiler/expression/user_attribute.h>
#include <compiler/analysis/block_scope.h>
#include <compiler/option.h>
@@ -67,6 +68,7 @@ public:
ModifierExpressionPtr modifiers, int attribute,
const std::string &docComment,
FileScopePtr file,
const std::vector<UserAttributePtr> &attrs,
bool inPseudoMain = false);
FunctionScope(FunctionScopePtr orig, AnalysisResultConstPtr ar,
@@ -80,8 +82,9 @@ public:
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 std::string &value,
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;
@@ -102,21 +105,25 @@ public:
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 isClosure() const;
bool isGenerator() const;
bool isGeneratorFromClosure() const;
bool hasGeneratorAsBody() const;
MethodStatementRawPtr getOrigGenStmt() const;
FunctionScopeRawPtr getOrigGenFS() const;
void setNeedsRefTemp() { m_needsRefTemp = true; }
bool needsRefTemp() const { return m_needsRefTemp; }
void setNeedsObjTemp() { m_needsObjTemp = true; }
bool needsObjTemp() const { return m_needsObjTemp; }
void setNeedsCheckMem() { m_needsCheckMem = true; }
bool needsCheckMem() const { return m_needsCheckMem; }
void setClosureGenerator() { m_closureGenerator = true; }
bool isClosureGenerator() const {
ASSERT(!m_closureGenerator || isClosure());
assert(!m_closureGenerator || isClosure());
return m_closureGenerator;
}
bool needsClassParam();
@@ -138,6 +145,9 @@ public:
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.
@@ -166,6 +176,13 @@ public:
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.
*/
@@ -200,6 +217,19 @@ public:
*/
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 and can be redefined
*/
bool ignoreRedefinition() const;
void setIgnoreRedefinition();
/**
* Whether this function is a runtime helper function
*/
@@ -214,9 +244,10 @@ public:
* Whether this function contains a usage of $this
*/
bool containsThis() const { return m_containsThis;}
void setContainsThis(bool f=true) { m_containsThis = f;}
void setContainsThis(bool f = true);
bool containsBareThis() const { return m_containsBareThis; }
void setContainsBareThis(bool f=true) { m_containsBareThis = f; }
bool containsRefThis() const { return m_containsBareThis & 2; }
void setContainsBareThis(bool f, bool ref = false);
/**
* How many parameters a caller should provide.
*/
@@ -240,7 +271,6 @@ public:
void fixRetExprs();
bool needsTypeCheckWrapper() const;
const char *getPrefix(ExpressionListPtr params);
void setOptFunction(FunctionOptPtr fn) { m_optFunction = fn; }
FunctionOptPtr getOptFunction() const { return m_optFunction; }
@@ -275,8 +305,10 @@ public:
bool isLocalRedeclaring() const { return m_localRedeclaring; }
/* For function_exists */
void setVolatile() { m_volatile = true;}
bool isVolatile() const { return m_volatile;}
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; }
@@ -290,6 +322,10 @@ public:
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.
@@ -307,101 +343,22 @@ public:
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);
/**
* Override to preface with call temps.
*/
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* Generate parameter declaration.
*/
void outputCPPParamsDecl(CodeGenerator &cg, AnalysisResultPtr ar,
ExpressionListPtr params, bool showDefault);
/**
* This one is a special version that doesn't require a params expression.
* It's for use with extension functions. It only works for the
* implementation since it ignores optional arguments.
*/
void outputCPPParamsImpl(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* If inside this function, we have to make a call to an implementation
* function that has the same signature, how does the parameter list
* look like?
*/
void outputCPPParamsCall(CodeGenerator &cg, AnalysisResultPtr ar,
bool aggregateParams);
/**
* How does a caller prepare parameters.
*/
static void OutputCPPArguments(ExpressionListPtr params,
FunctionScopePtr func,
CodeGenerator &cg, AnalysisResultPtr ar,
int extraArg, bool variableArgument,
int extraArgArrayId = -1,
int extraArgArrayHash = -1,
int extraArgArrayIndex = -1,
bool ignoreFuncParamTypes = false);
/**
* Only generate arguments that have effects. This is for keeping those
* parameters around when generating a error-raising function call, so to
* avoid "unused" variable compiler warnings.
*/
static void OutputCPPEffectiveArguments(ExpressionListPtr params,
CodeGenerator &cg,
AnalysisResultPtr ar);
/**
* Generate invoke proxy.
*/
static void OutputCPPDynamicInvokeCount(CodeGenerator &cg);
void outputCPPDynamicInvoke(CodeGenerator &cg, AnalysisResultPtr ar,
const char *funcPrefix,
const char *name,
bool voidWrapperOff = false,
bool fewArgs = false,
bool ret = true,
const char *extraArg = NULL,
bool constructor = false,
const char *instance = NULL,
const char *class_name = "");
/**
* ...so ClassStatement can call them for classes that don't have
* constructors defined
*/
void outputCPPCreateDecl(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPCreateImpl(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* output functions
*/
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar);
void outputMethodWrapper(CodeGenerator &cg, AnalysisResultPtr ar,
const char *clsToConstruct);
/**
* Output CallInfo instance for this function.
*/
void outputCPPCallInfo(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPPreface(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPHelperClassAlloc(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() {
bool inPseudoMain() const {
return m_pseudoMain;
}
@@ -475,14 +432,6 @@ public:
};
private:
bool outputCPPArrayCreate(CodeGenerator &cg,
AnalysisResultPtr ar,
int m_maxParam);
void outputCPPSubClassParam(CodeGenerator &cg,
AnalysisResultPtr ar,
ParameterExpressionPtr param);
void init(AnalysisResultConstPtr ar);
static StringToFunctionInfoPtrMap s_refParamInfo;
@@ -493,12 +442,13 @@ private:
std::vector<std::string> m_paramNames;
TypePtrVec m_paramTypes;
TypePtrVec m_paramTypeSpecs;
std::vector<std::string> m_paramDefaults;
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;
@@ -510,19 +460,22 @@ private:
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 : 1; // $this outside object-context
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_needsRefTemp : 1;
unsigned m_needsObjTemp : 1;
unsigned m_needsCheckMem : 1;
unsigned m_closureGenerator : 1;
unsigned m_noLSB : 1;
@@ -535,12 +488,12 @@ private:
StatementPtr m_stmtCloned; // cloned method body stmt
int m_inlineIndex;
FunctionOptPtr m_optFunction;
int outputCPPInvokeArgCountCheck(CodeGenerator &cg, AnalysisResultPtr ar,
bool ret, bool constructor, int maxCount);
ExpressionPtrVec m_retExprsToFix;
ExpressionListPtr m_closureVars;
ExpressionListPtr m_closureValues;
ReadWriteMutex m_inlineMutex;
unsigned m_nextID; // used when cloning generators for traits
std::list<FunctionScopeRawPtr> m_clonedTraitOuterScope;
};
///////////////////////////////////////////////////////////////////////////////
@@ -30,7 +30,6 @@
#include <compiler/statement/statement_list.h>
using namespace HPHP;
using namespace boost;
using std::vector;
///////////////////////////////////////////////////////////////////////////////
@@ -94,7 +93,7 @@ void LiveDict::updateParams() {
BitOps::set(width, dieout, 0);
for (int i = size(); i--; ) {
if (ExpressionPtr e = get(i)) {
assert(e->is(Expression::KindOfSimpleVariable));
always_assert(e->is(Expression::KindOfSimpleVariable));
Symbol *sym = static_pointer_cast<SimpleVariable>(e)->getSymbol();
if (sym) {
if (sym->isParameter() || sym->isClosureVar() || e->isThis()) {
@@ -122,7 +121,7 @@ void LiveDict::beginBlock(ControlBlock *b) {
m_refs.reset();
for (int i = size(); i--; ) {
if (ExpressionPtr e = get(i)) {
assert(e->is(Expression::KindOfSimpleVariable));
always_assert(e->is(Expression::KindOfSimpleVariable));
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
if (m_am.hasWildRefs() || sv->couldBeAliased()) {
sv->setCanonPtr(m_refs);
@@ -353,7 +352,7 @@ struct Colorizer {
if (ix) {
std::pair<std::set<int>::iterator, bool> ret =
ni.conflicts.insert(ix-1);
assert(ret.second);
always_assert(ret.second);
ni.size++;
}
}
@@ -406,7 +405,7 @@ struct Colorizer {
NodeInfo &node = nodes[sorted[i]];
int bucket = node.size;
for (int j = 0; j <= bucket; j++) {
assert(buckets[j] == i);
always_assert(buckets[j] == i);
buckets[j]++;
}
for (std::set<int>::iterator it = node.conflicts.begin(),
@@ -417,7 +416,7 @@ struct Colorizer {
NodeInfo &n = nodes[ix];
int &bi = buckets[n.size];
if (si != bi) {
assert(si > bi);
always_assert(si > bi);
sorted[si] = sorted[bi];
sorted[bi] = ix;
isorted[sorted[si]] = si;
@@ -442,7 +441,7 @@ struct Colorizer {
int j = 0;
while (BitOps::get_bit(j, tmp)) {
j++;
assert(j < size);
always_assert(j < size);
}
n.color = j;
}
@@ -462,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()) {
@@ -597,7 +582,7 @@ public:
}
break;
}
assert(sz >= 0);
always_assert(sz >= 0);
}
void execute() {
@@ -608,25 +593,24 @@ public:
if (!re.second) break;
const AstWalkerState &s = re.first[re.first.size() - 1];
StatementPtr sp(dynamic_pointer_cast<Statement>(s.cp));
assert(sp);
always_assert(sp);
StatementListPtr sl;
int ix;
if (sp->is(Statement::KindOfStatementList)) {
sl = static_pointer_cast<StatementList>(sp);
ix = (s.index - 1) / 2;
} else {
assert(sp->is(Statement::KindOfBlockStatement));
always_assert(sp->is(Statement::KindOfBlockStatement));
sl = static_pointer_cast<BlockStatement>(sp)->getStmts();
if (!sl) continue;
ix = 0;
}
ExpressionPtr e = m_dict.get(re.second);
assert(e && e->is(Expression::KindOfSimpleVariable));
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;
}
+183
Ver Arquivo
@@ -0,0 +1,183 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 "compiler/analysis/peephole.h"
#include "compiler/analysis/emitter.h"
namespace HPHP { namespace Compiler {
using VM::FuncEmitter;
using VM::UnitEmitter;
using VM::Offset;
static void collapseJmp(Offset* offsetPtr, Opcode* instr, Opcode* start) {
if (offsetPtr) {
Opcode* dest = instr + *offsetPtr;
while (*dest == OpJmp && dest != instr) {
dest = start + instrJumpTarget(start, dest - start);
}
*offsetPtr = dest - instr;
}
}
Peephole::Peephole(UnitEmitter &ue, MetaInfoBuilder& metaInfo)
: m_ue(ue) {
// be careful about an empty input
if (ue.m_bclen == 0) {
return;
}
// We need to know which instructions may be jumped to, since this blocks
// certain optimizations
buildJumpTargets();
// Scan the bytecode linearly.
Opcode* start = ue.m_bc;
Opcode* prev = start;
Opcode* cur = prev + instrLen(prev);
Opcode* end = start + ue.m_bclen;
/*
* TODO(1086005): we should try to minimize use of CGetL2/CGetL3.
* (When they appear in an order like "CGetL; CGetL2" we can just
* switch them to "CGetL; CGetL".)
*/
while (cur < end) {
if (LIKELY(!m_jumpTargets.count(cur - start))) {
// prev and cur are always dynamically adjacent (i.e. whenever cur is
// executed, prev was always the previous instruction), so we can optimize
// them based on this assumption.
// Not, JmpZ -> Nop, JmpNZ (and vice versa)
// We replace the Not with a Nop, instead of shifting up the rest of the
// bytecode. Shifting has a lot of costs: copying bytecode around, and
// remapping jump targets and line numbers. This optimization is rare
// enough that the space savings are not worthwhile.
if (*prev == OpNot) {
if (*cur == OpJmpZ) {
*prev = OpNop;
*cur = OpJmpNZ;
} else if (*cur == OpJmpNZ) {
*prev = OpNop;
*cur = OpJmpZ;
}
metaInfo.deleteInfo(prev - start);
}
// IncDec* Post*, PopC -> IncDec* Pre*, PopC
ArgUnion* imm = 0;
if (*cur == OpPopC) {
switch (*prev) {
case OpIncDecL:
imm = getImmPtr(prev, 1);
goto incDecOp;
case OpIncDecN:
case OpIncDecG:
case OpIncDecS:
case OpIncDecM:
imm = getImmPtr(prev, 0);
// fallthrough
incDecOp:
if (imm->u_OA == PostInc) {
imm->u_OA = PreInc;
} else if (imm->u_OA == PostDec) {
imm->u_OA = PreDec;
}
break;
default:
break;
}
}
}
// Simplify jumps. Follow a jump's target until it lands on something that
// isn't an unconditional jump. Then rewrite the offset to cut out any
// intermediate jumps.
if (isSwitch(*prev)) {
foreachSwitchTarget(prev, [&](Offset& o) {
collapseJmp(&o, prev, start);
});
} else {
collapseJmp(instrJumpOffset(prev), prev, start);
}
prev = cur;
cur = cur + instrLen(cur);
}
}
void Peephole::buildFuncTargets(FuncEmitter* fe) {
m_jumpTargets.insert(fe->base());
for (FuncEmitter::EHEntVec::const_iterator it = fe->ehtab().begin();
it != fe->ehtab().end(); ++it) {
m_jumpTargets.insert(it->m_base);
m_jumpTargets.insert(it->m_past);
for (EHEnt::CatchVec::const_iterator catchIt = it->m_catches.begin();
catchIt != it->m_catches.end(); ++catchIt) {
m_jumpTargets.insert(catchIt->second);
}
m_jumpTargets.insert(it->m_fault);
}
for (uint i = 0; i < fe->params().size(); i++) {
const FuncEmitter::ParamInfo& pi = fe->params()[i];
if (pi.hasDefaultValue()) {
m_jumpTargets.insert(pi.funcletOff());
}
}
for (FuncEmitter::FPIEntVec::const_iterator it = fe->fpitab().begin();
it != fe->fpitab().end(); ++it) {
m_jumpTargets.insert(it->m_fpushOff);
m_jumpTargets.insert(it->m_fcallOff);
}
}
void Peephole::buildJumpTargets() {
// all function start locations, exception handlers, default value funclets,
// and FPI regions are targets
for (UnitEmitter::FeVec::const_iterator it = m_ue.m_fes.begin();
it != m_ue.m_fes.end(); ++it) {
FuncEmitter *fe = *it;
buildFuncTargets(fe);
}
for (UnitEmitter::PceVec::const_iterator it = m_ue.m_pceVec.begin();
it != m_ue.m_pceVec.end(); ++it) {
for (PreClassEmitter::MethodVec::const_iterator mit =
(*it)->methods().begin(); mit != (*it)->methods().end(); ++mit) {
FuncEmitter* fe = *mit;
buildFuncTargets(fe);
}
}
// 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];
if (isSwitch(*instr)) {
foreachSwitchTarget(instr, [&](Offset& o) {
m_jumpTargets.insert(pos + o);
});
} else {
Offset target = instrJumpTarget(m_ue.m_bc, pos);
if (target != InvalidAbsoluteOffset) {
m_jumpTargets.insert(target);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
}}
+58
Ver Arquivo
@@ -0,0 +1,58 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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. |
+----------------------------------------------------------------------+
*/
/* The Peephole Optimizer
* ======================
*
* The peephole optimizer performs some postprocessing on bytecode. Currently we
* perform the following optimizations:
*
* - Jump rewriting: if we jump to a jump, we rewrite the original jump to just
* directly jump to the final destination. We can handle long chains of jumps
* and are careful about infinite loops and conditional jumps.
* - PostInc/PostDec to PreInc/PreDec conversion: PostInc and PostDec are
* necessarily slower than PreInc and PreDec, so when possible we convert
* PostInc/PostDec to PreInc/PreDec.
* - Conditional jump conversion: if a JmpZ uses an item from the stack which
* was placed there by a Not, we remove the Not and replace the JmpZ with
* JmpNZ. We likewise convert Not + JmpNZ to JmpZ.
*/
#ifndef incl_HPHP_COMPILER_ANALYSIS_PEEPHOLE_H_
#define incl_HPHP_COMPILER_ANALYSIS_PEEPHOLE_H_
#include "runtime/vm/unit.h"
#include "runtime/vm/func.h"
namespace HPHP { namespace Compiler {
class MetaInfoBuilder;
class Peephole {
public:
Peephole(VM::UnitEmitter& ue, MetaInfoBuilder& metaInfo);
private:
void buildFuncTargets(VM::FuncEmitter* fe);
void buildJumpTargets();
VM::UnitEmitter& m_ue;
hphp_hash_set<VM::Offset> m_jumpTargets;
};
}}
#endif
@@ -32,7 +32,6 @@
#include <util/parser/hphp.tab.hpp>
using namespace HPHP;
using namespace boost;
using std::vector;
///////////////////////////////////////////////////////////////////////////////
@@ -94,7 +93,7 @@ void RefDict::beginBlock(ControlBlock *b) {
m_obj = b->getRow(DataFlow::Object);
m_noobj = b->getRow(DataFlow::NotObject);
assert(
always_assert(
m_am.graph()->rowExists(DataFlow::Referenced) &&
m_am.graph()->rowExists(DataFlow::Killed) &&
m_am.graph()->rowExists(DataFlow::PRefIn) &&
@@ -122,8 +121,8 @@ void RefDict::updateParams() {
for (int i = size(); i--; ) {
if (ExpressionPtr e = get(i)) {
assert(e->is(Expression::KindOfSimpleVariable));
assert(((unsigned int)i) == e->getCanonID());
always_assert(e->is(Expression::KindOfSimpleVariable));
always_assert(((unsigned int)i) == e->getCanonID());
Symbol *sym = static_pointer_cast<SimpleVariable>(e)->getSymbol();
if (sym && (sym->isParameter() || sym->isClosureVar())) {
TypePtr paramType;
@@ -135,7 +134,7 @@ void RefDict::updateParams() {
paramType = paramExprPtr->getType();
isRef = m_method_stmt->isRef(sym->getParameterIndex());
} else {
ASSERT(sym->isClosureVar());
assert(sym->isClosureVar());
// can only assume it is a Variant for now
paramType = Type::Variant;
isRef = sym->isRefClosureVar();
@@ -160,7 +159,7 @@ void RefDict::updateParams() {
}
void RefDict::updateAccess(ExpressionPtr e) {
assert(!e->getScope()->inPseudoMain());
always_assert(!e->getScope()->inPseudoMain());
int eid = e->getCanonID();
int context = e->getContext();
@@ -340,7 +339,7 @@ void RefDict::updateAccess(ExpressionPtr e) {
if (context & Expression::LValue &&
context & Expression::UnsetContext) {
assert(!isRefd);
always_assert(!isRefd);
// unset($x);
BitOps::set_bit(eid, m_obj, false);
BitOps::set_bit(eid, m_noobj, true);
@@ -361,8 +360,8 @@ void RefDict::updateAccess(ExpressionPtr e) {
// containing an object (in the bit vector)
for (int i = size(); i--; ) {
if (ExpressionPtr e = get(i)) {
assert(e->is(Expression::KindOfSimpleVariable));
assert(((unsigned int)i) == e->getCanonID());
always_assert(e->is(Expression::KindOfSimpleVariable));
always_assert(((unsigned int)i) == e->getCanonID());
if (BitOps::get_bit(i, m_referenced)) {
BitOps::set_bit(i, m_obj, true);
BitOps::set_bit(i, m_noobj, false);
@@ -381,13 +380,13 @@ int RefDictWalker::after(ConstructRawPtr cp) {
s->setReferenced();
}
s->setReferencedValid();
assert(s->isReferencedValid());
always_assert(s->isReferencedValid());
} else {
if (s->isAvailable() && m_block->getBit(DataFlow::PObjIn, id)) {
s->setNeeded();
}
s->setNeededValid();
assert(s->isNeededValid());
always_assert(s->isNeededValid());
}
}
}
@@ -32,15 +32,15 @@
#include <util/logger.h>
using namespace std;
using namespace HPHP;
using namespace boost;
///////////////////////////////////////////////////////////////////////////////
// Symbol
TypePtr Symbol::getFinalType() const {
if (m_coerced &&
!m_coerced->is(Type::KindOfSome) && !m_coerced->is(Type::KindOfAny)) {
!m_coerced->is(Type::KindOfSome) &&
!m_coerced->is(Type::KindOfAny) &&
!m_coerced->is(Type::KindOfVoid)) {
return m_coerced;
}
return Type::Variant;
@@ -81,7 +81,7 @@ TypePtr Symbol::setType(AnalysisResultConstPtr ar, BlockScopeRawPtr scope,
if (!coerced) return oldType;
type = CoerceTo(ar, m_coerced, type);
ASSERT(!isRefClosureVar() || (type && type->is(Type::KindOfVariant)));
assert(!isRefClosureVar() || (type && type->is(Type::KindOfVariant)));
if (ar->getPhase() >= AnalysisResult::AnalyzeAll &&
!Type::SameType(oldType, type)) {
@@ -96,7 +96,7 @@ void Symbol::beginLocal(BlockScopeRawPtr scope) {
if (isClosureVar()) {
ExpressionListPtr useVars =
scope->getContainingFunction()->getClosureVars();
ASSERT(useVars);
assert(useVars);
// linear scan for now, since most use var lists are
// fairly short
bool found = false;
@@ -110,8 +110,8 @@ void Symbol::beginLocal(BlockScopeRawPtr scope) {
break;
}
}
if (!found) ASSERT(false);
ASSERT(!isRefClosureVar() ||
if (!found) assert(false);
assert(!isRefClosureVar() ||
(m_coerced && m_coerced->is(Type::KindOfVariant)));
} else {
m_coerced.reset();
@@ -168,28 +168,28 @@ void Symbol::triggerUpdates(BlockScopeRawPtr scope) const {
/**
* Constants can only belong to a file or class scope
*/
ASSERT(scope->is(BlockScope::FileScope) ||
assert(scope->is(BlockScope::FileScope) ||
scope->is(BlockScope::ClassScope));
/**
* Constants can only be declared in a function or
* class scope
*/
ASSERT(declScope->is(BlockScope::FunctionScope) ||
assert(declScope->is(BlockScope::FunctionScope) ||
declScope->is(BlockScope::ClassScope));
/**
* For class scopes, the declaration scope *must*
* match the scope the symbol lives in
*/
ASSERT(!scope->is(BlockScope::ClassScope) ||
assert(!scope->is(BlockScope::ClassScope) ||
scope == declScope);
/**
* For file scopes, the declaration scope *must*
* live in a function scope
*/
ASSERT(!scope->is(BlockScope::FileScope) ||
assert(!scope->is(BlockScope::FileScope) ||
declScope->is(BlockScope::FunctionScope));
/**
@@ -237,7 +237,7 @@ void Symbol::import(BlockScopeRawPtr scope, const Symbol &src_sym) {
bool Symbol::checkDefined() {
if (isSystem()) return true;
assert(m_flags.m_declaration_set);
always_assert(m_flags.m_declaration_set);
if (!m_declaration) return false;
if (!m_declaration.unique()) return true;
if (!m_flags.m_replaced) {
@@ -270,7 +270,7 @@ std::string ExtractInitializer(AnalysisResultPtr ar, ExpressionPtr e) {
}
void Symbol::serializeParam(JSON::DocTarget::OutputStream &out) const {
ASSERT(isParameter());
assert(isParameter());
JSON::DocTarget::MapStream ms(out);
ms.add("name", m_name);
@@ -281,7 +281,7 @@ void Symbol::serializeParam(JSON::DocTarget::OutputStream &out) const {
if (m_value) {
ExpressionPtr valueExp(
dynamic_pointer_cast<Expression>(m_value));
ASSERT(valueExp);
assert(valueExp);
const string &init = ExtractInitializer(out.analysisResult(), valueExp);
if (!init.empty()) out << init;
else out << JSON::Null;
@@ -315,7 +315,7 @@ static inline std::string ExtractDocComment(ExpressionPtr e) {
}
void Symbol::serializeClassVar(JSON::DocTarget::OutputStream &out) const {
ASSERT(!isParameter());
assert(!isParameter());
JSON::DocTarget::MapStream ms(out);
ms.add("name", m_name);
@@ -334,7 +334,7 @@ void Symbol::serializeClassVar(JSON::DocTarget::OutputStream &out) const {
if (m_initVal) {
ExpressionPtr initExp(
dynamic_pointer_cast<Expression>(m_initVal));
ASSERT(initExp);
assert(initExp);
const string &init = ExtractInitializer(out.analysisResult(), initExp);
if (!init.empty()) out << init;
else out << JSON::Null;
@@ -363,6 +363,11 @@ void SymbolTable::CountTypes(std::map<std::string, int> &counts) {
}
}
void SymbolTable::Purge() {
Lock lock(AllSymbolTablesMutex);
AllSymbolTables.clear();
}
///////////////////////////////////////////////////////////////////////////////
SymbolTable::SymbolTable(BlockScope &blockScope, bool isConst) :
@@ -373,7 +378,7 @@ SymbolTable::~SymbolTable() {
}
void SymbolTable::import(SymbolTablePtr src) {
ASSERT(m_symbolMap.empty());
assert(m_symbolMap.empty());
for (unsigned int i = 0; i < src->m_symbolVec.size(); i++) {
Symbol &src_sym = *src->m_symbolVec[i];
@@ -447,7 +452,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) {
@@ -461,7 +466,7 @@ const Symbol *SymbolTable::getSymbol(const std::string &name) const {
Symbol *SymbolTable::genSymbol(const std::string &name, bool konst) {
std::map<std::string,Symbol>::iterator it = m_symbolMap.find(name);
if (it != m_symbolMap.end()) {
ASSERT(konst == it->second.isConstant());
assert(konst == it->second.isConstant());
return &it->second;
}
@@ -471,6 +476,16 @@ Symbol *SymbolTable::genSymbol(const std::string &name, bool konst) {
return sym;
}
Symbol *SymbolTable::genSymbol(const std::string &name, bool konst,
ConstructPtr construct) {
Symbol *sym = genSymbol(name, konst);
if (!sym->declarationSet() && construct) {
m_symbolVec.push_back(sym);
sym->setDeclaration(construct);
}
return sym;
}
TypePtr SymbolTable::getType(const std::string &name) const {
if (const Symbol *sym = getSymbol(name)) {
return sym->getType();
@@ -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,6 +233,10 @@ 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;
@@ -245,7 +255,7 @@ private:
class SymParamWrapper : public JSON::DocTarget::ISerializable {
public:
SymParamWrapper(const Symbol* sym) : m_sym(sym) {
ASSERT(sym);
assert(sym);
}
virtual void serialize(JSON::DocTarget::OutputStream &out) const {
m_sym->serializeParam(out);
@@ -257,7 +267,7 @@ private:
class SymClassVarWrapper : public JSON::DocTarget::ISerializable {
public:
SymClassVarWrapper(const Symbol* sym) : m_sym(sym) {
ASSERT(sym);
assert(sym);
}
virtual void serialize(JSON::DocTarget::OutputStream &out) const {
m_sym->serializeClassVar(out);
@@ -274,6 +284,7 @@ class SymbolTable : public boost::enable_shared_from_this<SymbolTable>,
public:
static Mutex AllSymbolTablesMutex;
static SymbolTablePtrList AllSymbolTables; // for stats purpose
static void Purge();
static void CountTypes(std::map<std::string, int> &counts);
BlockScope *getScopePtr() const { return &m_blockScope; }
BlockScopeRawPtr getBlockScope() const {
@@ -364,6 +375,8 @@ public:
static std::string getEscapedText(Variant v, int &len);
protected:
Symbol *genSymbol(const std::string &name, bool konst);
Symbol *genSymbol(const std::string &name, bool konst,
ConstructPtr construct);
typedef std::map<std::string,Symbol> StringToSymbolMap;
BlockScope &m_blockScope; // owner
+785
Ver Arquivo
@@ -0,0 +1,785 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 <compiler/analysis/type.h>
#include <compiler/code_generator.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/class_scope.h>
#include <compiler/analysis/file_scope.h>
#include <compiler/expression/expression.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;
void Type::InitTypeHintMap() {
assert(s_TypeHintTypes.empty());
s_TypeHintTypes["array"] = Type::Array;
if (Option::EnableHipHopSyntax) {
s_TypeHintTypes["bool"] = Type::Boolean;
s_TypeHintTypes["boolean"] = Type::Boolean;
s_TypeHintTypes["int"] = Type::Int64;
s_TypeHintTypes["integer"] = Type::Int64;
s_TypeHintTypes["real"] = Type::Double;
s_TypeHintTypes["double"] = Type::Double;
s_TypeHintTypes["float"] = Type::Double;
s_TypeHintTypes["string"] = Type::String;
}
}
const Type::TypePtrMap &Type::GetTypeHintTypes() {
return s_TypeHintTypes;
}
void Type::ResetTypeHintTypes() {
s_TypeHintTypes.clear();
}
TypePtr Type::CreateObjectType(const std::string &classname) {
return TypePtr(new Type(KindOfObject, classname));
}
TypePtr Type::GetType(KindOf kindOf,
const std::string &clsname /* = "" */) {
assert(kindOf);
if (!clsname.empty()) 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();
}
@@ -22,9 +22,9 @@
#include <util/case_insensitive.h>
#include <runtime/base/types.h>
#define NEW_TYPE(s) TypePtr(new Type(Type::KindOf ## s))
class TestCodeRun;
class TestCodeError;
struct ProgramOptions;
int process(const ProgramOptions&);
@@ -40,8 +40,8 @@ DECLARE_BOOST_TYPES(ClassScope);
class Type : public JSON::CodeError::ISerializable,
public JSON::DocTarget::ISerializable {
friend int ::process(const ProgramOptions&);
friend class ::TestCodeRun;
friend class ::TestCodeError;
public:
typedef int KindOf;
@@ -80,9 +80,8 @@ public:
/**
* Inferred types: types that a variable or a constant is sure to be.
*/
static TypePtr Null;
static TypePtr Boolean;
static TypePtr Byte;
static TypePtr Int16;
static TypePtr Int32;
static TypePtr Int64;
static TypePtr Double;
@@ -175,6 +174,12 @@ public:
*/
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.
*/
@@ -210,7 +215,8 @@ public:
bool isSpecificObject() const;
bool isNonConvertibleType() const; // other types cannot convert to them
bool isPrimitive() const {
return IsExactType(m_kindOf) && (m_kindOf <= KindOfDouble);
return IsExactType(m_kindOf) && (m_kindOf <= KindOfDouble) &&
(m_kindOf != KindOfVoid);
}
bool isNoObjectInvolved() const;
const std::string &getName() const { return m_name;}
@@ -219,32 +225,8 @@ public:
ClassScopePtr getClass(AnalysisResultConstPtr ar,
BlockScopeRawPtr scope) const;
/**
* Generate type specifier in C++.
*/
std::string getCPPDecl(AnalysisResultConstPtr ar,
BlockScopeRawPtr scope);
DataType getDataType() const;
void outputCPPDecl(CodeGenerator &cg, AnalysisResultConstPtr ar,
BlockScopeRawPtr scope);
/**
* Generate type conversion in C++.
*/
void outputCPPFastObjectCast(CodeGenerator &cg,
AnalysisResultConstPtr ar,
BlockScopeRawPtr scope,
bool isConst);
void outputCPPCast(CodeGenerator &cg, AnalysisResultConstPtr ar,
BlockScopeRawPtr scope);
/**
* Generate variable initialization code.
*/
const char *getCPPInitializer();
DataType getHhvmDataType() const;
/**
* Type hint names in PHP.
@@ -273,11 +255,11 @@ public:
*/
void count(std::map<std::string, int> &counts);
private:
/**
* Must not be invoked concurrently
*/
static void InitTypeHintMap();
private:
/**
* Must not be invoked concurrently
+781
Ver Arquivo
@@ -0,0 +1,781 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 <compiler/analysis/variable_table.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/file_scope.h>
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/type.h>
#include <compiler/code_generator.h>
#include <compiler/expression/modifier_expression.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/expression/simple_variable.h>
#include <compiler/builtin_symbols.h>
#include <compiler/option.h>
#include <compiler/expression/simple_function_call.h>
#include <compiler/analysis/class_scope.h>
#include <compiler/expression/static_member_expression.h>
#include <runtime/base/class_info.h>
#include <util/util.h>
#include <util/parser/location.h>
#include <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->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();
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();
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- 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 __VARIABLE_TABLE_H__
#define __VARIABLE_TABLE_H__
#include <compiler/analysis/symbol_table.h>
#include <compiler/statement/statement.h>
#include <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:
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 // __VARIABLE_TABLE_H__
@@ -28,13 +28,13 @@
#include <compiler/analysis/constant_table.h>
#include <util/parser/hphp.tab.hpp>
#include <runtime/base/class_info.h>
#include <runtime/base/program_functions.h>
#include <runtime/base/array/array_iterator.h>
#include <util/logger.h>
#include <util/util.h>
#include <dlfcn.h>
using namespace HPHP;
using namespace std;
using namespace boost;
#define BF_COLUMN_COUNT 3
#define BF_COLUMN_NAME 0
@@ -60,38 +60,40 @@ const char *BuiltinSymbols::ExtensionFunctions[] = {
#define T(t) (const char *)Type::KindOf ## t
#define EXT_TYPE 0
#include <system/ext.inc>
NULL,
nullptr,
};
#undef EXT_TYPE
const char *BuiltinSymbols::ExtensionConsts[] = {
#define EXT_TYPE 1
#include <system/ext.inc>
NULL,
nullptr,
};
#undef EXT_TYPE
const char *BuiltinSymbols::ExtensionClasses[] = {
#define EXT_TYPE 2
#include <system/ext.inc>
NULL,
nullptr,
};
#undef EXT_TYPE
const char *BuiltinSymbols::ExtensionDeclaredDynamic[] = {
#define EXT_TYPE 3
#include <system/ext.inc>
NULL,
};
#undef EXT_TYPE
const char *BuiltinSymbols::HelperFunctions[] = {
#include <system/helper.inc>
NULL,
};
StringToFunctionScopePtrMap BuiltinSymbols::s_functions;
StringToFunctionScopePtrMap BuiltinSymbols::s_helperFunctions;
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",
@@ -107,18 +109,22 @@ const char *BuiltinSymbols::SystemClasses[] = {
"directoryiterator",
"soapfault",
"fbmysqllexer",
NULL
nullptr
};
StringToClassScopePtrMap BuiltinSymbols::s_classes;
VariableTablePtr BuiltinSymbols::s_variables;
ConstantTablePtr BuiltinSymbols::s_constants;
StringToTypePtrMap BuiltinSymbols::s_superGlobals;
std::set<std::string> BuiltinSymbols::s_declaredDynamic;
void *BuiltinSymbols::s_handle_main = NULL;
void *BuiltinSymbols::s_handle_main = nullptr;
///////////////////////////////////////////////////////////////////////////////
int BuiltinSymbols::NumGlobalNames() {
return sizeof(BuiltinSymbols::GlobalNames) /
sizeof(BuiltinSymbols::GlobalNames[0]);
}
void BuiltinSymbols::ParseExtFunctions(AnalysisResultPtr ar, const char **p,
bool sep) {
while (*p) {
@@ -126,7 +132,7 @@ void BuiltinSymbols::ParseExtFunctions(AnalysisResultPtr ar, const char **p,
if (sep) {
f->setSepExtension();
}
ASSERT(!s_functions[f->getName()]);
assert(!s_functions[f->getName()]);
s_functions[f->getName()] = f;
}
}
@@ -144,7 +150,7 @@ void BuiltinSymbols::ParseExtConsts(AnalysisResultPtr ar, const char **p,
}
TypePtr BuiltinSymbols::ParseType(const char **&p) {
const char *clsname = NULL;
const char *clsname = nullptr;
Type::KindOf ktype = (Type::KindOf)(long)(*p++);
if (ktype == CLASS_TYPE) {
clsname = *p++;
@@ -177,7 +183,7 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
if (sep) {
fs->setSepExtension();
}
int flags = (int)(int64)(*p++);
int flags = (int)(int64_t)(*p++);
if (flags & ClassInfo::IsAbstract) {
fs->addModifier(T_ABSTRACT);
}
@@ -203,7 +209,7 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
p++;
// Parse properties
while (*p) {
int flags = (int)(int64)(*p++);
int flags = (int)(int64_t)(*p++);
ModifierExpressionPtr modifiers(
new ModifierExpression(BlockScopePtr(), LocationPtr()));
if (flags & ClassInfo::IsProtected) {
@@ -227,7 +233,7 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
}
p++;
int flags = (int)(int64)(*p++);
int flags = (int)(int64_t)(*p++);
cl->setClassInfoAttribute(flags);
if (flags & ClassInfo::HasDocComment) {
cl->setDocComment(*p++);
@@ -241,14 +247,6 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
}
}
void BuiltinSymbols::ParseExtDynamics(AnalysisResultPtr ar, const char **p,
bool sep) {
while (*p) {
s_declaredDynamic.insert(Util::toLower(string(*p)));
p++;
}
}
FunctionScopePtr BuiltinSymbols::ParseExtFunction(AnalysisResultPtr ar,
const char** &p, bool method /* = false */) {
const char *name = *p++;
@@ -262,6 +260,7 @@ FunctionScopePtr BuiltinSymbols::ParseExtFunction(AnalysisResultPtr ar,
/* name */ arg++;
ParseType(arg);
const char *argDefault = *arg++;
/* const char *argDefaultLen = */ arg++;
/* const char *argDefaultText = */ arg++;
/* bool argReference = */ arg++;
if (argDefault && minParam < 0) {
@@ -278,22 +277,25 @@ FunctionScopePtr BuiltinSymbols::ParseExtFunction(AnalysisResultPtr ar,
}
int index = 0;
const char *paramName = NULL;
const char *paramName = nullptr;
while ((paramName = *p++ /* argName */)) {
TypePtr argType = ParseType(p);
const char *argDefault = *p++;
const char *argDefaultLen = *p++;
const char *argDefaultText = *p++;
bool argReference = *p++;
f->setParamName(index, paramName);
if (argReference) f->setRefParam(index);
f->setParamType(ar, index, argType);
if (argDefault) f->setParamDefault(index, argDefault, argDefaultText);
if (argDefault) f->setParamDefault(index, argDefault,
(int64_t)argDefaultLen,
argDefaultText);
index++;
}
int flags = (int)(int64)(*p++);
int flags = (int)(int64_t)(*p++);
f->setClassInfoAttribute(flags);
if (flags & ClassInfo::HasDocComment) {
f->setDocComment(*p++);
@@ -319,6 +321,12 @@ FunctionScopePtr BuiltinSymbols::ParseExtFunction(AnalysisResultPtr ar,
if (flags & ClassInfo::ContextSensitive) {
f->setContextSensitive(true);
}
if (flags & ClassInfo::NeedsActRec) {
f->setNeedsActRec();
}
if ((flags & ClassInfo::IgnoreRedefinition) && !method) {
f->setIgnoreRedefinition();
}
return f;
}
@@ -334,11 +342,11 @@ bool BuiltinSymbols::LoadSepExtensionSymbols(AnalysisResultPtr ar,
const std::string &soname) {
string mapname = name + "_map";
const char ***symbols = NULL;
const char ***symbols = nullptr;
// If we linked with .a, the symbol is already in main program.
if (s_handle_main == NULL) {
s_handle_main = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);
if (s_handle_main == nullptr) {
s_handle_main = dlopen(nullptr, RTLD_NOW | RTLD_GLOBAL);
if (!s_handle_main) {
const char *error = dlerror();
Logger::Error("Unable to load main program's symbols: %s",
@@ -350,7 +358,7 @@ bool BuiltinSymbols::LoadSepExtensionSymbols(AnalysisResultPtr ar,
}
// Otherwise, look for .so to load it.
void *handle = NULL;
void *handle = nullptr;
if (!symbols) {
handle = dlopen(soname.c_str(), RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
@@ -371,7 +379,6 @@ bool BuiltinSymbols::LoadSepExtensionSymbols(AnalysisResultPtr ar,
ParseExtFunctions(ar, symbols[0], true);
ParseExtConsts (ar, symbols[1], true);
ParseExtClasses (ar, symbols[2], true);
ParseExtDynamics (ar, symbols[3], true);
if (handle) {
/*
@@ -385,45 +392,48 @@ bool BuiltinSymbols::LoadSepExtensionSymbols(AnalysisResultPtr ar,
return true;
}
void BuiltinSymbols::Parse(AnalysisResultPtr ar,
const std::string& phpBaseName,
const std::string& phpFileName) {
const char *baseName = s_strings.add(phpBaseName.c_str());
const char *fileName = s_strings.add(phpFileName.c_str());
try {
Scanner scanner(fileName, Option::ScannerType);
Compiler::Parser parser(scanner, baseName, ar);
if (!parser.parse()) {
Logger::Error("Unable to parse file %s: %s", fileName,
parser.getMessage().c_str());
assert(false);
}
} catch (FileOpenException &e) {
Logger::Error("%s", e.getMessage().c_str());
}
}
bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) {
if (Loaded) return true;
Loaded = true;
// Build function scopes for some of the runtime helper functions
// declared in "runtime/base/builtin_functions.h"
const char **helper = HelperFunctions;
while (*helper) {
FunctionScopePtr f = ParseHelperFunction(ar, helper);
ASSERT(!s_helperFunctions[f->getName()]);
s_helperFunctions[f->getName()] = f;
}
// load extension functions first, so system/classes may call them
ParseExtFunctions(ar, ExtensionFunctions, false);
AnalysisResultPtr ar2;
AnalysisResultPtr ar2 = AnalysisResultPtr(new AnalysisResult());
s_variables = VariableTablePtr(new VariableTable(*ar2.get()));
s_constants = ConstantTablePtr(new ConstantTable(*ar2.get()));
// parse all PHP files under system/classes
if (!extOnly) {
ar = AnalysisResultPtr(new AnalysisResult());
ar->loadBuiltinFunctions();
for (const char **cls = SystemClasses; *cls; cls++) {
string phpBaseName = "/system/classes/";
phpBaseName += *cls;
phpBaseName += ".php";
string phpFileName = Option::GetSystemRoot() + phpBaseName;
const char *baseName = s_strings.add(phpBaseName.c_str());
const char *fileName = s_strings.add(phpFileName.c_str());
try {
Scanner scanner(fileName, Option::ScannerType);
Compiler::Parser parser(scanner, baseName, ar);
if (!parser.parse()) {
Logger::Error("Unable to parse file %s: %s", fileName,
parser.getMessage().c_str());
ASSERT(false);
}
} catch (FileOpenException &e) {
Logger::Error("%s", e.getMessage().c_str());
string slib = systemlib_path();
if (slib.empty()) {
for (const char **cls = SystemClasses; *cls; cls++) {
string phpBaseName = "/system/classes/";
phpBaseName += *cls;
phpBaseName += ".php";
Parse(ar, phpBaseName, Option::GetSystemRoot() + phpBaseName);
}
} else {
Parse(ar, slib, slib);
}
ar->analyzeProgram(true);
ar->inferTypes();
@@ -434,37 +444,19 @@ bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) {
iterFile->second->getClasses();
for (StringToClassScopePtrVecMap::const_iterator iter = classes.begin();
iter != classes.end(); ++iter) {
ASSERT(iter->second.size() == 1);
assert(iter->second.size() == 1);
iter->second[0]->setSystem();
ASSERT(!s_classes[iter->first]);
assert(!s_classes[iter->first]);
s_classes[iter->first] = iter->second[0];
}
}
// parse globals/variables.php and globals/constants.php
NoSuperGlobals = true;
s_variables = LoadGlobalSymbols("symbols.php")->getVariables();
ar2 = LoadGlobalSymbols("constants.php");
const FileScopePtrVec &fileScopes = ar2->getAllFilesVector();
if (!fileScopes.empty()) {
s_constants = fileScopes[0]->getConstants();
} else {
ar2 = AnalysisResultPtr(new AnalysisResult());
s_constants = ConstantTablePtr(new ConstantTable(*ar2.get()));
}
NoSuperGlobals = false;
} else {
ar2 = AnalysisResultPtr(new AnalysisResult());
s_variables = VariableTablePtr(new VariableTable(*ar2.get()));
s_constants = ConstantTablePtr(new ConstantTable(*ar2.get()));
NoSuperGlobals = true;
}
s_constants->setDynamic(ar, "SID", true);
// load extension constants, classes and dynamics
ParseExtConsts(ar, ExtensionConsts, false);
ParseExtClasses(ar, ExtensionClasses, false);
ParseExtDynamics(ar, ExtensionDeclaredDynamic, false);
for (unsigned int i = 0; i < Option::SepExtensions.size(); i++) {
Option::SepExtensionOptions &options = Option::SepExtensions[i];
string soname = options.soname;
@@ -479,6 +471,35 @@ bool BuiltinSymbols::Load(AnalysisResultPtr ar, bool extOnly /* = false */) {
}
}
if (!extOnly) {
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);
return true;
}
@@ -494,7 +515,7 @@ AnalysisResultPtr BuiltinSymbols::LoadGlobalSymbols(const char *fileName) {
Scanner scanner(fileName, Option::ScannerType);
Compiler::Parser parser(scanner, baseName, ar);
if (!parser.parse()) {
ASSERT(false);
assert(false);
Logger::Error("Unable to parse file %s: %s", fileName,
parser.getMessage().c_str());
}
@@ -508,7 +529,7 @@ AnalysisResultPtr BuiltinSymbols::LoadGlobalSymbols(const char *fileName) {
void BuiltinSymbols::LoadFunctions(AnalysisResultPtr ar,
StringToFunctionScopePtrMap &functions) {
ASSERT(Loaded);
assert(Loaded);
for (StringToFunctionScopePtrMap::const_iterator it = s_functions.begin();
it != s_functions.end(); ++it) {
if (functions.find(it->first) == functions.end()) {
@@ -520,7 +541,7 @@ void BuiltinSymbols::LoadFunctions(AnalysisResultPtr ar,
void BuiltinSymbols::LoadClasses(AnalysisResultPtr ar,
StringToClassScopePtrMap &classes) {
ASSERT(Loaded);
assert(Loaded);
classes.insert(s_classes.begin(), s_classes.end());
// we are adding these builtin functions, so that user-defined functions
@@ -537,7 +558,7 @@ void BuiltinSymbols::LoadClasses(AnalysisResultPtr ar,
void BuiltinSymbols::LoadVariables(AnalysisResultPtr ar,
VariableTablePtr variables) {
ASSERT(Loaded);
assert(Loaded);
if (s_variables) {
variables->import(s_variables);
}
@@ -545,12 +566,21 @@ void BuiltinSymbols::LoadVariables(AnalysisResultPtr ar,
void BuiltinSymbols::LoadConstants(AnalysisResultPtr ar,
ConstantTablePtr constants) {
ASSERT(Loaded);
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;
@@ -567,19 +597,13 @@ void BuiltinSymbols::LoadSuperGlobals() {
bool BuiltinSymbols::IsSuperGlobal(const std::string &name) {
if (NoSuperGlobals) return false;
LoadSuperGlobals();
return s_superGlobals.find(name) != s_superGlobals.end();
}
TypePtr BuiltinSymbols::GetSuperGlobalType(const std::string &name) {
LoadSuperGlobals();
StringToTypePtrMap::const_iterator iter = s_superGlobals.find(name);
if (iter != s_superGlobals.end()) {
return iter->second;
}
return TypePtr();
}
bool BuiltinSymbols::IsDeclaredDynamic(const std::string& name) {
return s_declaredDynamic.find(name) != s_declaredDynamic.end();
}
@@ -46,6 +46,11 @@ public:
static void LoadConstants(AnalysisResultPtr ar,
ConstantTablePtr constants);
/*
* Load system/globals/constants.php.
*/
static ConstantTablePtr LoadSystemConstants();
/**
* Testing whether a variable is a PHP superglobal.
*/
@@ -53,13 +58,15 @@ public:
static TypePtr GetSuperGlobalType(const std::string &name);
static bool IsDeclaredDynamic(const std::string& name);
static void LoadSuperGlobals();
static StringToFunctionScopePtrMap s_functions;
static StringToFunctionScopePtrMap s_helperFunctions;
static StringToClassScopePtrMap s_classes;
static VariableTablePtr s_variables;
static ConstantTablePtr s_constants;
static const char *const GlobalNames[];
static int NumGlobalNames();
private:
static StringBag s_strings;
static const char *ExtensionFunctions[];
@@ -67,11 +74,13 @@ private:
static const char *ExtensionConsts[];
static const char *ExtensionDeclaredDynamic[];
static const char *SystemClasses[];
static const char *HelperFunctions[];
static AnalysisResultPtr LoadGlobalSymbols(const char *fileName);
static void Parse(AnalysisResultPtr ar,
const std::string& phpBaseName,
const std::string& phpFileName);
static StringToTypePtrMap s_superGlobals;
static void LoadSuperGlobals();
static std::set<std::string> s_declaredDynamic;
+426
Ver Arquivo
@@ -0,0 +1,426 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 <compiler/code_generator.h>
#include <compiler/statement/statement_list.h>
#include <compiler/option.h>
#include <compiler/analysis/file_scope.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/analysis/analysis_result.h>
#include <compiler/analysis/variable_table.h>
#include <util/util.h>
#include <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());
}
@@ -27,6 +27,8 @@ DECLARE_BOOST_TYPES(Statement);
DECLARE_BOOST_TYPES(Construct);
DECLARE_BOOST_TYPES(BlockScope);
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(FunctionScope);
DECLARE_BOOST_TYPES(FileScope);
DECLARE_BOOST_TYPES(LoopStatement);
class CodeGenerator {
@@ -41,6 +43,8 @@ public:
FileCPP, // 1 to 1 from php to cpp file
ClusterCPP, // each directory up to a certain depth to a cpp file
SystemCPP, // special mode for generating builtin classes
TextHHBC, // HHBC dump in human-readable format
BinaryHHBC, // serialized HHBC
};
enum Stream {
@@ -91,6 +95,27 @@ public:
BreakScopeBitMask = InsideSwitch | StaticCases
};
class ClassScopeCompare {
public:
bool operator()(const ClassScopeRawPtr &p1,
const ClassScopeRawPtr &p2) const {
return cmp(p1, p2) < 0;
}
int cmp(const ClassScopeRawPtr &p1, const ClassScopeRawPtr &p2) const;
};
typedef std::set<ClassScopeRawPtr,ClassScopeCompare> ClassScopeSet;
typedef std::pair<ClassScopeRawPtr, std::string> UsedClassConst;
class ClassConstCompare : public ClassScopeCompare {
public:
bool operator()(const UsedClassConst &p1,
const UsedClassConst &p2) const {
int d = cmp(p1.first, p2.first);
if (d) return d < 0;
return p1.second < p2.second;
}
};
typedef std::set<UsedClassConst,ClassConstCompare> UsedClassConstSet;
public:
/**
* Hash strings to numbers so we can build a switch statement.
@@ -107,7 +132,7 @@ public:
public:
CodeGenerator() {} // only for creating a dummy code generator
CodeGenerator(std::ostream *primary, Output output = PickledPHP,
const std::string *filename = NULL);
const std::string *filename = nullptr);
/**
* ...if it was passed in from constructor.
@@ -138,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.
*/
@@ -158,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
@@ -243,31 +249,22 @@ 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);
bool insertDeclaredClosure(const FunctionScope *f) {
return m_declaredClosures.insert(f).second;
}
void setLiteralScope(FileScopeRawPtr fs) {
m_literalScope = fs;
}
FileScopeRawPtr getLiteralScope() const {
return m_literalScope;
}
void clearClasses() { m_classes.clear(); }
private:
std::string m_filename;
Stream m_curStream;
@@ -287,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;
@@ -298,8 +293,9 @@ 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;
int m_itemIndex;
@@ -309,8 +305,10 @@ private:
bool m_scalarVariant;
bool m_initListFirstElem;
public: void print(const char *msg, bool indent = true);
private:
void print(const char *fmt, va_list ap);
void print(const char *msg, bool indent = true);
void printSubstring(const char *start, int length);
void printIndent();
std::string getFormattedName(const std::string &file);
@@ -319,10 +317,12 @@ private:
#define STR(x) #x
#define XSTR(x) STR(x)
#define FLANN(stream,func,nl) (Option::FlAnnotate ? \
stream.printf("/* %s:" XSTR(__LINE__) "*/"nl, __func__): \
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,"")
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+26
Ver Arquivo
@@ -0,0 +1,26 @@
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- 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 COMPILER_H
#define COMPILER_H
namespace HPHP {
int compiler_main(int argc, char** argv);
}
#endif

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