120 Commits

Autor SHA1 Mensagem Data
hermanv b74a0da062 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 07:48:43 -08:00
ptarjan e663cfb0fd make test filters consistent
Summary:
Here are all the lines in filters: https://phabricator.fb.com/P1981345

About 1/2 of them are removing the path. I thought about doing it by default but the easiest still seemed like an opt-in symlink. I re-used another script someone else wrote so if it misses some edge case lets just fix that script. I don't like the name of it since it is hard to remembrer what to symlink, but I guess ##ls##ing isn't too bad.

Done with:

    grep -l "^sed -e 's/[\]/\.\*hphp/hphp/g'$" * | xargs -I{} ln -sf filepath.filter {}
    grep -l "^sed -e 's, in \[^ \]\*hphp/, in hphp/,'$" * | xargs -I{} ln -sf filepath.filter {}
    grep -l "^sed -e 's/in [\]/\.\*hphp/in hphp/g'$" * | xargs -I{} ln -sf filepath.filter {}
    grep -l "^sed -e 's, \[^ \]\*hphp/, hphp/,g'$" * | xargs -I{} ln -sf filepath.filter {}
    grep -l "^sed -e 's/ in [\]/\.\*hphp\.\*$//g'$" * | xargs -I{} ln -sf filepath.filter {}
    grep -l "^sed -e 's, \[^ \]\*\(hphp/\.\*[\])\$, [\]1,g'$" * | xargs -I{} ln -sf filepath.filter {}
    grep -l "^sed -e 's, \[^ \]\*[\](hphp/\.\*[\])\$, [\]1,g'$" * | xargs -I{} ln -sf filepath.filter {}

then i did the rest by hand with:

    vim `find . -type f -name '*.filter'`

and then took all the test output as gospel (after looking it over of course):

    for i in `ls *.out`; do j=`echo $i | sed s/out/exp/`; mv $i $j; done

Test Plan:
make verify_quick

  $ grep sed `find . -type f -name '*.filter' ` | grep -v filepath
  ./closure.filter:sed -r -e 's,(Closure\$)([^$]*\$){3}[0-9_]*,\1,g'
  ./backup_cycle_collector.php.filter:exec sed -e 's/cpu\ time.*//g'
  ./perfctr.php.filter:sed -e '/int(.*/d'
  ./reflection.php.filter:sed -e 's/^\([ ]*object([^)]\+)\)#[0-9]\+/\1/g' | sed -e 's/^string.*"\/.*hphp/"hphp/g'
  ./Setprofile.php.filter:sed -e 's/.*hphp\//hphp\//g' -e 's/.*systemlib.*//g' -e 's/string(..) "[0-9]\+_[0-9]\+"/string() "XX_X"/'
  ./builtin_call.php.filter:sed -e '/SlowTimer/d'
  ./serialize.php.filter:sed -e 's/^\(object([^)]\+)\)#[0-9]\+/\1/g'
  ./properties.php.filter:sed -e 's/^\(object([^)]\+)\)#[0-9]\+/\1/g'
  ./PropU.php.filter:sed -e 's/^\(object([^)]\+)\)#[0-9]\+/\1/g'
  ./destructed_this.php.filter:exec sed -e's/.*string.*//g'
  ./bitop_types.php.filter:sed -e 's,to int in string on line [0-9]*,to int,g'
  ./debug_backtrace.php.filter:sed -e 's/string(.*) ".*\/hphp/string() "hphp/g'
  ./resurrect.php.filter:sed -e 's/^\(object([^)]\+)\)#[0-9]\+/\1/g'
  ./objiter.php.filter:sed -e 's/^\(object([^)]\+)\)#[0-9]\+/\1/g'
  ./magic-get-set.php.filter:sed -e 's/^\(object([^)]\+)\)#[0-9]\+/\1/g'
  ./clone.php.filter:sed -e 's/^\(object([^)]\+)\)#[0-9]\+/\1/g'
  ./setprofile_throw.php.filter:exec sed -e 's/hook threw.*//g'

Reviewers: jdelong, andrewparoski, mwilliams

Reviewed By: mwilliams

CC: hphp-diffs@lists, ps, mwilliams, ottoni, smith

Differential Revision: https://phabricator.fb.com/D708806
2013-02-19 07:02:21 -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
9189 arquivos alterados com 142774 adições e 554078 exclusões
+38 -78
Ver Arquivo
@@ -8,102 +8,62 @@
.mkdir
hphp.log
/src/test/test
/src/test/test_fast.inc
/src/test/test_mysql_info.inc
/src/test/test_suite.inc
/src/test/real_mysql_info.inc
/src/test/*.tmp
/src/test/vm/*.out
/src/test/vm/*.diff
/src/test/vm/*.log
/src/test/vm/*.reduce_out
/src/test/vm/*.reduce_diff
/src/test/vm/*.reduce_exp
/src/test/vm/*.perf
/src/test/vm/perf/*.out
/src/test/vm/perf/*.diff
/src/test/vm/perf/*.perf
/src/runtime/ext_hhvm/xconstants.php
/src/runtime/ext_hhvm/ext_hhvm_infotabs.cpp
/src/runtime/ext_hhvm/ext_noinline.cpp
/src/compiler/analysis/code_error.inc
/hphp/test/test
/hphp/test/test_fast.inc
/hphp/test/test_mysql_info.inc
/hphp/test/test_suite.inc
/hphp/test/real_mysql_info.inc
/hphp/test/*.tmp
/hphp/test/vm/*.out
/hphp/test/vm/*.diff
/hphp/test/vm/*.log
/hphp/test/vm/*.reduce_out
/hphp/test/vm/*.reduce_diff
/hphp/test/vm/*.reduce_exp
/hphp/test/vm/*.perf
/hphp/test/vm/perf/*.out
/hphp/test/vm/perf/*.diff
/hphp/test/vm/perf/*.perf
/hphp/runtime/ext_hhvm/ext_noinline.cpp
/hphp/compiler/analysis/code_error.inc
/src/runtime/tmp/Test*
/src/runtime/tmp/run
/src/runtime/tmp/run.sh
/src/runtime/tmp/libtest.so
/src/runtime/vm/repo_schema.h
/src/runtime/base/compiler_id.h
/hphp/runtime/tmp/Test*
/hphp/runtime/tmp/run
/hphp/runtime/tmp/run.sh
/hphp/runtime/tmp/libtest.so
/hphp/runtime/vm/repo_schema.h
/hphp/runtime/base/compiler_id.h
/src/hphpi/gen
/src/hphpi/hphpi
/hphp/hphpi/gen
/hphp/hphpi/hphpi
/src/hhvm/gen
/src/hhvm/hhvm
/src/hhvm/hphp
/hphp/hhvm/gen
/hphp/hhvm/hhvm
/src/tools/shmw/shmw
/hphp/tools/shmw/shmw
/src/ffi/java/classes
/src/ffi/java/hphp_ffi_java.h
/hphp/ffi/java/classes
/hphp/ffi/java/hphp_ffi_java.h
# Ignore all makefiles generated for fbcode's third-party repo
/bin/*.mk
!/bin/run.mk
/facebook/arcanist/.phutil_module_cache
/facebook/autoload_files
/facebook/hotcold.hdf
/facebook/benchmark/shootout/output_bench
/facebook/benchmark/shootout/output_bintree_new
/facebook/libcore_files
/facebook/output_*
/facebook/push/install
/facebook/stub_funcs.hdf
/facebook/volatile.hdf
/facebook/www.pid
/facebook/push/apc
/facebook/push/apclog
/facebook/push/autoload_files
/facebook/push/hotcold.hdf
/facebook/push/output_www
/facebook/push/system.tgz
/facebook/push/volatile.hdf
/facebook/push/stub_funcs.hdf
/facebook/push/output
/facebook/push/shared
/facebook/extensions/gen
/facebook/extensions/hphpi
/local/*.mk
CMakeFiles
CMakeCache.txt
cmake_install.cmake
/output_gd/
/src/TAGS
# arcanist working-copy settings
.arc/
# fbcode output directory
/bin/_fbcode_bin/
/hphp/TAGS
# Generated makefiles
/src/third_party/lz4/Makefile
/src/third_party/double-conversion/Makefile
/src/third_party/folly/Makefile
/src/runtime/ext_hhvm/Makefile
/src/test/Makefile
/src/hphp/Makefile
/src/hhvm/Makefile
/src/compiler/Makefile
/src/Makefile
/hphp/runtime/ext_hhvm/Makefile
/hphp/test/Makefile
/hphp/hphp/Makefile
/hphp/hhvm/Makefile
/hphp/compiler/Makefile
/hphp/Makefile
/Makefile
# eclipse files
+12 -12
Ver Arquivo
@@ -134,15 +134,15 @@ find_package(EXPAT REQUIRED)
include_directories(${EXPAT_INCLUDE_DIRS})
# SQLite3 + timelib are bundled in HPHP sources
include_directories("${HPHP_HOME}/src/third_party/libsqlite3")
include_directories("${HPHP_HOME}/src/third_party/timelib")
include_directories("${HPHP_HOME}/src/third_party/libafdt/src")
include_directories("${HPHP_HOME}/src/third_party/libmbfl")
include_directories("${HPHP_HOME}/src/third_party/libmbfl/mbfl")
include_directories("${HPHP_HOME}/src/third_party/libmbfl/filter")
include_directories("${HPHP_HOME}/src/third_party/lz4")
include_directories("${HPHP_HOME}/src/third_party/double-conversion/src")
include_directories("${HPHP_HOME}/src/third_party/folly")
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)
@@ -151,7 +151,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
@@ -351,8 +351,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)
+4 -4
Ver Arquivo
@@ -112,10 +112,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-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names -Wno-error=array-bounds -Wno-error=switch -std=gnu++0x -Werror=format-security -Wno-unused-result -Wno-sign-compare")
set(CMAKE_CXX_FLAGS "-fno-gcse -fno-omit-frame-pointer -ftemplate-depth-120 -Wall -Woverloaded-virtual -Wno-deprecated -Wno-strict-aliasing -Wno-write-strings -Wno-invalid-offsetof -fno-operator-names -Wno-error=array-bounds -Wno-error=switch -std=gnu++0x -Werror=format-security -Wno-unused-result -Wno-sign-compare")
endif()
IF(CMAKE_COMPILER_IS_GNUCC)
@@ -126,6 +126,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})
+1 -1
Ver Arquivo
@@ -20,7 +20,7 @@ SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/HPHPFunctions.cmake")
include(CheckFunctionExists)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/hphp)
IF(CMAKE_SIZEOF_VOID_P EQUAL 4)
message(FATAL_ERROR "32-bit support is currently unsupported, check back with a later version of HipHop")
+3 -5
Ver Arquivo
@@ -179,16 +179,14 @@ class Exception {
// Remove top stack frames up to and including Exception::__init__,
// set the 'file' and 'line' properties appropriately
while (!empty($this->trace)) {
$top = $this->trace[0];
$top = array_shift($this->trace);
if (isset($top['class']) && isset($top['function']) &&
strcasecmp($top['class'], 'exception') === 0 &&
strcasecmp($top['function'], '__init__') === 0) {
$frame = array_shift($this->trace);
if (isset($frame['file'])) $this->file = $frame['file'];
if (isset($frame['line'])) $this->line = $frame['line'];
if (isset($top['file'])) $this->file = $top['file'];
if (isset($top['line'])) $this->line = $top['line'];
return;
}
array_shift($this->trace);
}
}
+196
Ver Arquivo
@@ -0,0 +1,196 @@
#
# +----------------------------------------------------------------------+
# | 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)
if ("$ENV{USE_HHVM}" STREQUAL "1")
# HHVM Build
SET(USE_HHVM TRUE)
SET(ENV{HHVM} 1)
ADD_DEFINITIONS("-DHHVM -DHHVM_BINARY=1 -DHHVM_PATH=\\\"${HPHP_HOME}/hphp/hhvm/hhvm\\\"")
if ("$ENV{USE_HPHPC}" STREQUAL "1")
message(FATAL_ERROR "Both USE_HHVM and USE_HPHPC are set, you may only select one")
endif()
else()
# HPHPc Build
SET(USE_HHVM FALSE)
ADD_DEFINITIONS("-DHHVM_PATH=\"\"")
if (NOT "$ENV{USE_HPHPC}" STREQUAL "1")
message(FATAL_ERROR "You must select which version of HipHop to build by setting either USE_HHVM=1 or USE_HPHPC=1 in your environment")
endif()
endif()
set(RECURSIVE_SOURCE_SUBDIRS runtime/base runtime/eval runtime/ext runtime/vm system/gen system/lib 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
if (USE_HHVM)
foreach (file ${CXX_SOURCES})
if (${file} MATCHES "ext/sep")
list(REMOVE_ITEM CXX_SOURCES ${file})
endif()
endforeach(file ${CXX_SOURCES})
endif(USE_HHVM)
if (EXISTS "${hphp_SOURCE_DIR}/HPHP_EXCLUDE_FILES.txt")
FILE(READ ${hphp_SOURCE_DIR}/HPHP_EXCLUDE_FILES.txt HPHP_EXCLUDE_FILES)
STRING(REGEX REPLACE "[\n\r]" ";" HPHP_EXCLUDE_FILES "${HPHP_EXCLUDE_FILES}")
else ()
SET(HPHP_EXCLUDE_FILES)
endif ()
foreach (t ${HPHP_EXCLUDE_FILES})
string(SUBSTRING ${t} 0 1 T_FIRST_CHAR)
if (${T_FIRST_CHAR} STREQUAL "D")
string(REGEX REPLACE "^[D]" "" SKIP_DIR "${t}")
file(TO_CMAKE_PATH "${hphp_SOURCE_DIR}/${SKIP_DIR}" SKIP_DIR)
string(LENGTH "${SKIP_DIR}" SKIP_DIR_LENGTH)
message(STATUS "Let's remove ${SKIP_DIR}")
foreach (file ${CXX_SOURCES})
string(LENGTH "${file}" FILE_LENGTH)
if (${FILE_LENGTH} GREATER ${SKIP_DIR_LENGTH})
string(SUBSTRING ${file} 0 ${SKIP_DIR_LENGTH} FILE_PATH)
if (${FILE_PATH} STREQUAL ${SKIP_DIR})
list(REMOVE_ITEM CXX_SOURCES ${file})
endif ()
endif ()
endforeach(file ${CXX_SOURCES})
elseif (${T_FIRST_CHAR} STREQUAL "#")
# doing nothing since this is a comment
else ()
list(FIND CXX_SOURCES "${hphp_SOURCE_DIR}/${t}" FOUND_T)
if (FOUND_T GREATER -1)
LIST(REMOVE_AT CXX_SOURCES ${FOUND_T})
endif()
endif ()
endforeach(t ${HPHP_EXCLUDE_FILES})
#FLEX_TARGET(HphpScanner ${CMAKE_CURRENT_SOURCE_DIR}/runtime/eval/parser/hphp.x ${CMAKE_CURRENT_SOURCE_DIR}/runtime/eval/parser/lex.eval_.cpp COMPILE_FLAGS " -w -i -Peval_")
#BISON_TARGET(HphpParser ${CMAKE_CURRENT_SOURCE_DIR}/runtime/eval/parser/hphp.y ${CMAKE_CURRENT_SOURCE_DIR}/runtime/eval/parser/hphp.tab.cpp COMPILE_FLAGS " -v -d -p eval_")
#ADD_FLEX_BISON_DEPENDENCY(HphpScanner HphpParser)
# required to remove warning when a file is there twice
#list(REMOVE_ITEM CXX_SOURCES ${FLEX_HphpScanner_OUTPUTS} ${BISON_HphpParser_OUTPUTS})
#list(APPEND CXX_SOURCES ${FLEX_HphpScanner_OUTPUTS} ${BISON_HphpParser_OUTPUTS})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
#add_library(sqlite3 STATIC "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libsqlite3/sqlite3.c")
#auto_sources(TIMELIB_SOURCES "*.c" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/third_party/timelib")
#add_library(timelib STATIC ${TIMELIB_SOURCES})
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/base/compiler_id.h
COMMAND hphp/tools/generate_compiler_id.sh
DEPENDS ${CXX_SOURCES} ${C_SOURCES}
WORKING_DIRECTORY ${HPHP_HOME}
COMMENT "Generating Compiler ID"
VERBATIM)
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 runtime/base/compiler_id.h ${CXX_SOURCES} ${C_SOURCES})
#ADD_LIBRARY(hphp_runtime SHARED ${C_SOURCES} ${CXX_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 PROPERTIES CLEAN_DIRECT_OUTPUT 1)
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)
if (USE_HHVM)
add_subdirectory(runtime/ext_hhvm)
endif()
add_subdirectory(hhvm)
if (NOT "$ENV{HPHP_NOTEST}" STREQUAL "1")
add_subdirectory(test)
endif ()
@@ -1438,7 +1438,7 @@ ExpressionPtr AliasManager::canonicalizeNode(
Expression::UnsetContext)) {
ExpressionPtr rep;
int interf =
findInterf(e, true, rep, NULL, doArrayCSE);
findInterf(e, true, rep, nullptr, doArrayCSE);
add(m_accessList, e);
if (interf == SameAccess) {
if (e->getKindOf() == rep->getKindOf()) {
@@ -1498,7 +1498,7 @@ ExpressionPtr AliasManager::canonicalizeNode(
Expression::UnsetContext))) {
ExpressionPtr rep;
int interf =
findInterf(e, true, rep, NULL, doArrayCSE);
findInterf(e, true, rep, nullptr, doArrayCSE);
if (!m_inPseudoMain && interf == DisjointAccess && !m_cleared &&
e->is(Expression::KindOfSimpleVariable) &&
!e->isThis()) {
@@ -3669,7 +3669,7 @@ void AliasManager::doFinal(MethodStatementPtr m) {
}
void AliasManager::performReferencedAndNeededAnalysis(MethodStatementPtr m) {
always_assert(m_graph != NULL);
always_assert(m_graph != nullptr);
// bail out for pseudomain context
if (m->getScope()->inPseudoMain()) return;
@@ -3696,7 +3696,7 @@ void AliasManager::performReferencedAndNeededAnalysis(MethodStatementPtr m) {
}
int AliasManager::copyProp(MethodStatementPtr m) {
if (m_graph == NULL) createCFG(m);
if (m_graph == nullptr) createCFG(m);
performReferencedAndNeededAnalysis(m);
@@ -3719,13 +3719,13 @@ int AliasManager::copyProp(MethodStatementPtr m) {
}
void AliasManager::deleteCFG() {
assert(m_graph != NULL);
assert(m_graph != nullptr);
delete m_graph;
m_graph = NULL;
m_graph = nullptr;
}
void AliasManager::createCFG(MethodStatementPtr m) {
assert(m_graph == NULL);
assert(m_graph == nullptr);
m_graph = ControlFlowGraph::buildControlFlow(m);
}
@@ -3735,7 +3735,7 @@ void AliasManager::insertTypeAssertions(AnalysisResultConstPtr ar,
i.walk(m->getStmts());
if (Option::ControlFlow && Option::DumpAst) {
if (m_graph != NULL) deleteCFG();
if (m_graph != nullptr) deleteCFG();
createCFG(m);
printf("-------- BEGIN INSERTED -----------\n");
m_graph->dump(m_arp);
@@ -3750,7 +3750,7 @@ void AliasManager::removeTypeAssertions(AnalysisResultConstPtr ar,
r.walk(m->getStmts());
if (Option::ControlFlow && Option::DumpAst) {
if (m_graph != NULL) deleteCFG();
if (m_graph != nullptr) deleteCFG();
createCFG(m);
printf("-------- BEGIN REMOVED -----------\n");
m_graph->dump(m_arp);
@@ -3778,7 +3778,7 @@ int AliasManager::optimize(AnalysisResultConstPtr ar, MethodStatementPtr m) {
if (copyProp(m)) return 1;
}
if (m_graph != NULL) deleteCFG();
if (m_graph != nullptr) deleteCFG();
m_hasChainRoot = false;
@@ -74,7 +74,7 @@ IMPLEMENT_THREAD_LOCAL(BlockScopeRawPtrFlagsHashMap,
AnalysisResult::AnalysisResult()
: BlockScope("Root", "", StatementPtr(), BlockScope::ProgramScope),
m_arrayLitstrKeyMaxSize(0), m_arrayIntegerKeyMaxSize(0),
m_package(NULL), m_parseOnDemand(false), m_phase(ParseAllFiles),
m_package(nullptr), m_parseOnDemand(false), m_phase(ParseAllFiles),
m_scalarArraysCounter(0), m_paramRTTICounter(0),
m_scalarArraySortedAvgLen(0), m_scalarArraySortedIndex(0),
m_scalarArraySortedSumLen(0), m_scalarArrayCompressedTextSize(0),
@@ -1611,7 +1611,7 @@ public:
template<>
void AnalysisResult::preWaitCallback<Post>(
bool first, const BlockScopeRawPtrQueue &scopes, void *opaque) {
assert(!Option::ControlFlow || opaque != NULL);
assert(!Option::ControlFlow || opaque != nullptr);
if (first && Option::ControlFlow) {
JobQueueDispatcher<FinalWorker::JobType, FinalWorker> *dispatcher
= (JobQueueDispatcher<FinalWorker::JobType, FinalWorker> *) opaque;
@@ -1814,14 +1814,14 @@ void AnalysisResult::outputCPPNamedScalarVarIntegers(const std::string &file) {
const vector<string> &strings = it->second;
for (unsigned int i = 0; i < strings.size(); i++) {
int64 val;
sscanf(strings[i].c_str(), "%llx", &val);
sscanf(strings[i].c_str(), "%" PRIx64, &val);
Variant v(val);
int64 *startp = (int64 *)&v;
int64 *endp = (startp + multiple);
for (int64 *p = startp; p < endp; p++) {
cg_printf("0x%016llxLL, ", *p);
cg_printf("0x%016" PRIx64 "L, ", *p);
}
cg_printf("// %lld\n", val);
cg_printf("// %" PRId64 "\n", val);
}
}
cg_indentEnd("};\n");
@@ -1844,7 +1844,7 @@ void AnalysisResult::outputCPPNamedScalarVarIntegers(const std::string &file) {
void AnalysisResult::outputCPPFiniteDouble(CodeGenerator &cg, double dval) {
assert(finite(dval));
char *buf = NULL;
char *buf = nullptr;
if (dval == 0.0) dval = 0.0; // so to avoid "-0" output
// 17 to ensure lossless conversion
vspprintf(&buf, 0, "%.*G", 17, dval);
@@ -1882,12 +1882,12 @@ void AnalysisResult::outputCPPNamedScalarVarDoubles(const std::string &file) {
const vector<string> &strings = it->second;
for (unsigned int i = 0; i < strings.size(); i++) {
double val;
sscanf(strings[i].c_str(), "%llx", (int64*)(&val));
sscanf(strings[i].c_str(), "%" PRIx64, (int64*)(&val));
Variant v(val);
int64 *startp = (int64 *)&v;
int64 *endp = (startp + multiple);
for (int64 *p = startp; p < endp; p++) {
cg_printf("0x%016llxLL, ", *p);
cg_printf("0x%016" PRIx64 "L, ", *p);
}
cg_printf("// ");
outputCPPFiniteDouble(cg, val);
@@ -2511,7 +2511,7 @@ void AnalysisResult::outputAllCPP(CodeGenerator::Output output,
{
vector<OutputJob*> jobs;
JobQueueDispatcher<OutputJob*, OutputWorker>
dispatcher(threadCount, true, 0, false, NULL);
dispatcher(threadCount, true, 0, false, nullptr);
string root = getOutputPath() + "/";
for (StringToFileScopePtrVecMap::const_iterator iter = clusters.begin();
@@ -2544,7 +2544,7 @@ void AnalysisResult::outputAllCPP(CodeGenerator::Output output,
{
vector<OutputJob*> jobs;
JobQueueDispatcher<OutputJob*, OutputWorker>
dispatcher(threadCount, true, 0, false, NULL);
dispatcher(threadCount, true, 0, false, nullptr);
if (clusterCount > 0) {
OutputJob *job = new RepartitionJob(ar, filenames, additionalCPPs);
@@ -2809,7 +2809,7 @@ void AnalysisResult::outputCPPNameMaps() {
char **params = (char **)calloc(m_paramRTTICounter, sizeof(char*));
for (map<string, int>::const_iterator
iter = m_paramRTTIs.begin(); iter != m_paramRTTIs.end(); ++iter) {
assert(params[iter->second] == NULL);
assert(params[iter->second] == nullptr);
params[iter->second] = (char *)iter->first.c_str();
}
for (int i = 0; i < m_paramRTTICounter; i++) {
@@ -2828,7 +2828,7 @@ void AnalysisResult::outputCPPNameMaps() {
void AnalysisResult::outputRTTIMetaData(const char *filename) {
assert(filename && *filename);
FILE *f = fopen(filename, "w");
if (f == NULL) {
if (f == nullptr) {
throw Exception("Unable to open %s: %s", filename,
Util::safe_strerror(errno).c_str());
}
@@ -2886,10 +2886,10 @@ void AnalysisResult::outputCPPUtilImpl(CodeGenerator::Output output) {
for (set<int64>::const_iterator it = m_allIntegers.begin();
it != m_allIntegers.end(); it++) {
if (!String::HasConverted(*(it))) {
if (*(it) == LONG_MIN) {
cg_printf("(int64)0x%llxLL,\n", (uint64)LONG_MIN);
if (*(it) == std::numeric_limits<int64_t>::min()) {
cg_printf("(int64)0x8000000000000000LL,\n");
} else {
cg_printf("%lldLL,\n", *(it));
cg_printf("%" PRId64 "L,\n", *(it));
}
}
}
@@ -4587,7 +4587,7 @@ void AnalysisResult::preGenerateCPP(CodeGenerator::Output output,
AnalysisResultPtr ar = shared_from_this();
vector<PreGenerateCPPJob*> jobs;
JobQueueDispatcher<OutputJob*, OutputWorker>
dispatcher(threadCount, true, 0, false, NULL);
dispatcher(threadCount, true, 0, false, nullptr);
m_pregenerating = true;
BOOST_FOREACH(FileScopePtr fs, files) {
@@ -5065,7 +5065,7 @@ void AnalysisResult::outputStringProxyData(CodeGenerator &cg,
cg_printf("%s,\n", lStrings[i].c_str());
}
for (uint i = 0; i < bStrings.size(); i++) {
cg_printf("%s, (const char *)%lldLL,\n",
cg_printf("%s, (const char *)%" PRId64 "L,\n",
bStrings[i].first.c_str(), (int64)bStrings[i].second);
}
cg_indentEnd("};\n");
@@ -5306,7 +5306,7 @@ void AnalysisResult::outputCPPSepExtensionMake() {
for (unsigned int i = 0; i < Option::SepExtensions.size(); i++) {
Option::SepExtensionOptions &options = Option::SepExtensions[i];
if (options.include_path.empty()) {
f << "\t-I $(PROJECT_ROOT)/src/runtime/ext/sep/" << options.name;
f << "\t-I $(PROJECT_ROOT)/hphp/runtime/ext/sep/" << options.name;
} else {
f << "\t-I " << options.include_path;
}
@@ -5318,14 +5318,14 @@ void AnalysisResult::outputCPPSepExtensionMake() {
Option::SepExtensionOptions &options = Option::SepExtensions[i];
if (options.shared) {
if (options.lib_path.empty()) {
f << "\t-L $(PROJECT_ROOT)/src/runtime/ext/sep/" << options.name;
f << "\t-L $(PROJECT_ROOT)/hphp/runtime/ext/sep/" << options.name;
} else {
f << "\t-L " << options.lib_path;
}
f << " -l" << options.name << " \\\n";
} else {
if (options.lib_path.empty()) {
f << "\t$(PROJECT_ROOT)/src/runtime/ext/sep/" << options.name;
f << "\t$(PROJECT_ROOT)/hphp/runtime/ext/sep/" << options.name;
} else {
f << "\t" << options.lib_path;
}
@@ -635,7 +635,7 @@ public:
private:
template <typename Visitor>
void processScopesParallel(const char *id, void *opaque = NULL);
void processScopesParallel(const char *id, void *opaque = nullptr);
template <typename Visitor>
void preWaitCallback(bool first,
@@ -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);
@@ -1247,7 +1247,7 @@ TypePtr ClassScope::checkConst(BlockScopeRawPtr context,
ConstructPtr construct,
const std::vector<std::string> &bases,
BlockScope *&defScope) {
defScope = NULL;
defScope = nullptr;
return getConstants()->check(context, name, type, coerce,
ar, construct, m_bases, defScope);
}
@@ -2216,7 +2216,7 @@ void ClassScope::outputCPPGetClassPropTableImpl(
Option::ConstantPrefix,
CodeGenerator::FormatLabel(name).c_str());
}
cg_printf("0x%x1LL", name_ix);
cg_printf("int64_t(0x%xd)", name_ix);
} else if (flags & ConstRedeclared) {
cg_printf("offsetof(%s,%s%s)+0x%x00000003",
system ? "SystemGlobals" : "GlobalVariables",
@@ -2232,7 +2232,7 @@ void ClassScope::outputCPPGetClassPropTableImpl(
CodeGenerator::FormatLabel(name).c_str(),
cls_ix);
} else {
cg_printf("0x%x%07x%dLL", name_ix, cls_ix,
cg_printf("0x%x%07x%dL", name_ix, cls_ix,
flags & ConstDerivesFromRedeclared ? 4 : 5);
}
*p = ++index;
@@ -3219,9 +3219,9 @@ void ClassScope::outputCPPMethodInvokeTableSupport(CodeGenerator &cg,
assert(iterFuncs != funcScopes.end());
FunctionScopePtr func = iterFuncs->second;
const char *extra = NULL;
const char *extra = nullptr;
string prefix;
const char *instance = NULL;
const char *instance = nullptr;
if (func->isStatic()) {
prefix += Option::ClassPrefix;
prefix += id;
@@ -3459,7 +3459,7 @@ void ClassScope::outputMethodWrappers(CodeGenerator &cg,
FunctionScopePtr func = m_functionsVec[i];
if (func->isPublic() && !func->isConstructor(self) &&
!func->isMagic() && !func->isAbstract()) {
func->outputMethodWrapper(cg, ar, NULL);
func->outputMethodWrapper(cg, ar, nullptr);
}
}
}
@@ -178,7 +178,7 @@ void ClearErrors() {
}
void Error(ErrorType error, ConstructPtr construct) {
if (hhvm) return;
if (!Option::RecordErrors) return;
ErrorInfoPtr errorInfo(new ErrorInfo());
errorInfo->m_error = error;
errorInfo->m_construct1 = construct;
@@ -187,7 +187,7 @@ void Error(ErrorType error, ConstructPtr construct) {
}
void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
if (hhvm) return;
if (!Option::RecordErrors) return;
ErrorInfoPtr errorInfo(new ErrorInfo());
errorInfo->m_error = error;
errorInfo->m_construct1 = construct1;
@@ -197,7 +197,7 @@ void Error(ErrorType error, ConstructPtr construct1, ConstructPtr construct2) {
}
void Error(ErrorType error, ConstructPtr construct, const std::string &data) {
if (hhvm) return;
if (!Option::RecordErrors) return;
ErrorInfoPtr errorInfo(new ErrorInfo());
errorInfo->m_error = error;
errorInfo->m_construct1 = construct;
@@ -165,7 +165,7 @@ TypePtr ConstantTable::check(BlockScopeRawPtr context,
assert(!m_blockScope.is(BlockScope::FunctionScope));
bool isClassScope = m_blockScope.is(BlockScope::ClassScope);
TypePtr actualType;
defScope = NULL;
defScope = nullptr;
if (name == "true" || name == "false") {
actualType = Type::Boolean;
} else {
@@ -128,7 +128,7 @@ private:
ControlFlowInfo *get(ConstructRawPtr cp) {
ConstructCFIMap::iterator it = m_ccfiMap.find(cp);
return it == m_ccfiMap.end() ? NULL : &it->second;
return it == m_ccfiMap.end() ? nullptr : &it->second;
}
ControlFlowInfo &cfi(ConstructRawPtr cp) {
@@ -735,7 +735,7 @@ const StringData* SymbolicStack::getName(int index) const {
if (m_symStack[index].metaType == META_LITSTR) {
return m_symStack[index].metaData.name;
}
return NULL;
return nullptr;
}
const StringData* SymbolicStack::getClsName(int index) const {
@@ -1353,7 +1353,7 @@ void EmitterVisitor::prepareEvalStack() {
if (m_evalStackIsUnknown) {
if (!m_evalStack.empty()) {
InvariantViolation("Emitter expected to have an empty evaluation "
"stack because the eval stack was unknown, but"
"stack because the eval stack was unknown, but "
"it was non-empty.");
return;
}
@@ -1400,19 +1400,24 @@ bool EmitterVisitor::isJumpTarget(Offset target) {
}
#define CONTROL_BODY(brk, cnt, brkH, cntH) \
ControlTargetPusher _cop(this, -1, brk, cnt, brkH, cntH)
#define FOREACH_BODY(itId, brk, cnt, brkH, cntH) \
ControlTargetPusher _cop(this, itId, brk, cnt, brkH, cntH)
ControlTargetPusher _cop(this, -1, false, brk, cnt, brkH, cntH)
#define FOREACH_BODY(itId, itRef, brk, cnt, brkH, cntH) \
ControlTargetPusher _cop(this, itId, itRef, brk, cnt, brkH, cntH)
class IterFreeThunklet : public Thunklet {
public:
IterFreeThunklet(Id iterId) : m_id(iterId) {}
IterFreeThunklet(Id iterId, bool itRef) : m_id(iterId), m_itRef(itRef) {}
virtual void emit(Emitter& e) {
e.IterFree(m_id);
if (m_itRef) {
e.MIterFree(m_id);
} else {
e.IterFree(m_id);
}
e.Unwind();
}
private:
Id m_id;
bool m_itRef;
};
/**
@@ -1595,7 +1600,7 @@ void EmitterVisitor::visit(FileScopePtr file) {
StringData::GetStaticString(meth->getOriginalName());
m_methLabels[methName] = new Label();
// Emit afterwards
postponeMeth(meth, NULL, true);
postponeMeth(meth, nullptr, true);
}
}
{
@@ -1788,7 +1793,7 @@ static StringData* getClassName(ExpressionPtr e) {
if (cls && !cls->isTrait()) {
return StringData::GetStaticString(cls->getOriginalName());
}
return NULL;
return nullptr;
}
static DataType getPredictedDataType(ExpressionPtr expr) {
@@ -1890,7 +1895,7 @@ bool isTupleInit(ExpressionPtr init_expr, int* cap) {
ExpressionPtr ex = (*el)[i];
if (ex->getKindOf() != Expression::KindOfArrayPairExpression) return false;
ArrayPairExpressionPtr ap = static_pointer_cast<ArrayPairExpression>(ex);
if (ap->getName() != NULL || ap->isRef()) return false;
if (ap->getName() != nullptr || ap->isRef()) return false;
}
*cap = n;
return true;
@@ -1960,7 +1965,11 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
}
if (bs->is(Statement::KindOfBreakStatement)) {
if (m_contTargets.front().m_itId != -1) {
e.IterFree(m_contTargets.front().m_itId);
if (m_contTargets.front().m_itRef) {
e.MIterFree(m_contTargets.front().m_itId);
} else {
e.IterFree(m_contTargets.front().m_itId);
}
}
e.Jmp(m_contTargets.front().m_brkTarg);
} else {
@@ -2514,7 +2523,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
return false;
}
postponeMeth(m, NULL, true);
postponeMeth(m, nullptr, true);
} else {
FuncEmitter* fe = m_ue.newFuncEmitter(nName, false);
e.DefFunc(fe->id());
@@ -2834,7 +2843,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
if (op == T_COLLECTION) {
ScalarExpressionPtr cls =
static_pointer_cast<ScalarExpression>(b->getExp1());
const std::string* clsName = NULL;
const std::string* clsName = nullptr;
cls->getString(clsName);
int cType = 0;
if (!strcasecmp(clsName->c_str(), "vector")) {
@@ -2987,7 +2996,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
ExpressionListPtr args(el->getExpressions());
int n = args ? args->getCount() : 0;
int i = 0;
FPIRegionRecorder* fpi = NULL;
FPIRegionRecorder* fpi = nullptr;
if (el->getType() == '`') {
const static StringData* s_shell_exec =
StringData::GetStaticString("shell_exec");
@@ -3398,20 +3407,29 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
ExpressionListPtr params(om->getParams());
int numParams = params ? params->getCount() : 0;
Offset fpiStart;
if (!om->getName().empty()) {
// $obj->name(...)
// ^^^^
// Use getOriginalName, which hasn't been case-normalized, since
// __call() is case-preserving.
StringData* nameLiteral =
StringData::GetStaticString(om->getOriginalName());
fpiStart = m_ue.bcPos();
e.FPushObjMethodD(numParams, nameLiteral);
} else {
Offset fpiStart = 0;
ExpressionPtr methName = om->getNameExp();
bool useDirectForm = false;
if (methName->is(Expression::KindOfScalarExpression)) {
ScalarExpressionPtr sval(
static_pointer_cast<ScalarExpression>(methName));
const std::string& methStr = sval->getOriginalLiteralString();
if (!methStr.empty()) {
// $obj->name(...)
// ^^^^
// Use getOriginalLiteralString(), which hasn't been
// case-normalized, since __call() needs to preserve
// the case.
StringData* nameLiteral = StringData::GetStaticString(methStr);
fpiStart = m_ue.bcPos();
e.FPushObjMethodD(numParams, nameLiteral);
useDirectForm = true;
}
}
if (!useDirectForm) {
// $obj->{...}(...)
// ^^^^^
visit(om->getNameExp());
visit(methName);
emitConvertToCell(e);
fpiStart = m_ue.bcPos();
e.FPushObjMethod(numParams);
@@ -3419,7 +3437,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
if (clsName) {
Id id = m_ue.mergeLitstr(clsName);
m_metaInfo.add(fpiStart, Unit::MetaInfo::Class, false,
om->getName().empty() ? 1 : 0, id);
useDirectForm ? 0 : 1, id);
}
{
FPIRegionRecorder fpi(this, m_ue, m_evalStack, fpiStart);
@@ -3625,7 +3643,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
TypedValue tvVal;
initScalar(tvVal, val);
if (key != NULL) {
if (key != nullptr) {
// Key.
assert(key->isScalar());
TypedValue tvKey;
@@ -3768,7 +3786,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
PreClassEmitter* pce = m_ue.newPreClassEmitter(
className, PreClass::AlwaysHoistable);
pce->init(sLoc->line0, sLoc->line1, m_ue.bcPos(),
AttrUnique | AttrPersistent, parentName, NULL);
AttrUnique | AttrPersistent, parentName, nullptr);
// We're still at the closure definition site. Emit code to instantiate
// the new anonymous class, with the use variables as arguments.
@@ -3789,7 +3807,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
TypedValue uninit;
tvWriteUninit(&uninit);
for (int i = 0; i < useCount; ++i) {
pce->addProperty(useVars[i].first, AttrPrivate, NULL, &uninit);
pce->addProperty(useVars[i].first, AttrPrivate, nullptr, &uninit);
}
// The constructor. This is entirely generated; all it does is stash its
@@ -4135,13 +4153,7 @@ void EmitterVisitor::emitVGet(Emitter& e) {
}
}
namespace PassByRefKind {
static const ssize_t AllowCell = 0;
static const ssize_t WarnOnCell = 1;
static const ssize_t ErrorOnCell = 2;
}
static ssize_t getPassByRefKind(ExpressionPtr exp) {
EmitterVisitor::PassByRefKind EmitterVisitor::getPassByRefKind(ExpressionPtr exp) {
// The PassByRefKind of a list assignment expression is determined
// by the PassByRefKind of the RHS. This loop will repeatedly recurse
// on the RHS until it encounters an expression other than a list
@@ -4265,21 +4277,25 @@ void EmitterVisitor::emitFuncCallArg(Emitter& e,
}
return;
}
emitFPass(e, paramId, getPassByRefKind(exp));
}
void EmitterVisitor::emitFPass(Emitter& e, int paramId, PassByRefKind passByRefKind) {
if (checkIfStackEmpty("FPass*")) return;
LocationGuard locGuard(e, m_tempLoc);
m_tempLoc.reset();
emitClsIfSPropBase(e);
int iLast = m_evalStack.size()-1;
int i = scanStackForLocation(iLast);
int sz = iLast - i;
assert(sz >= 0);
char sym = m_evalStack.get(i);
// This ensures that the FPass instruction will be associated with
// exp's source location.
LocationGuard locGuard(e, m_tempLoc);
m_tempLoc.reset();
if (sz == 0 || (sz == 1 && StackSym::GetMarker(sym) == StackSym::S)) {
switch (sym) {
case StackSym::L: e.FPassL(paramId, m_evalStack.getLoc(i)); break;
case StackSym::C:
switch (getPassByRefKind(exp)) {
switch (passByRefKind) {
case PassByRefKind::AllowCell: e.FPassC(paramId); break;
case PassByRefKind::WarnOnCell: e.FPassCW(paramId); break;
case PassByRefKind::ErrorOnCell: e.FPassCE(paramId); break;
@@ -4575,7 +4591,13 @@ void EmitterVisitor::emitConvertToCell(Emitter& e) {
void EmitterVisitor::emitFreePendingIters(Emitter& e) {
for (unsigned i = 0; i < m_pendingIters.size(); ++i) {
e.IterFree(m_pendingIters[i]);
auto pendingIter = m_pendingIters[i];
if (pendingIter.second == KindOfMIter) {
e.MIterFree(pendingIter.first);
} else {
assert(pendingIter.second == KindOfIter);
e.IterFree(pendingIter.first);
}
}
}
@@ -4739,7 +4761,7 @@ void EmitterVisitor::emitClsIfSPropBase(Emitter& e) {
}
Label* EmitterVisitor::getContinuationGotoLabel(StatementPtr s) {
Label* label = NULL;
Label* label = nullptr;
StatementListPtr stmts(static_pointer_cast<StatementList>(s));
for (int i = 0; i < stmts->getCount(); i++) {
StatementPtr s((*stmts)[i]);
@@ -4749,7 +4771,7 @@ Label* EmitterVisitor::getContinuationGotoLabel(StatementPtr s) {
visit(f);
} else if (s->is(Statement::KindOfGotoStatement)) {
GotoStatementPtr g(static_pointer_cast<GotoStatement>(s));
always_assert(label == NULL);
always_assert(label == nullptr);
label = &m_gotoLabels[StringData::GetStaticString(g->label())];
} else {
not_implemented();
@@ -5292,7 +5314,7 @@ void EmitterVisitor::emitPostponedMeths() {
e.VerifyParamType(i);
}
if (fe->isClosureBody()) {
assert(p.m_closureUseVars != NULL);
assert(p.m_closureUseVars != nullptr);
// Emit code to unpack the instance variables (which store the
// use-variables) into locals. Some of the use-variables may have the
// same name, in which case the last one wins.
@@ -5583,7 +5605,7 @@ void EmitterVisitor::emitPostponedClosureCtors() {
ClosureUseVarVec& useVars = ctor.m_useVars;
FuncEmitter* fe = ctor.m_fe;
const Location* sLoc = ctor.m_expr->getLocation().get();
fe->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), AttrPublic, false, NULL);
fe->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), AttrPublic, false, nullptr);
unsigned n = useVars.size();
Emitter e(ctor.m_expr, m_ue, *this);
@@ -5837,7 +5859,7 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
ExpressionListPtr params(node->getParams());
int numParams = params ? params->getCount() : 0;
bool isBuiltinCall = false;
StringData* nLiteral = NULL;
StringData* nLiteral = nullptr;
Offset fpiStart;
if (node->getClass() || !node->getClassName().empty()) {
bool isSelfOrParent = node->isSelf() || node->isParent();
@@ -5884,7 +5906,7 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
e.FPushFuncD(numParams, nLiteral);
} else {
// Special handling for func_get_args and friends inside a generator.
const StringData* specialMethodName = NULL;
const StringData* specialMethodName = nullptr;
static const StringData* contName =
StringData::GetStaticString(CONTINUATION_OBJECT_NAME);
Id contId = m_curFunc->lookupVarId(contName);
@@ -5902,7 +5924,7 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
specialMethodName = s_get_arg;
}
if (specialMethodName != NULL) {
if (specialMethodName != nullptr) {
emitVirtualLocal(contId);
emitCGet(e);
fpiStart = m_ue.bcPos();
@@ -6082,9 +6104,9 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
pce->addUserAttribute(uaName, tv);
}
NonScalarVec* nonScalarPinitVec = NULL;
NonScalarVec* nonScalarSinitVec = NULL;
NonScalarVec* nonScalarConstVec = NULL;
NonScalarVec* nonScalarPinitVec = nullptr;
NonScalarVec* nonScalarSinitVec = nullptr;
NonScalarVec* nonScalarConstVec = nullptr;
if (StatementListPtr stmts = is->getStmts()) {
int i, n = stmts->getCount();
for (i = 0; i < n; i++) {
@@ -6128,12 +6150,12 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
} else {
tvWriteUninit(&tvVal);
if (!(attrs & AttrStatic)) {
if (nonScalarPinitVec == NULL) {
if (nonScalarPinitVec == nullptr) {
nonScalarPinitVec = new NonScalarVec();
}
nonScalarPinitVec->push_back(NonScalarPair(propName, vNode));
} else {
if (nonScalarSinitVec == NULL) {
if (nonScalarSinitVec == nullptr) {
nonScalarSinitVec = new NonScalarVec();
}
nonScalarSinitVec->push_back(NonScalarPair(propName, vNode));
@@ -6166,7 +6188,7 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
initScalar(tvVal, vNode);
} else {
tvWriteUninit(&tvVal);
if (nonScalarConstVec == NULL) {
if (nonScalarConstVec == nullptr) {
nonScalarConstVec = new NonScalarVec();
}
nonScalarConstVec->push_back(NonScalarPair(constName, vNode));
@@ -6198,7 +6220,7 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
postponeCtor(is, fe);
}
if (nonScalarPinitVec != NULL) {
if (nonScalarPinitVec != nullptr) {
// Non-scalar property initializers require 86pinit() for run-time
// initialization support.
static const StringData* methName = StringData::GetStaticString("86pinit");
@@ -6207,7 +6229,7 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
postponePinit(is, fe, nonScalarPinitVec);
}
if (nonScalarSinitVec != NULL) {
if (nonScalarSinitVec != nullptr) {
// Non-scalar property initializers require 86sinit() for run-time
// initialization support.
static const StringData* methName = StringData::GetStaticString("86sinit");
@@ -6216,7 +6238,7 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
postponeSinit(is, fe, nonScalarSinitVec);
}
if (nonScalarConstVec != NULL) {
if (nonScalarConstVec != nullptr) {
// Non-scalar constant initializers require 86cinit() for run-time
// initialization support.
static const StringData* methName = StringData::GetStaticString("86cinit");
@@ -6230,15 +6252,25 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
return hoistable;
}
void EmitterVisitor::emitBreakHandler(Emitter& e, Label& brkTarg,
Label& cntTarg, Label& brkHand, Label& cntHand, Id iter /* = -1 */) {
void
EmitterVisitor::emitBreakHandler(Emitter& e,
Label& brkTarg,
Label& cntTarg,
Label& brkHand,
Label& cntHand,
Id iter /* = -1 */,
IterKind itKind /* = KindOfIter */) {
// Handle dynamic break
if (brkHand.isUsed()) {
brkHand.set(e);
// Whatever happens, we have left this loop
if (iter != -1) {
e.IterFree(iter);
if (itKind == KindOfMIter) {
e.MIterFree(iter);
} else {
assert(itKind == KindOfIter);
e.IterFree(iter);
}
}
e.Int(1);
e.Sub();
@@ -6266,7 +6298,12 @@ void EmitterVisitor::emitBreakHandler(Emitter& e, Label& brkTarg,
e.Jmp(cntTarg);
leaving.set(e);
// Leaving this loop
e.IterFree(iter);
if (itKind == KindOfMIter) {
e.MIterFree(iter);
} else {
assert(itKind == KindOfIter);
e.IterFree(iter);
}
e.Jmp(topContHandler());
} else {
e.JmpZ(topContHandler());
@@ -6279,11 +6316,11 @@ void EmitterVisitor::emitBreakHandler(Emitter& e, Label& brkTarg,
class ForeachIterGuard {
EmitterVisitor& m_ev;
public:
ForeachIterGuard(EmitterVisitor& ev, Id iterId) : m_ev(ev) {
m_ev.pushIterId(iterId);
ForeachIterGuard(EmitterVisitor& ev, Id iterId, bool itRef) : m_ev(ev) {
m_ev.pushIterScope(iterId, itRef);
}
~ForeachIterGuard() {
m_ev.popIterId();
m_ev.popIterScope();
}
};
@@ -6306,7 +6343,7 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
Label start;
Offset bIterStart;
Id itId = m_curFunc->allocIterator();
ForeachIterGuard fig(*this, itId);
ForeachIterGuard fig(*this, itId, strong);
bool simpleCase = (!key || key->is(Expression::KindOfSimpleVariable)) &&
val->is(Expression::KindOfSimpleVariable);
@@ -6334,9 +6371,9 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
if (strong) {
emitConvertToVar(e);
if (key) {
e.IterInitMK(itId, exit, valTempLocal, keyTempLocal);
e.MIterInitK(itId, exit, valTempLocal, keyTempLocal);
} else {
e.IterInitM(itId, exit, valTempLocal);
e.MIterInit(itId, exit, valTempLocal);
}
} else {
emitConvertToCell(e);
@@ -6366,9 +6403,9 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
if (strong) {
if (key) {
e.IterInitMK(itId, exit, valTempLocal, keyTempLocal);
e.MIterInitK(itId, exit, valTempLocal, keyTempLocal);
} else {
e.IterInitM(itId, exit, valTempLocal);
e.MIterInit(itId, exit, valTempLocal);
}
} else {
if (key) {
@@ -6413,7 +6450,7 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
}
{
FOREACH_BODY(itId, exit, next, brkHand, cntHand);
FOREACH_BODY(itId, strong, exit, next, brkHand, cntHand);
if (body) visit(body);
}
bool needBreakHandler = (brkHand.isUsed() || cntHand.isUsed());
@@ -6432,9 +6469,9 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
m_evalStack.cleanTopMeta();
if (strong) {
if (key) {
e.IterNextMK(itId, start, valTempLocal, keyTempLocal);
e.MIterNextK(itId, start, valTempLocal, keyTempLocal);
} else {
e.IterNextM(itId, start, valTempLocal);
e.MIterNext(itId, start, valTempLocal);
}
} else {
if (key) {
@@ -6443,10 +6480,12 @@ void EmitterVisitor::emitForeach(Emitter& e, ForEachStatementPtr fe) {
e.IterNext(itId, start, valTempLocal);
}
}
newFaultRegion(bIterStart, m_ue.bcPos(), new IterFreeThunklet(itId), itId);
newFaultRegion(bIterStart, m_ue.bcPos(), new IterFreeThunklet(itId, strong),
itId);
if (needBreakHandler) {
e.Jmp(exit);
emitBreakHandler(e, exit, next, brkHand, cntHand, itId);
IterKind itKind = strong ? KindOfMIter : KindOfIter;
emitBreakHandler(e, exit, next, brkHand, cntHand, itId, itKind);
}
if (!simpleCase) {
m_curFunc->freeUnnamedLocal(valTempLocal);
@@ -6604,8 +6643,8 @@ void EmitterVisitor::finishFunc(Emitter& e, FuncEmitter* fe) {
StringData* EmitterVisitor::newClosureName() {
std::ostringstream str;
str << "closure$";
if (m_curFunc->pce() != NULL) {
str << "Closure" << '$';
if (m_curFunc->pce() != nullptr) {
str << m_curFunc->pce()->name()->data();
}
str << '$';
@@ -6806,14 +6845,14 @@ static Unit* emitHHBCNativeFuncUnit(const HhbcExtFuncInfo* builtinFuncs,
fe->finish(ue->bcPos(), false);
ue->recordFunction(fe);
for (ssize_t i = 0LL; i < numBuiltinFuncs; ++i) {
for (ssize_t i = 0; i < numBuiltinFuncs; ++i) {
const HhbcExtFuncInfo* info = &builtinFuncs[i];
StringData* name = StringData::GetStaticString(info->m_name);
BuiltinFunction bif = (BuiltinFunction)info->m_builtinFunc;
BuiltinFunction nif = (BuiltinFunction)info->m_nativeFunc;
const ClassInfo::MethodInfo* mi = ClassInfo::FindFunction(name);
assert(mi &&
"MethodInfo not found; probably need to rebuild src/system");
"MethodInfo not found; probably need to rebuild hphp/system");
FuncEmitter* fe = ue->newFuncEmitter(name, /*top*/ true);
Offset base = ue->bcPos();
fe->setBuiltinFunc(mi, bif, nif, base);
@@ -6929,7 +6968,7 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
// Build up extClassHash, a hashtable that maps class names to structures
// containing C++ function pointers for the class's methods and constructors
assert(Class::s_extClassHash.size() == 0);
for (long long i = 0LL; i < numBuiltinClasses; ++i) {
for (long long i = 0; i < numBuiltinClasses; ++i) {
const HhbcExtClassInfo* info = builtinClasses + i;
StringData *s = StringData::GetStaticString(info->m_name);
Class::s_extClassHash[s] = info;
@@ -6978,13 +7017,13 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
assert(pending.empty());
}
for (unsigned int i = 0LL; i < classEntries.size(); ++i) {
for (unsigned int i = 0; i < classEntries.size(); ++i) {
Entry& e = classEntries[i];
StringData* parentName =
StringData::GetStaticString(e.ci->getParentClass().get());
PreClassEmitter* pce = ue->newPreClassEmitter(e.name,
PreClass::AlwaysHoistable);
pce->init(0, 0, ue->bcPos(), AttrUnique | AttrPersistent, parentName, NULL);
pce->init(0, 0, ue->bcPos(), AttrUnique | AttrPersistent, parentName, nullptr);
pce->setBuiltinClassInfo(e.ci, e.info->m_InstanceCtor, e.info->m_sizeof);
{
ClassInfo::InterfaceVec intfVec = e.ci->getInterfacesVec();
@@ -7013,7 +7052,7 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
const ClassInfo::MethodInfo* mi =
e.ci->getMethodInfo(std::string(methodInfo->m_name));
Offset base = ue->bcPos();
fe->setBuiltinFunc(mi, bcf, NULL, base);
fe->setBuiltinFunc(mi, bcf, nullptr, base);
ue->emitOp(OpNativeImpl);
}
Offset past = ue->bcPos();
@@ -7062,7 +7101,7 @@ static UnitEmitter* emitHHBCVisitor(AnalysisResultPtr ar, FileScopeRawPtr fsp) {
}
UnitEmitter* ue = emitHHBCUnitEmitter(ar, fsp, md5);
assert(ue != NULL);
assert(ue != nullptr);
if (Option::GenerateTextHHBC) {
std::unique_ptr<Unit> unit(ue->create());
@@ -7087,7 +7126,7 @@ static UnitEmitter* emitHHBCVisitor(AnalysisResultPtr ar, FileScopeRawPtr fsp) {
class UEQ : public Synchronizable {
public:
void push(UnitEmitter* ue) {
assert(ue != NULL);
assert(ue != nullptr);
Lock lock(this);
m_ues.push_back(ue);
notify();
@@ -7097,12 +7136,12 @@ class UEQ : public Synchronizable {
if (m_ues.empty()) {
// Check for empty() after wait(), in case of spurious wakeup.
if (!wait(sec, nsec) || m_ues.empty()) {
return NULL;
return nullptr;
}
}
assert(m_ues.size() > 0);
UnitEmitter* ue = m_ues.front();
assert(ue != NULL);
assert(ue != nullptr);
m_ues.pop_front();
return ue;
}
@@ -7264,7 +7303,7 @@ void emitAllHHBC(AnalysisResultPtr ar) {
// Poll, but with a 100ms timeout so that this thread doesn't spin wildly
// if it gets ahead of the workers.
UnitEmitter* ue = s_ueq.tryPop(0, 100 * 1000 * 1000);
if ((didPop = (ue != NULL))) {
if ((didPop = (ue != nullptr))) {
ues.push_back(ue);
}
if (ues.size() == kBatchSize
@@ -7306,6 +7345,7 @@ Unit* hphp_compiler_parse(const char* code, int codeLen, const MD5& md5,
for (auto& i : RuntimeOption::DynamicInvokeFunctions) {
Option::DynamicInvokeFunctions.insert(i);
}
Option::RecordErrors = false;
Option::OutputHHBC = true;
Option::ParseTimeOpts = false;
Option::WholeProgram = false;
@@ -7315,7 +7355,7 @@ Unit* hphp_compiler_parse(const char* code, int codeLen, const MD5& md5,
BuiltinSymbols::Load(ar, true);
BuiltinSymbols::NoSuperGlobals = false;
TypeConstraint tc;
return NULL;
return nullptr;
}
try {
@@ -7350,15 +7390,13 @@ Unit* hphp_compiler_parse(const char* code, int codeLen, const MD5& md5,
fsp->analyzeProgram(ar);
UnitEmitter* ue = emitHHBCUnitEmitter(ar, fsp, md5);
if (RuntimeOption::RepoCommit) {
Repo::get().commitUnit(ue, unitOrigin);
}
Repo::get().commitUnit(ue, unitOrigin);
Unit* unit = ue->create();
delete ue;
return unit;
} catch (const std::exception&) {
// extern "C" function should not be throwing exceptions...
return NULL;
return nullptr;
}
}
@@ -379,12 +379,20 @@ public:
EXCEPTION_COMMON_IMPL(IncludeTimeFatalException);
};
void pushIterId(Id id) { m_pendingIters.push_back(id); }
void popIterId() { m_pendingIters.pop_back(); }
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<Id> IdVec;
typedef std::vector<std::pair<Id,IterKind> > PendingIterVec;
class PostponedMeth {
public:
PostponedMeth(MethodStatementPtr m, FuncEmitter* fe, bool top,
@@ -427,10 +435,12 @@ private:
};
class ControlTargets {
public:
ControlTargets(Id itId, Label& brkTarg, Label& cntTarg, Label& brkHand,
Label& cntHand) : m_itId(itId), m_brkTarg(brkTarg), m_cntTarg(cntTarg),
m_brkHand(brkHand), m_cntHand(cntHand) {}
ControlTargets(Id itId, bool itRef, Label& brkTarg, Label& cntTarg,
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;"
@@ -438,9 +448,9 @@ private:
};
class ControlTargetPusher {
public:
ControlTargetPusher(EmitterVisitor* e, Id itId, Label& brkTarg,
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, brkTarg, cntTarg,
e->m_contTargets.push_front(ControlTargets(itId, itRef, brkTarg, cntTarg,
brkHand, cntHand));
}
~ControlTargetPusher() {
@@ -505,7 +515,7 @@ private:
std::deque<PostponedNonScalars> m_postponedSinits;
std::deque<PostponedNonScalars> m_postponedCinits;
std::deque<PostponedClosureCtor> m_postponedClosureCtors;
IdVec m_pendingIters;
PendingIterVec m_pendingIters;
typedef std::map<const StringData*, Label*, string_data_lt> LabelMap;
LabelMap m_methLabels;
SymbolicStack m_evalStack;
@@ -535,6 +545,12 @@ public:
void buildVectorImm(std::vector<uchar>& vectorImm,
int iFirst, int iLast, bool allowW,
Emitter& e);
enum class PassByRefKind {
AllowCell,
WarnOnCell,
ErrorOnCell,
};
PassByRefKind getPassByRefKind(ExpressionPtr exp);
void emitAGet(Emitter& e);
void emitCGetL2(Emitter& e);
void emitCGetL3(Emitter& e);
@@ -561,6 +577,7 @@ public:
void emitConvertToCellOrLoc(Emitter& e);
void emitConvertSecondToCell(Emitter& e);
void emitConvertToVar(Emitter& e);
void emitFPass(Emitter& e, int paramID, PassByRefKind passByRefKind);
void emitVirtualLocal(int localId, DataType dt = KindOfUnknown);
template<class Expr> void emitVirtualClassBase(Emitter&, Expr* node);
void emitResolveClsBase(Emitter& e, int pos);
@@ -587,7 +604,7 @@ public:
void emitAssignment(Emitter& e, ExpressionPtr c, int op, bool bind);
void emitListAssignment(Emitter& e, ListAssignmentPtr lst);
void postponeMeth(MethodStatementPtr m, FuncEmitter* fe, bool top,
ClosureUseVarVec* useVars = NULL);
ClosureUseVarVec* useVars = nullptr);
void postponeCtor(InterfaceStatementPtr m, FuncEmitter* fe);
void postponePinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
void postponeSinit(InterfaceStatementPtr m, FuncEmitter* fe, NonScalarVec* v);
@@ -622,7 +639,8 @@ public:
PreClass::Hoistable emitClass(Emitter& e, ClassScopePtr cNode,
bool topLevel);
void emitBreakHandler(Emitter& e, Label& brkTarg, Label& cntTarg,
Label& brkHand, Label& cntHand, Id iter = -1);
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);
@@ -425,7 +425,7 @@ void FunctionContainer::outputCPPCodeInfoTable(
vector<const char *> funcs;
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
if (system) {
outputCPPCallInfoTableSupport(cg, ar, 0, needGlobals, NULL);
outputCPPCallInfoTableSupport(cg, ar, 0, needGlobals, nullptr);
}
for (StringToFunctionScopePtrMap::const_iterator iter = functions.begin(),
end = functions.end(); iter != end; ++iter) {
@@ -64,14 +64,14 @@ protected:
void outputCPPJumpTableSupport(CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec,
bool &hasRedeclared,
std::vector<const char *> *funcs = NULL);
std::vector<const char *> *funcs = nullptr);
void outputCPPJumpTableEvalSupport(
CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec, bool &hasRedeclared);
void outputCPPCallInfoTableSupport(
CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec,
bool &hasRedeclared, std::vector<const char *> *funcs = NULL);
bool &hasRedeclared, std::vector<const char *> *funcs = nullptr);
void outputCPPJumpTableSupportMethod(CodeGenerator &cg, AnalysisResultPtr ar,
FunctionScopePtr func,
const char *funcPrefix);
@@ -2165,7 +2165,7 @@ void FunctionScope::outputCPPCallInfo(CodeGenerator &cg,
Option::InvokePrefix, id.c_str(),
Option::InvokeFewArgsPrefix, id.c_str());
}
cg.printf(", %d, %d, 0x%.16llXLL", m_maxParam, flags, refflags);
cg.printf(", %d, %d, 0x%.16llXL", m_maxParam, flags, refflags);
if (isRedeclaring()) {
cg_printf("}, %d", getRedeclaringId());
}
@@ -2458,24 +2458,27 @@ FunctionScope::StringToFunctionInfoPtrMap FunctionScope::s_refParamInfo;
static Mutex s_refParamInfoLock;
void FunctionScope::RecordFunctionInfo(string fname, FunctionScopePtr func) {
if (!Option::WholeProgram) return; // Only needed in WholeProgram mode.
Lock lock(s_refParamInfoLock);
FunctionInfoPtr &info = s_refParamInfo[fname];
if (!info) {
info = FunctionInfoPtr(new FunctionInfo());
}
if (func->isStatic()) {
info->setMaybeStatic();
}
if (func->isRefReturn()) {
info->setMaybeRefReturn();
}
if (func->isReferenceVariableArgument()) {
info->setRefVarArg(func->getMaxParamCount());
}
VariableTablePtr variables = func->getVariables();
if (Option::WholeProgram) {
Lock lock(s_refParamInfoLock);
FunctionInfoPtr &info = s_refParamInfo[fname];
if (!info) {
info = FunctionInfoPtr(new FunctionInfo());
}
if (func->isStatic()) {
info->setMaybeStatic();
}
if (func->isRefReturn()) {
info->setMaybeRefReturn();
}
if (func->isReferenceVariableArgument()) {
info->setRefVarArg(func->getMaxParamCount());
}
for (int i = 0; i < func->getMaxParamCount(); i++) {
if (func->isRefParam(i)) info->setRefParam(i);
}
}
for (int i = 0; i < func->getMaxParamCount(); i++) {
if (func->isRefParam(i)) info->setRefParam(i);
variables->addParam(func->getParamName(i),
TypePtr(), AnalysisResultPtr(), ConstructPtr());
}
@@ -407,9 +407,9 @@ public:
bool voidWrapperOff = false,
bool fewArgs = false,
bool ret = true,
const char *extraArg = NULL,
const char *extraArg = nullptr,
bool constructor = false,
const char *instance = NULL,
const char *instance = nullptr,
const char *class_name = "");
void outputCPPDef(CodeGenerator &cg);
@@ -452,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) {
+876
Ver Arquivo
@@ -0,0 +1,876 @@
/*
+----------------------------------------------------------------------+
| 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;
}
string Type::getCPPDecl(AnalysisResultConstPtr ar,
BlockScopeRawPtr scope,
CodeGenerator *cg /* = 0 */) {
switch (m_kindOf) {
case KindOfBoolean: return "bool";
case KindOfInt32: return "int";
case KindOfInt64: return "int64";
case KindOfDouble: return "double";
case KindOfString: return "String";
case KindOfArray: return "Array";
case KindOfObject:{
ClassScopePtr cls(getClass(ar, scope));
if (!cls) return "Object";
if (cg && cg->isFileOrClassHeader() && scope) {
if (scope->getContainingClass()) {
scope->getContainingClass()->addUsedClassHeader(cls);
} else if (scope->getContainingFile()) {
scope->getContainingFile()->addUsedClassHeader(cls);
}
}
return Option::SmartPtrPrefix + cls->getId();
}
case KindOfNumeric: return "Numeric";
case KindOfPrimitive: return "Primitive";
case KindOfPlusOperand: return "PlusOperand";
case KindOfSequence: return "Sequence";
default:
return "Variant";
}
}
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();
}
}
void Type::outputCPPDecl(CodeGenerator &cg, AnalysisResultConstPtr ar,
BlockScopeRawPtr scope) {
cg_print(getCPPDecl(ar, scope, &cg).c_str());
}
void Type::outputCPPFastObjectCast(CodeGenerator &cg,
AnalysisResultConstPtr ar,
BlockScopeRawPtr scope,
bool isConst) {
assert(isSpecificObject());
ClassScopePtr cls(getClass(ar, scope));
assert(cls);
const string &cppClsName = cls->getId();
cg_printf("(%s%s%s&)",
isConst ? "const " : "",
Option::SmartPtrPrefix,
cppClsName.c_str());
}
void Type::outputCPPCast(CodeGenerator &cg, AnalysisResultConstPtr ar,
BlockScopeRawPtr scope) {
switch (m_kindOf) {
case KindOfBoolean: cg_printf("toBoolean"); break;
case KindOfInt32: cg_printf("toInt32"); break;
case KindOfInt64: cg_printf("toInt64"); break;
case KindOfDouble: cg_printf("toDouble"); break;
case KindOfString: cg_printf("toString"); break;
case KindOfArray: cg_printf("toArray"); break;
case KindOfNumeric: cg_printf("Numeric"); break;
case KindOfPrimitive: cg_printf("Primitive"); break;
case KindOfPlusOperand: cg_printf("PlusOperand"); break;
case KindOfSequence: cg_printf("Sequence"); break;
case KindOfObject: {
ClassScopePtr cls(getClass(ar, scope));
if (!cls) {
cg_printf("toObject");
} else {
cg_printf("%s%s", Option::SmartPtrPrefix, cls->getId().c_str());
}
break;
}
default:
cg_printf("Variant");
break;
}
}
const char *Type::getCPPInitializer() {
switch (m_kindOf) {
case KindOfBoolean: return "false";
case KindOfInt32:
case KindOfInt64: return "0";
case KindOfNumeric:
case KindOfPrimitive:
case KindOfPlusOperand: return "0";
case KindOfDouble: return "0.0";
default: return nullptr;
}
}
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();
}
@@ -527,7 +527,7 @@ Symbol *VariableTable::findProperty(ClassScopePtr &cls,
return sym;
}
assert(!sym->isStatic());
sym = NULL;
sym = nullptr;
}
if (!sym) {
@@ -733,7 +733,7 @@ bool VariableTable::isConvertibleSuperGlobal(const string &name) const {
ClassScopePtr VariableTable::findParent(AnalysisResultConstPtr ar,
const string &name,
const Symbol *&sym) const {
sym = NULL;
sym = nullptr;
for (ClassScopePtr parent = m_blockScope.getParentScope(ar);
parent && !parent->isRedeclaring();
parent = parent->getParentScope(ar)) {
@@ -1302,7 +1302,7 @@ void VariableTable::outputCPPGVHashTableGetImpl(CodeGenerator &cg,
string escaped = CodeGenerator::EscapeLabel(name);
string varName = string("gvm_") + CodeGenerator::FormatLabel(name);
cg_printf(" (const char *)\"%s\",\n"
" (const char *)%lld,\n"
" (const char *)%" PRId64 ",\n"
" (const char *)GET_GV_OFFSET(%s),\n"
" (const char *)%u,\n",
escaped.c_str(),
@@ -1625,7 +1625,7 @@ void VariableTable::outputCPPVariableTable(CodeGenerator &cg,
if (m_forcedVariants) {
cg_indentBegin("virtual Variant &getImpl(CStrRef s) {\n");
if (!outputCPPJumpTable(cg, ar, NULL, true, true, EitherStatic,
if (!outputCPPJumpTable(cg, ar, nullptr, true, true, EitherStatic,
JumpReturnString)) {
m_emptyJumpTables.insert(JumpTableLocalGetImpl);
}
@@ -1634,7 +1634,7 @@ void VariableTable::outputCPPVariableTable(CodeGenerator &cg,
if (getAttribute(ContainsExtract)) {
cg_indentBegin("virtual bool exists(CStrRef s) const {\n");
if (!outputCPPJumpTable(cg, ar, NULL, true, false,
if (!outputCPPJumpTable(cg, ar, nullptr, true, false,
EitherStatic, JumpInitializedString)) {
m_emptyJumpTables.insert(JumpTableLocalExists);
}
@@ -1643,7 +1643,7 @@ void VariableTable::outputCPPVariableTable(CodeGenerator &cg,
}
} else {
cg_indentBegin("virtual Variant getImpl(CStrRef s) {\n");
if (!outputCPPJumpTable(cg, ar, NULL, true, false, EitherStatic,
if (!outputCPPJumpTable(cg, ar, nullptr, true, false, EitherStatic,
JumpReturnString)) {
m_emptyJumpTables.insert(JumpTableLocalGetImpl);
}
@@ -1653,7 +1653,7 @@ void VariableTable::outputCPPVariableTable(CodeGenerator &cg,
if (getAttribute(ContainsCompact)) {
cg_indentBegin("virtual bool exists(CStrRef s) const {\n");
if (!outputCPPJumpTable(cg, ar, NULL, true, false,
if (!outputCPPJumpTable(cg, ar, nullptr, true, false,
EitherStatic, JumpInitializedString)) {
m_emptyJumpTables.insert(JumpTableLocalExists);
}
@@ -394,7 +394,7 @@ private:
bool variantOnly, StaticSelection staticVar,
JumpTableType type = JumpReturn,
PrivateSelection privateVar = NonPrivate,
bool *declaredGlobals = NULL);
bool *declaredGlobals = nullptr);
bool outputCPPPrivateSelector(CodeGenerator &cg, AnalysisResultPtr ar,
const char *op, const char *args);
void outputCPPVariableInit(CodeGenerator &cg, AnalysisResultPtr ar,
@@ -60,21 +60,21 @@ 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
@@ -109,14 +109,14 @@ 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;
void *BuiltinSymbols::s_handle_main = NULL;
void *BuiltinSymbols::s_handle_main = nullptr;
///////////////////////////////////////////////////////////////////////////////
@@ -150,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++;
@@ -277,7 +277,7 @@ 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++;
@@ -342,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",
@@ -358,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) {
@@ -60,11 +60,11 @@ const char *CodeGenerator::HASH_INCLUDE =
CodeGenerator::CodeGenerator(std::ostream *primary,
Output output /* = PickledPHP */,
const std::string *filename /* = NULL */)
: m_out(NULL), m_output(output),
: m_out(nullptr), m_output(output),
m_hoistedClasses(0), m_collectHoistedClasses(false),
m_context(NoContext), m_insideScalarArray(false), m_itemIndex(-1) {
for (int i = 0; i < StreamCount; i++) {
m_streams[i] = NULL;
m_streams[i] = nullptr;
m_indentation[i] = 0;
m_indentPending[i] = true;
m_lineNo[i] = 1;
@@ -87,7 +87,7 @@ void CodeGenerator::useStream(Stream stream) {
assert(stream >= NullStream && stream < StreamCount);
m_curStream = stream;
if (stream == NullStream) {
m_out = NULL;
m_out = nullptr;
} else {
m_out = m_streams[stream];
}
@@ -132,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.
@@ -196,7 +196,7 @@ public:
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
@@ -887,11 +887,11 @@ void hhbcTargetInit(const CompilerOptions &po, AnalysisResultPtr ar) {
ar->setOutputPath(po.syncDir);
}
// Propagate relevant compiler-specific options to the runtime.
RuntimeOption::RepoLocalPath = ar->getOutputPath() + '/' + po.program;
RuntimeOption::RepoCentralPath = ar->getOutputPath() + '/' + po.program;
if (po.format.find("exe") != string::npos) {
RuntimeOption::RepoLocalPath += ".hhbc";
RuntimeOption::RepoCentralPath += ".hhbc";
}
RuntimeOption::RepoLocalMode = "rw";
RuntimeOption::RepoLocalMode = "--";
RuntimeOption::RepoDebugInfo = Option::RepoDebugInfo;
RuntimeOption::RepoJournal = "memory";
RuntimeOption::EnableHipHopSyntax = Option::EnableHipHopSyntax;
@@ -960,7 +960,7 @@ int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
const char *argv[] = { "objcopy", "--add-section", repo.c_str(),
buf, exe.c_str(), 0 };
string out;
ret = Process::Exec(argv[0], argv, NULL, out, NULL) ? 0 : 1;
ret = Process::Exec(argv[0], argv, nullptr, out, nullptr) ? 0 : 1;
}
return ret;
@@ -1007,7 +1007,7 @@ int cppTarget(const CompilerOptions &po, AnalysisResultPtr ar,
Timer timer(Timer::WallTime, "creating CPP files");
if (po.syncDir.empty()) {
ar->setOutputPath(po.outputDir);
ar->outputAllCPP(format, clusterCount, NULL);
ar->outputAllCPP(format, clusterCount, nullptr);
} else {
ar->setOutputPath(po.syncDir);
ar->outputAllCPP(format, clusterCount, &po.outputDir);
@@ -1036,7 +1036,7 @@ int buildTarget(const CompilerOptions &po) {
if (!HPHP_HOME || !*HPHP_HOME) {
throw Exception("Environment variable HPHP_HOME is not set.");
}
string cmd = string(HPHP_HOME) + "/src/legacy/run.sh";
string cmd = string(HPHP_HOME) + "/hphp/legacy/run.sh";
string flags;
if (getenv("RELEASE")) flags += "RELEASE=1 ";
if (getenv("SHOW_LINK")) flags += "SHOW_LINK=1 ";
@@ -1044,7 +1044,7 @@ int buildTarget(const CompilerOptions &po) {
if (po.format == "lib") flags += "HPHP_BUILD_LIBRARY=1 ";
if (Option::GenerateFFI) flags += "HPHP_BUILD_FFI=1 ";
const char *argv[] = {"", po.outputDir.c_str(),
po.program.c_str(), flags.c_str(), NULL};
po.program.c_str(), flags.c_str(), nullptr};
if (getenv("SHOW_COMPILE")) {
Logger::Info ("Compile command: %s %s %s", po.outputDir.c_str(),
@@ -1052,7 +1052,7 @@ int buildTarget(const CompilerOptions &po) {
}
Timer timer(Timer::WallTime, "compiling and linking CPP files");
string out, err;
bool ret = Process::Exec(cmd.c_str(), argv, NULL, out, &err);
bool ret = Process::Exec(cmd.c_str(), argv, nullptr, out, &err);
if (getenv("SHOW_COMPILE")) {
Logger::Info("%s", out.c_str());
} else {
@@ -364,7 +364,7 @@ void Construct::dumpNode(int spc) {
}
string refstr;
if (dynamic_cast<SimpleVariable*>(this) != NULL) {
if (dynamic_cast<SimpleVariable*>(this) != nullptr) {
if (isReferencedValid()) {
if (isReferenced()) {
refstr += ",Referenced";
@@ -380,7 +380,7 @@ void Construct::dumpNode(int spc) {
if (refstr != "") refstr = " (" + refstr.substr(1) + ")";
string objstr;
if (dynamic_cast<SimpleVariable*>(this) != NULL) {
if (dynamic_cast<SimpleVariable*>(this) != nullptr) {
if (isNeededValid()) {
if (isNeeded()) {
objstr += "Object";
@@ -164,7 +164,7 @@ bool ArrayPairExpression::outputCPPName(CodeGenerator &cg,
string s = sc->getLiteralString();
int64 res;
if (is_strictly_integer(s.c_str(), s.size(), res)) {
cg_printf("%sLL", s.c_str());
cg_printf("%sL", s.c_str());
} else {
m_name->outputCPP(cg, ar);
}
@@ -489,7 +489,7 @@ void AssignmentExpression::outputCPPImpl(CodeGenerator &cg,
bool setNull = false;
if (SpecialAssignment(cg, ar, m_variable, m_value, NULL, ref)) {
if (SpecialAssignment(cg, ar, m_variable, m_value, nullptr, ref)) {
return;
}
@@ -37,7 +37,7 @@ ClassConstantExpression::ClassConstantExpression
ExpressionPtr classExp, const std::string &varName)
: Expression(
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ClassConstantExpression)),
StaticClassName(classExp), m_varName(varName), m_defScope(NULL),
StaticClassName(classExp), m_varName(varName), m_defScope(nullptr),
m_valid(false), m_depsSet(false) {
}
@@ -255,7 +255,7 @@ TypePtr ConstantExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
// read value and dynamic-ness together + check() atomically
value = constants->getValue(m_name);
isDynamic = constants->isDynamic(m_name);
BlockScope *defScope = NULL;
BlockScope *defScope = nullptr;
std::vector<std::string> bases;
actualType = constants->check(getScope(), m_name, type, coerce,
ar, self, bases, defScope);
@@ -484,7 +484,7 @@ TypePtr Expression::inferAssignmentTypes(AnalysisResultPtr ar, TypePtr type,
// ...as in ClassConstant statement
ConstantExpressionPtr exp =
dynamic_pointer_cast<ConstantExpression>(variable);
BlockScope *defScope = NULL;
BlockScope *defScope = nullptr;
std::vector<std::string> bases;
scope->getConstants()->check(getScope(), exp->getName(), ret,
true, ar, variable,
@@ -124,7 +124,7 @@ bool ExpressionList::isScalar() const {
bool ExpressionList::isNoObjectInvolved() const {
for (unsigned int i = 0; i < m_exps.size(); i++) {
TypePtr t = m_exps[i]->getActualType();
if (t == NULL || !t->isNoObjectInvolved())
if (t == nullptr || !t->isNoObjectInvolved())
return false;
}
return true;
@@ -674,7 +674,7 @@ void ExpressionList::outputCPPUniqLitKeyArrayInit(
bool arrayElements /* = true */, unsigned int start /* = 0 */) {
if (arrayElements) assert(m_arrayElements && !m_collectionType);
unsigned int n = m_exps.size();
cg_printf("array_createv%c(%lld, ", litstrKeys ? 's' : 'i', num);
cg_printf("array_createv%c(%" PRId64 ", ", litstrKeys ? 's' : 'i', num);
always_assert(n - start == num);
for (unsigned int i = start; i < n; i++) {
ExpressionPtr exp = m_exps[i];
@@ -59,10 +59,9 @@ FunctionCall::FunctionCall
m_nameExp->getKindOf() == Expression::KindOfScalarExpression) {
assert(m_name.empty());
ScalarExpressionPtr c = dynamic_pointer_cast<ScalarExpression>(m_nameExp);
m_origName = c->getString();
m_origName = c->getOriginalLiteralString();
c->toLower(true /* func call*/);
m_name = c->getString();
assert(!m_name.empty());
m_name = c->getLiteralString();
} else {
m_origName = name;
m_name = Util::toLower(name);
@@ -38,7 +38,7 @@ ObjectPropertyExpression::ObjectPropertyExpression
: Expression(
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ObjectPropertyExpression)),
LocalEffectsContainer(AccessorEffect),
m_object(object), m_property(property), m_propSym(NULL) {
m_object(object), m_property(property), m_propSym(nullptr) {
m_valid = false;
m_propSymValid = false;
m_object->setContext(Expression::ObjectContext);
@@ -72,7 +72,10 @@ bool ObjectPropertyExpression::isNonPrivate(AnalysisResultPtr ar) {
}
ScalarExpressionPtr name =
dynamic_pointer_cast<ScalarExpression>(m_property);
string propName = name->getString();
string propName = name->getLiteralString();
if (propName.empty()) {
return false;
}
Symbol *sym = cls->getVariables()->getSymbol(propName);
if (!sym || sym->isStatic() || !sym->isPrivate()) return true;
return false;
@@ -200,20 +203,24 @@ TypePtr ObjectPropertyExpression::inferTypes(AnalysisResultPtr ar,
if (!m_property->is(Expression::KindOfScalarExpression)) {
m_property->inferAndCheck(ar, Type::String, false);
// we also lost track of which class variable an expression is about, hence
// any type inference could be wrong. Instead, we just force variants on
// all class variables.
if (m_context & (LValue | RefValue)) {
ar->forceClassVariants(getOriginalClass(), false, true);
}
return Type::Variant; // we have to use a variant to hold dynamic value
}
ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>(m_property);
const string &name = exp->getString();
assert(!name.empty());
const string &name = exp->getLiteralString();
if (name.empty()) {
m_property->inferAndCheck(ar, Type::String, false);
if (m_context & (LValue | RefValue)) {
ar->forceClassVariants(getOriginalClass(), false, true);
}
return Type::Variant; // we have to use a variant to hold dynamic value
}
m_property->inferAndCheck(ar, Type::String, false);
@@ -456,7 +463,7 @@ void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg,
}
cg_printf("(((%s%s*)obj_tmp)->%s%s)",
Option::ClassPrefix, cls->getId().c_str(),
Option::PropertyPrefix, name->getString().c_str());
Option::PropertyPrefix, name->getLiteralString().c_str());
if (!write_context) {
cg_printf(" : (raise_null_object_prop(),%s)",
@@ -483,7 +490,8 @@ void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg,
m_object->getActualType()->isSpecificObject());
ScalarExpressionPtr name =
dynamic_pointer_cast<ScalarExpression>(m_property);
cg_printf("%s%s", Option::PropertyPrefix, name->getString().c_str());
cg_printf("%s%s", Option::PropertyPrefix,
name->getLiteralString().c_str());
if (doExist || doUnset) cg_printf(")");
} else {
cg_printf("%s(", func.c_str());
@@ -628,10 +636,13 @@ void ObjectPropertyExpression::outputCPPProperty(CodeGenerator &cg,
if (m_property->getKindOf() == Expression::KindOfScalarExpression) {
ScalarExpressionPtr name =
dynamic_pointer_cast<ScalarExpression>(m_property);
cg_printString(name->getString(), ar, shared_from_this());
} else {
m_property->outputCPP(cg, ar);
string propName = name->getLiteralString();
if (!propName.empty()) {
cg_printString(propName, ar, shared_from_this());
return;
}
}
m_property->outputCPP(cg, ar);
}
void ObjectPropertyExpression::outputCPPExistTest(CodeGenerator &cg,

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