203 Commits

Autor SHA1 Mensagem Data
Sara Golemon d660972153 HPHP 2.0.1 2013-03-22 19:14:35 -07:00
ptarjan ca437add64 fix this callsite incase someone ever does the TODO for setting valueClass() 2013-03-25 13:59:21 -07:00
mwilliams 3611bf3d58 Fix getContextClassName and getParentContextClassName
They both returned the late static bound class, not the context
class. This meant that eg "constant('self::FOO')" was actually
returning what "constant('static::FOO')" should have done.

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

Finally, noticed that while "defined()" was recently fixed to
support "static::", "constant()" was not. Pulled out a common
function to find the correct Class*.
2013-03-25 13:59:02 -07:00
jan 565c8477f8 Fix ref generator parameters
Alias manager does not know whether generator parameters are passed by
reference. This didn't matter, because every generator had at least one
function call (hphp_continuation_done()) that pretty much disabled unused
variable elimination.

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

We raise a lot of strict_warnings; and when we fix hphpiCompat
(to match zend better) we will raise a lot more, so this could
matter.
2013-03-22 13:57:18 -07:00
ottoni 7241c247dd Disable spilling into MMX registers 2013-03-22 13:57:06 -07:00
jan f06575d4e2 Fix local propagation of generator parameters
Alias manager does not know that generator parameters are populated and
assumes they are uninit. The current code works because control flow
algorithm gives up while trying to deal with the continuation switch
statement full of gotos.

This diff fixes it by setting isGeneratorParameter flag in symbols
representing parameters of enclosing generator wrapper and use variables
of enclosing closure.
2013-03-21 20:41:02 -07:00
Owen Yamauchi cc897749f8 Fix the RIP_REGISTER macro
Pretty simple. This makes me slightly nervous because I've only
confirmed it works in my stupid OpenEmbedded ARM SDK; a different Linux
might call this something else. But we'll cross that bridge when we get
to it, and this works for now.

I'm also sneaking in a change to remove x29 from the list of
callee-saved regs; I put it in there by accident last time.
2013-03-21 20:41:02 -07:00
ptarjan b597e3a753 fix static closures
I added the check for this in the interpreter but ##f_array_map## re-enteres the VM via a different path than FCall. Here is the equivilent check for the VM.
2013-03-21 20:41:02 -07:00
mwilliams 8ec621676d Fix args for embedded repo
When we generate a binary with an embedded repo,
we add various args (-vRepo.Authoritative etc) to the end
of the command line. But the argument "--" is taken to mean
"pass the rest of the args to the script". So if you use
"--" on such a binary, it gets rather badly broken.

Reorder the args so that the inserted ones come first.
2013-03-21 20:41:02 -07:00
mwilliams a134b25671 Fix nemo warnings about undefined $this
The fix for the crash caused us to take a different path
when checking locals.
2013-03-21 20:41:01 -07:00
mwilliams 15fa1ebfde Fix StringBuffer::resize()
capacity doesnt include the terminating null, so len is
allowed to grow to capacity (not capacity - 1).
2013-03-19 14:47:25 -07:00
mwilliams ce75713972 Fix assertion when target==analyze
Option::OutputHHBC should always be true.
2013-03-19 14:47:15 -07:00
Owen Yamauchi adc56c6d8c Fix includes in curl_tls_workarounds.cpp
raise_notice() wasn't declared in this file, so include runtime_error.h.
This caused further problems with ATTRIBUTE_PRINTF not being defined
yet, so include some more stuff.
2013-03-19 14:47:06 -07:00
Sara Golemon 3fb0fe8a6a SSL_OP_NO_TLSv1_2 is not supported by all openssl versions 2013-03-18 18:38:47 -07:00
ottoni 38306b527f SIMPLIFY_COMMUTATIVE only handles Type::Int
So check that the inputs are really Ints.
2013-03-18 18:38:37 -07:00
aravind e4e3bee5d3 Don't simplify Same to Eq to arrays 2013-03-18 18:38:29 -07:00
michalburger1 d25adc550b Fix bzdecompress
Bad memory allocation, the buffer needs to be large enough to fit all
the data we've decompressed so far plus the extra storage we're
incrementally allocationg, not just the incremental part.
2013-03-18 16:20:44 -07:00
Sara Golemon 8b23419a37 HPHP version 2.0.0 2013-03-14 16:00:42 -07:00
ottoni af5623b4fc Properly patch exit traces ending with JmpZero and JmpNZero
The hoistConditionalJumps pass was not handling traces ending with
JmpZero and JmpNZero.  This was resulting in spurious jumps to
'astubs' instead of patching the jcc+jump pair in 'a'.
2013-03-14 15:45:51 -07:00
ptarjan b51003b5aa tell closures about scope clones
In HHBC mode, traits are flattened into their classes.
When that happens, closures need to know about all the
classes that contain them so that when we find a ##$this##
inside the closure, it can tell EVERY containing scope to
please propogate ##$this## down to me.
2013-03-14 15:45:40 -07:00
mwilliams 5f019f5b43 Fix CodeGenerator::cgNInstanceOf
It assumed the result would be in rax, but it isnt always.
Use the correct register.
2013-03-13 10:16:23 -07:00
bertrand 35e347efa5 Fixed ContNext by writing InitNull rather than Uninit.
Apparently, m_received needs to be InitNull, rather than
Uninit.
2013-03-13 10:16:14 -07:00
Sara Golemon 6169f73d80 TCP ports should be unsigned 16 bit integers.
Summary:
Specifying Signed 16-bit Int in HDF parsing
prevents use of any port greater than 32767.

Test Plan: Run a server on port 40000

Reviewers: andrewparoski, jdelong, smith, kma, mwilliams

Reviewed By: jdelong

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

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

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

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

For a release build:
  cmake -DCMAKE_BUILD_TYPE=Release .

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

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

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

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

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

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

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

  static $foo;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

There are multiple problems with this approach:

1. Unability to exit contet safely

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

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

2. Unability to break edge that caused the cycle

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

Solution:

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

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

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

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

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

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

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

Implemented code gen for Unbox and cleaned up its
simplification.

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

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

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

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

Emit inc/dec x86 instructions in some cases.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

To checkout the commit immediately prior to this:
git checkout use-hphpc
2013-02-19 13:41:26 -08:00
hermanv 9cb2d7af85 Add support for UTS #46, along the lines of Zend, to idn_to_ascii.
Removes the output errorCode parameter (that is not currently used anywhere, except in testing code that gets but ignores it). Adds the options, variant and
idna_info parameters that are present in the Zend version of idn_to_ascii. Implement the new functionality required by these parameters by using the UTS #46 API, if
present.
2013-02-19 13:41:26 -08:00
ptarjan 6a311f2fab make test filters consistent 2013-02-19 13:41:08 -08:00
1248 arquivos alterados com 110163 adições e 220981 exclusões
-1
Ver Arquivo
@@ -32,7 +32,6 @@ hphp.log
/hphp/runtime/tmp/run.sh
/hphp/runtime/tmp/libtest.so
/hphp/runtime/vm/repo_schema.h
/hphp/runtime/base/compiler_id.h
/hphp/hphpi/gen
/hphp/hphpi/hphpi
+1 -6
Ver Arquivo
@@ -19,12 +19,7 @@ include(CheckFunctionExists)
# boost checks
find_package(Boost 1.37.0 COMPONENTS system;program_options;filesystem REQUIRED)
if (BOOST_VERSION EQUAL 104200)
# Boost bug #3942 prevents us using 1.42
message(FATAL_ERROR "Boost 1.42 is not compatible with HipHop")
endif()
find_package(Boost 1.48.0 COMPONENTS system program_options filesystem regex REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
+5
Ver Arquivo
@@ -50,6 +50,11 @@ add_definitions(-DHHVM_LIB_PATH_DEFAULT="${HPHP_HOME}/bin")
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
add_definitions(-DRELEASE=1)
add_definitions(-DNDEBUG)
message("Generating Release build")
else()
add_definitions(-DDEBUG)
message("Generating DEBUG build")
endif()
if(INFINITE_LOOP_DETECTION)
+1 -1
Ver Arquivo
@@ -30,5 +30,5 @@ if ("$ENV{USE_HHVM}" STREQUAL "1")
message("Building for HHVM")
endif()
if ("$ENV{USE_HPHPC}" STREQUAL "1")
message("Building for HPHPc")
message(FATAL_ERROR "Building HPHPc is no longer supported")
endif()
+6 -2
Ver Arquivo
@@ -31,13 +31,17 @@ The latest information is available on the [wiki](http://wiki.github.com/faceboo
* libexpat
* libmemcached
* google-glog (http://code.google.com/p/google-glog/)
* libc-client2007
* libdwarf
* libelf
* libunwind
The following packages have had slight modifications added to them. Patches are provided and should be made against the current source copies.
* [libcurl](http://curl.haxx.se/download.html)
* src/third_party/libcurl.fb-changes.diff
* hphp/third_party/libcurl.fb-changes.diff
* [libevent 1.4](http://www.monkey.org/~provos/libevent/)
* src/third_party/libevent-1.4.13.fb-changes.diff OR src/third_party/libevent-1.4.14.fb-changes.diff
* hphp/third_party/libevent-1.4.14.fb-changes.diff
## Installation
-11
Ver Arquivo
@@ -5566,17 +5566,6 @@ class XhprofFrame {
}
}
// Used as the base class for all closures
class Closure {
protected $__static_locals;
// Adding a dummy __sleep() to return an illegal value to make the code
// go through error handling path
public function __sleep() {
return false;
}
}
// Used as a sentinel type in 86pinit().
class __pinitSentinel {
}
+12 -95
Ver Arquivo
@@ -17,26 +17,12 @@
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\\\"")
# 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)
set(RECURSIVE_SOURCE_SUBDIRS runtime/base runtime/eval runtime/ext runtime/vm system util)
foreach (dir ${RECURSIVE_SOURCE_SUBDIRS})
auto_sources(files "*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}/${dir}")
@@ -70,70 +56,15 @@ foreach (file ${CXX_SOURCES})
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})
foreach (file ${CXX_SOURCES})
if (${file} MATCHES "ext/sep")
list(REMOVE_ITEM CXX_SOURCES ${file})
endif()
endforeach(file ${CXX_SOURCES})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
#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()
@@ -156,14 +87,6 @@ foreach (CXX_FILE ${CXX_SOURCES})
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
@@ -172,11 +95,9 @@ add_custom_command(
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})
ADD_LIBRARY(hphp_runtime_static STATIC runtime/vm/repo_schema.h ${CXX_SOURCES} ${C_SOURCES})
SET_TARGET_PROPERTIES(hphp_runtime_static PROPERTIES OUTPUT_NAME "hphp_runtime")
SET_TARGET_PROPERTIES(hphp_runtime_static PROPERTIES PREFIX "lib")
#SET_TARGET_PROPERTIES(hphp_runtime 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>")
@@ -184,11 +105,7 @@ 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(runtime/ext_hhvm)
add_subdirectory(hhvm)
if (NOT "$ENV{HPHP_NOTEST}" STREQUAL "1")
+8 -7
Ver Arquivo
@@ -1503,7 +1503,8 @@ ExpressionPtr AliasManager::canonicalizeNode(
e->is(Expression::KindOfSimpleVariable) &&
!e->isThis()) {
Symbol *s = spc(SimpleVariable, e)->getSymbol();
if (s && !s->isParameter() && !s->isClosureVar()) {
if (s && !s->isParameter() && !s->isGeneratorParameter() &&
!s->isClosureVar()) {
rep = e->makeConstant(m_arp, "null");
Compiler::Error(Compiler::UseUndeclaredVariable, e);
if (m_variables->getAttribute(VariableTable::ContainsCompact)) {
@@ -1562,9 +1563,9 @@ ExpressionPtr AliasManager::canonicalizeNode(
}
cur = next;
}
if ((!m_inCall || (!hhvm && !ae->getValue()->hasEffect())) &&
if (!m_inCall &&
ae->isUnused() && m_accessList.isLast(ae) &&
!(hhvm && Option::OutputHHBC &&
!(Option::OutputHHBC &&
e->hasAnyContext(Expression::AccessContext |
Expression::ObjectContext |
Expression::ExistContext |
@@ -1835,7 +1836,7 @@ ExpressionPtr AliasManager::canonicalizeRecur(ExpressionPtr e) {
break;
case Expression::KindOfSimpleFunctionCall:
if (!hhvm || !Option::OutputHHBC) {
if (!Option::OutputHHBC) {
SimpleFunctionCallPtr f(spc(SimpleFunctionCall, e));
if (!f->getClass()) {
if (f->getClassName().empty()) {
@@ -3324,7 +3325,7 @@ public:
b->setBit(DataFlow::PRefIn, it->second);
b->setBit(DataFlow::PInitIn, it->second);
}
updateParamInfo(m->getParams(), hhvm && Option::HardTypeHints);
updateParamInfo(m->getParams(), Option::HardTypeHints);
updateParamInfo(m->getFunctionScope()->getClosureVars(), false);
}
}
@@ -4146,9 +4147,9 @@ void AliasManager::stringOptsRecur(StatementPtr s) {
case Statement::KindOfBreakStatement:
{
BreakStatementPtr b = spc(BreakStatement, s);
int64 depth = b->getDepth();
int64_t depth = b->getDepth();
if (depth != 1) {
int64 s = m_loopInfo.size() - 1;
int64_t s = m_loopInfo.size() - 1;
if (s >= 0) {
if (!depth || depth > s) depth = s;
while (depth--) {
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+5 -260
Ver Arquivo
@@ -166,28 +166,6 @@ public:
void inferTypes();
void postOptimize();
/**
* Scalar array handling.
*/
int registerScalarArray(bool insideScalarArray, FileScopePtr scope,
ExpressionPtr pairs, int &hash, int &index,
std::string &text);
int checkScalarArray(const std::string &text, int &index);
int getScalarArrayId(const std::string &text);
void outputCPPNamedScalarArrays(const std::string &file);
std::string getScalarArrayCompressedText();
std::string getScalarArrayName(int hash, int index);
std::string getScalarVarArrayName(int hash, int index);
int checkScalarVarInteger(int64 val, int &index);
std::string getScalarVarIntegerName(int hash, int index);
void outputCPPNamedScalarVarIntegers(const std::string &file);
int checkScalarVarDouble(double dval, int &index);
std::string getScalarVarDoubleName(int hash, int index);
void outputCPPNamedScalarVarDoubles(const std::string &file);
/**
* Force all class variables to be variants, since l-val or reference
* of dynamic properties are used.
@@ -210,30 +188,6 @@ public:
* Code generation functions.
*/
bool outputAllPHP(CodeGenerator::Output output);
void outputAllCPP(CodeGenerator::Output output, int clusterCount,
const std::string *compileDir);
void outputCPPSystemImplementations(CodeGenerator &cg);
void getCPPFileRunDecls(CodeGenerator &cg, Type2SymbolSetMap &type2names);
void getCPPRedeclaredFunctionDecl(CodeGenerator &cg,
Type2SymbolSetMap &type2names);
void getCPPRedeclaredClassDecl(CodeGenerator &cg,
Type2SymbolSetMap &type2names);
void outputCPPRedeclaredClassImpl(CodeGenerator &cg);
void getCPPDynamicConstantDecl(CodeGenerator &cg,
Type2SymbolSetMap &type2names);
void outputCPPDynamicConstantImpl(CodeGenerator &cg);
void outputCPPScalarArrayDecl(CodeGenerator &cg);
void outputCPPScalarArrayImpl(CodeGenerator &cg);
void outputCPPScalarArrayInit(CodeGenerator &cg, int fileCount, int part);
void outputCPPScalarArrayId(CodeGenerator &cg, int id, int hash, int index,
bool scalarVariant = false);
void getCPPClassStaticInitializerFlags(CodeGenerator &cg,
Type2SymbolSetMap &type2names);
void getCPPClassDeclaredFlags(CodeGenerator &cg,
Type2SymbolSetMap &type2names);
void outputCPPFiniteDouble(CodeGenerator &cg, double dval);
/**
* Parser creates a FileScope upon parsing a new file.
@@ -318,68 +272,30 @@ public:
return m_outputPath;
}
/**
* PHP source info functions.
*/
void recordSourceInfo(const std::string &file, int line, LocationPtr loc);
void recordClassSource(const std::string &clsname, LocationPtr loc,
const std::string &filename);
void recordFunctionSource(const std::string &funcname, LocationPtr loc,
const std::string &filename);
/**
* Literal string to String precomputation
*/
std::string getLiteralStringName(int64 hash, int index, bool iproxy = false);
std::string getLitVarStringName(int64 hash, int index, bool iproxy = false);
std::string getLiteralStringName(int64_t hash, int index, bool iproxy = false);
std::string getLitVarStringName(int64_t hash, int index, bool iproxy = false);
int getLiteralStringId(const std::string &s, int &index);
/**
* Profiling runtime parameter type
*/
std::string getFuncId(ClassScopePtr cls, FunctionScopePtr func);
std::string getParamRTTIEntryKey(ClassScopePtr cls,
FunctionScopePtr func,
const std::string &paramName);
void addParamRTTIEntry(ClassScopePtr cls,
FunctionScopePtr func,
const std::string &paramName);
int getParamRTTIEntryId(ClassScopePtr cls,
FunctionScopePtr func,
const std::string &paramName);
void addRTTIFunction(const std::string &id);
void cloneRTTIFuncs(const char *RTTIDirectory);
std::vector<const char *> &getFuncTableBucket(FunctionScopePtr func);
/**
* Generate default implementation for separable extension classes.
*/
void outputCPPSepExtensionImpl(const std::string &filename);
void outputCPPClusterImpl(CodeGenerator &cg, const FileScopePtrVec &files);
void outputCPPFileImpl(CodeGenerator &cg, FileScopePtr fs);
void addPregeneratedCPP(const std::string &name, std::string &code);
const std::string &getPregeneratedCPP(const std::string &name);
std::set<std::string> m_variableTableFunctions;
std::set<int> m_concatLengths;
int m_arrayLitstrKeyMaxSize;
int m_arrayIntegerKeyMaxSize;
void setSystem() { m_system = true; }
bool isSystem() const { return m_system; }
void setSepExtension() { m_sepExtension = true; }
bool isSepExtension() { return m_sepExtension; }
std::string getHashedName(int64 hash, int index, const char *prefix,
std::string getHashedName(int64_t hash, int index, const char *prefix,
bool longName = false);
void addNamedLiteralVarString(const std::string &s);
void addNamedScalarVarArray(const std::string &s);
StringToClassScopePtrVecMap getExtensionClasses();
void addInteger(int64 n);
void addInteger(int64_t n);
private:
Package *m_package;
bool m_parseOnDemand;
@@ -405,53 +321,7 @@ private:
StatementPtr m_stmt;
std::string m_outputPath;
std::map<std::string, int> m_scalarArrays;
Mutex m_namedScalarArraysMutex;
std::map<int, std::vector<std::string> > m_namedScalarArrays;
std::set<std::string> m_namedScalarVarArrays;
int m_scalarArraysCounter;
std::vector<ExpressionPtr> m_scalarArrayIds;
Mutex m_namedScalarVarIntegersMutex;
std::map<int, std::vector<std::string> > m_namedScalarVarIntegers;
Mutex m_allIntegersMutex;
std::set<int64> m_allIntegers;
Mutex m_namedScalarVarDoublesMutex;
std::map<int, std::vector<std::string> > m_namedScalarVarDoubles;
std::map<std::string, int> m_paramRTTIs;
std::set<std::string> m_rttiFuncs;
int m_paramRTTICounter;
public:
struct ScalarArrayExp {
int id;
int len;
ExpressionPtr exp;
};
void outputCPPDynamicTables(CodeGenerator::Output output);
void outputCPPClassMapFile(CodeGenerator::Output output);
void outputCPPSourceInfos();
void outputCPPNameMaps();
void outputRTTIMetaData(const char *filename);
void outputCPPClassMap(CodeGenerator &cg, CodeGenerator::Output);
void outputCPPSystem();
void outputCPPSepExtensionMake();
void outputFFI(std::vector<std::string> &additionalCPPs);
void repartitionLargeCPP(const std::vector<std::string> &filenames,
const std::vector<std::string> &additionals);
void outputCPPUtilDecl(CodeGenerator::Output output);
void outputCPPUtilImpl(CodeGenerator::Output output);
void outputCPPGlobalDeclarations();
void outputCPPMain();
void outputCPPScalarArrays(bool system);
void outputCPPGlobalVariablesMethods();
void outputCPPGlobalState();
AnalysisResultPtr shared_from_this() {
return boost::static_pointer_cast<AnalysisResult>
(BlockScope::shared_from_this());
@@ -463,12 +333,6 @@ public:
}
private:
int m_scalarArraySortedAvgLen;
int m_scalarArraySortedIndex;
int m_scalarArraySortedSumLen;
std::vector<ScalarArrayExp> m_scalarArraySorted;
int m_scalarArrayCompressedTextSize;
bool m_pregenerating, m_pregenerated;
BlockScopePtrVec m_ignoredScopes;
typedef boost::adjacency_list<boost::setS, boost::vecS> Graph;
@@ -478,33 +342,6 @@ private:
Graph m_depGraph;
typedef std::map<vertex_descriptor, FileScopePtr> VertexToFileScopePtrMap;
VertexToFileScopePtrMap m_fileVertMap;
void getTrueDeps(FileScopePtr f,
std::map<std::string, FileScopePtr> &trueDeps);
void clusterByFileSizes(StringToFileScopePtrVecMap &clusters,
int clusterCount);
void renameStaticNames(std::map<int, std::vector<std::string> > &names,
const char *file, const char *prefix);
typedef std::map<std::string, std::string> StringMap;
Mutex m_pregenMapMutex;
StringMap m_pregenMap;
typedef std::map<int, LocationPtr> SourceLocationMap;
typedef std::map<std::string, SourceLocationMap> SourceInfo;
Mutex m_sourceInfoMutex;
SourceInfo m_sourceInfos;
SourceInfo m_sourceInfoPregen;
std::map<std::string, std::set<std::pair<std::string, int> > > m_clsNameMap;
std::map<std::string, std::set<std::pair<std::string, int> > > m_funcNameMap;
Mutex m_namedStringLiteralsMutex;
std::map<int, std::vector<std::string> > m_namedStringLiterals;
std::set<std::string> m_namedVarStringLiterals;
int m_funcTableSize;
CodeGenerator::MapIntToStringVec m_funcTable;
bool m_system;
bool m_sepExtension;
/**
* Checks whether the file is in one of the on-demand parsing directories.
@@ -525,100 +362,8 @@ private:
*/
void checkClassDerivations();
/**
* Creates the global function table. Needs to be called before generating
* cpp code for each toplevel function.
*/
void createGlobalFuncTable();
void outputCPPScalarArrays(CodeGenerator &cg, int fileCount, int part);
void collectCPPGlobalSymbols(StringPairSetVec &symbols,
CodeGenerator &cg);
void outputCPPGlobalStateFileHeader(CodeGenerator &cg);
void outputCPPGlobalStateBegin(CodeGenerator &cg, const char *section);
void outputCPPGlobalStateEnd(CodeGenerator &cg, const char *section);
void outputCPPGlobalStateSection(CodeGenerator &cg,
const StringPairSet &names,
const char *section,
const char *prefix = "g->",
const char *name_prefix = "");
void outputCPPClassIncludes(CodeGenerator &cg);
void outputCPPExtClassImpl(CodeGenerator &cg);
void outputCPPDynamicTablesHeader(CodeGenerator &cg,
bool includeGlobalVars = true,
bool includes = true,
bool noNamespace = false);
void outputCPPGlobalImplementations(CodeGenerator &cg);
void preGenerateCPP(CodeGenerator::Output output,
const FileScopePtrVec &files, int threadCount);
void movePregeneratedSourceInfo(const std::string &source,
const std::string &target, int offset);
int getFileSize(FileScopePtr fs);
void repartitionCPP(const std::string &filename, int64 targetSize,
bool insideHPHP, bool force);
void outputCPPFFIStubs();
void outputHSFFIStubs();
/**
* Outputs Java stubs.
*
* Each PHP file becomes a Java package, in which the HphpMain class
* contains all the toplevel function definitions, and the rest of the
* classes are one-to-one corresponding to the php classes declared in
* that file.
*/
void outputJavaFFIStubs();
/**
* Outputs one .h file that declares all the Java native method stubs,
* avoiding javah for performance reason.
*/
void outputJavaFFICppDecl();
/**
* Outputs one .cpp file that implements all the native methods declared
* in the Java classes generated by outputJavaFFIStubs().
*/
void outputJavaFFICppImpl();
void outputSwigFFIStubs();
void outputHexBuffer(CodeGenerator &cg, const char *name,
const char *buf, int len);
void outputCPPNamedLiteralStrings(bool genStatic, const std::string &file);
void outputCPPSepExtensionIncludes(CodeGenerator &cg);
void outputCPPInvokeFileHeader(CodeGenerator &cg);
void outputCPPEvalHook(CodeGenerator &cg);
void outputCPPDefaultInvokeFile(CodeGenerator &cg, const char *file);
void outputArrayCreateDecl(CodeGenerator &cg);
void outputArrayCreateImpl(CodeGenerator &cg);
void outputCPPHashTableInvokeFile(CodeGenerator &cg,
const std::vector<const char*> &entries,
bool needEvalHook);
void outputCPPDynamicClassTables(CodeGenerator::Output output);
void outputCPPDynamicConstantTable(CodeGenerator::Output output);
void outputCPPHashTableGetConstant(CodeGenerator &cg, bool system,
const std::map<std::string, TypePtr> &constMap,
const hphp_string_map<bool> &dyns);
void cloneRTTIFuncs(const StringToFunctionScopePtrMap &functions,
const StringToFunctionScopePtrVecMap *redecFunctions);
void outputInitLiteralVarStrings(CodeGenerator &cg, int fileIndex,
std::vector<int> &litVarStrFileIndices,
std::vector<std::pair<int, int> > &litVarStrs);
void outputInitLiteralVarStrings();
void outputStringProxyData(CodeGenerator &cg,
int fileIndex, std::vector<std::string> &lStrings,
std::vector<std::pair<std::string, int> > &bStrings);
void outputVarStringProxyData(CodeGenerator &cg,
int fileIndex, std::vector<std::pair<int, int> > &litVarStrs);
public:
static DECLARE_THREAD_LOCAL(BlockScopeRawPtr, s_currentScopeThreadLocal);
static DECLARE_THREAD_LOCAL(BlockScopeRawPtrFlagsHashMap,
@@ -655,7 +400,7 @@ private:
class RescheduleException : public Exception {
public:
RescheduleException(BlockScopeRawPtr scope) :
Exception(false), m_scope(scope) {}
Exception(), m_scope(scope) {}
BlockScopeRawPtr &getScope() { return m_scope; }
#ifdef HPHP_INSTRUMENT_TYPE_INF
static int s_NumReschedules;
-5
Ver Arquivo
@@ -225,11 +225,6 @@ void BlockScope::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_variables->outputPHP(cg, ar);
}
void BlockScope::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_constants->outputCPP(cg, ar);
m_variables->outputCPP(cg, ar);
}
int BlockScope::ScopeCompare::cmp(const BlockScopeRawPtr &p1,
const BlockScopeRawPtr &p2) const {
int d1 = p1->m_kind - p2->m_kind;
-2
Ver Arquivo
@@ -218,9 +218,7 @@ public:
/**
* Code gen
*/
virtual void outputCPPDef(CodeGenerator &cg) {}
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual bool inPseudoMain() const {
return false;
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+4 -195
Ver Arquivo
@@ -124,7 +124,6 @@ public:
void checkDerivation(AnalysisResultPtr ar, hphp_string_iset &seen);
const std::string &getOriginalParent() const { return m_parent; }
std::string getHeaderFilename();
/**
* Returns topmost parent class that has the method.
@@ -212,7 +211,7 @@ public:
bool forInvoke = false);
/**
* Whether or not we can directly call c_ObjectData::o_invoke() when lookup
* Whether or not we can directly call ObjectData::o_invoke() when lookup
* in this class fails. If false, we need to call parent::o_invoke(), which
* may be redeclared or may have private methods that need to check class
* context.
@@ -292,62 +291,6 @@ public:
ClassScopePtr getParentScope(AnalysisResultConstPtr ar) const;
void addUsedLiteralStringHeader(const std::string &s) {
m_usedLiteralStringsHeader.insert(s);
}
void addUsedLitVarStringHeader(const std::string &s) {
m_usedLitVarStringsHeader.insert(s);
}
void addUsedScalarVarInteger(int64 i) {
m_usedScalarVarIntegers.insert(i);
}
std::set<int64> &getUsedScalarVarIntegers() {
return m_usedScalarVarIntegers;
}
void addUsedScalarVarIntegerHeader(int64 i) {
m_usedScalarVarIntegersHeader.insert(i);
}
void addUsedScalarVarDouble(double d) {
m_usedScalarVarDoubles.insert(d);
}
std::set<double> &getUsedScalarVarDoubles() {
return m_usedScalarVarDoubles;
}
void addUsedScalarVarDoubleHeader(double d) {
m_usedScalarVarDoublesHeader.insert(d);
}
void addUsedDefaultValueScalarArray(const std::string &s) {
m_usedDefaultValueScalarArrays.insert(s);
}
void addUsedDefaultValueScalarVarArray(const std::string &s) {
m_usedDefaultValueScalarVarArrays.insert(s);
}
void addUsedConstHeader(const std::string &s) {
m_usedConstsHeader.insert(s);
}
void addUsedClassConstHeader(ClassScopeRawPtr cls, const std::string &s) {
m_usedClassConstsHeader.insert(CodeGenerator::UsedClassConst(cls, s));
}
void addUsedClassHeader(ClassScopeRawPtr s) {
m_usedClassesHeader.insert(s);
}
void addUsedClassFullHeader(ClassScopeRawPtr s) {
m_usedClassesFullHeader.insert(s);
}
void addUsedTrait(const std::string &s) {
if (!usesTrait(s)) {
m_usedTraitNames.push_back(s);
@@ -375,42 +318,12 @@ public:
void importUsedTraits(AnalysisResultPtr ar);
/**
* Output class meta info for g_class_map.
*/
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* Serialize the iface, not everything.
*/
void serialize(JSON::CodeError::OutputStream &out) const;
void serialize(JSON::DocTarget::OutputStream &out) const;
static void outputCPPHashTableClasses
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
const std::vector<const char*> &classes);
static void outputCPPClassVarInitImpl(
CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
const std::vector<const char *> &classes);
void outputCPPDynamicClassDecl(CodeGenerator &cg);
void outputCPPDynamicClassImpl(CodeGenerator &cg, AnalysisResultPtr ar);
static void outputCPPDynamicClassCreateDecl(CodeGenerator &cg);
static void outputCPPDynamicClassCreateImpl
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
const std::vector<const char*> &classes);
static void outputCPPGetCallInfoStaticMethodImpl
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
const std::vector<const char*> &classes);
static void outputCPPGetStaticPropertyImpl
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes,
const std::vector<const char*> &classes);
static void outputCPPGetClassConstantImpl
(CodeGenerator &cg, const StringToClassScopePtrVecMap &classScopes);
static void outputCPPGetClassPropTableImpl
(CodeGenerator &cg, AnalysisResultPtr ar,
const StringToClassScopePtrVecMap &classScopes,
bool extension = false);
bool isInterface() const { return m_kindOf == KindOfInterface; }
bool isFinal() const { return m_kindOf == KindOfFinalClass ||
m_kindOf == KindOfTrait; }
@@ -419,32 +332,6 @@ public:
bool isTrait() const { return m_kindOf == KindOfTrait; }
bool hasProperty(const std::string &name) const;
bool hasConst(const std::string &name) const;
void outputCPPDef(CodeGenerator &cg);
void outputCPPHeader(AnalysisResultPtr ar,
CodeGenerator::Output output);
void outputCPPForwardHeader(CodeGenerator &cg,AnalysisResultPtr ar);
void outputCPPJumpTableDecl(CodeGenerator &cg, AnalysisResultPtr ar);
void outputMethodWrappers(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* This prints out all the support methods (invoke, create, destructor,
* etc.)
* This is here instead of ClassStatement because I want to be able to call
* these for extension classes that don't have a statement.
*/
void outputCPPSupportMethodsImpl(CodeGenerator &cg, AnalysisResultPtr ar);
std::string getClassPropTableId(AnalysisResultPtr ar);
/**
* These output wrappers for class methods so that class definitions don't
* have to be used in generating global jump tables.
*/
void outputCPPGlobalTableWrappersDecl(CodeGenerator &cg,
AnalysisResultPtr ar);
void outputCPPGlobalTableWrappersImpl(CodeGenerator &cg,
AnalysisResultPtr ar);
static bool NeedStaticArray(ClassScopePtr cls, FunctionScopePtr func);
void inheritedMagicMethods(ClassScopePtr super);
@@ -461,40 +348,12 @@ public:
m_parent = "";
}
void outputCPPStaticMethodWrappers(CodeGenerator &cg, AnalysisResultPtr ar,
std::set<std::string> &done,
const char *cls);
/**
* Override function container
*/
bool addFunction(AnalysisResultConstPtr ar,
FunctionScopePtr funcScope);
void outputVolatileCheckBegin(CodeGenerator &cg,
AnalysisResultPtr ar,
BlockScopePtr bs,
const std::string &name);
void outputVolatileCheckEnd(CodeGenerator &cg);
static void OutputVolatileCheckBegin(CodeGenerator &cg,
AnalysisResultPtr ar,
BlockScopePtr bs,
const std::string &origName);
static void OutputVolatileCheckEnd(CodeGenerator &cg);
static void OutputVolatileCheck(CodeGenerator &cg, AnalysisResultPtr ar,
BlockScopePtr bs,
const std::string &origName, bool noThrow);
/**
* Whether or not the specified jump table is empty.
*/
bool hasAllJumpTables() const {
return m_emptyJumpTables.empty();
}
bool hasJumpTable(JumpTableName name) const {
return m_emptyJumpTables.find(name) == m_emptyJumpTables.end();
}
void setNeedsCppCtor(bool needsCppCtor) {
m_needsCppCtor = needsCppCtor;
}
@@ -515,29 +374,6 @@ public:
bool canSkipCreateMethod(AnalysisResultConstPtr ar) const;
bool checkHasPropTable(AnalysisResultConstPtr ar);
struct IndexedSym {
IndexedSym(int i, int p, const Symbol *s) :
origIndex(i), privIndex(p), sym(s) {}
int origIndex;
int privIndex;
const Symbol *sym;
};
struct ClassPropTableInfo {
ClassScopeRawPtr cls;
std::vector<int> actualIndex[3];
std::vector<int> privateIndex[3];
std::map<int, std::vector<IndexedSym> > syms[3];
};
typedef std::map<std::string, ClassPropTableInfo>
ClassPropTableMap;
protected:
void findJumpTableMethods(CodeGenerator &cg, AnalysisResultPtr ar,
std::vector<const char *> &funcs);
bool hasJumpTableMethods(CodeGenerator &cg, AnalysisResultPtr ar);
private:
// need to maintain declaration order for ClassInfo map
FunctionScopePtrVec m_functionsVec;
@@ -546,19 +382,6 @@ private:
mutable std::vector<std::string> m_bases;
UserAttributeMap m_userAttributes;
std::set<JumpTableName> m_emptyJumpTables;
std::set<std::string> m_usedLiteralStringsHeader;
std::set<std::string> m_usedLitVarStringsHeader;
std::set<int64> m_usedScalarVarIntegers;
std::set<int64> m_usedScalarVarIntegersHeader;
std::set<double> m_usedScalarVarDoubles;
std::set<double> m_usedScalarVarDoublesHeader;
std::set<std::string> m_usedDefaultValueScalarArrays;
std::set<std::string> m_usedDefaultValueScalarVarArrays;
std::set<std::string> m_usedConstsHeader;
CodeGenerator::UsedClassConstSet m_usedClassConstsHeader;
CodeGenerator::ClassScopeSet m_usedClassesHeader;
CodeGenerator::ClassScopeSet m_usedClassesFullHeader;
std::vector<std::string> m_usedTraitNames;
// m_traitAliases is used to support ReflectionClass::getTraitAliases
std::vector<std::pair<std::string, std::string> > m_traitAliases;
@@ -614,6 +437,9 @@ private:
void addImportTraitMethod(const TraitMethod &traitMethod,
const std::string &methName);
void informClosuresAboutScopeClone(ConstructPtr root,
FunctionScopePtr outerScope,
AnalysisResultPtr ar);
void setImportTraitMethodModifiers(const std::string &methName,
ClassScopePtr traitCls,
@@ -659,23 +485,6 @@ private:
void renameCreateContinuationCalls(AnalysisResultPtr ar, ConstructPtr c,
ImportedMethodMap &importedMethods);
std::string getBaseHeaderFilename();
void outputCPPMethodInvokeBareObjectSupport(
CodeGenerator &cg, AnalysisResultPtr ar,
FunctionScopePtr func, bool fewArgs);
void outputCPPMethodInvokeTable
(CodeGenerator &cg, AnalysisResultPtr ar,
const std::vector <const char*> &keys,
const StringToFunctionScopePtrMap &funcScopes, bool fewArgs,
bool staticOnly);
void outputCPPMethodInvokeTableSupport(CodeGenerator &cg,
AnalysisResultPtr ar, const std::vector<const char*> &keys,
const StringToFunctionScopePtrMap &funcScopes, bool fewArgs);
hphp_const_char_imap<int> m_implemented;
ClassScopePtr getNextParentWithProp(AnalysisResultPtr ar);
};
///////////////////////////////////////////////////////////////////////////////
-182
Ver Arquivo
@@ -251,185 +251,3 @@ void ConstantTable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
}
}
void ConstantTable::getCPPDynamicDecl(CodeGenerator &cg,
AnalysisResultPtr ar,
Type2SymbolSetMap &type2names) {
const char *prefix = Option::ConstantPrefix;
string classId;
const char *fmt = "";
ClassScopePtr scope = getClassScope();
if (scope) {
prefix = Option::ClassConstantPrefix;
classId = scope->getId();
fmt = Option::IdPrefix.c_str();
}
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
SymbolSet &symbols = type2names["Variant"];
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (sym->declarationSet() && sym->isDynamic() &&
system == sym->isSystem()) {
string tmp = string(prefix) + classId + fmt +
CodeGenerator::FormatLabel(sym->getName());
if (Type::IsMappedToVariant(sym->getFinalType())) {
symbols.insert(tmp);
} else {
type2names[sym->getFinalType()->getCPPDecl(ar, BlockScopeRawPtr())].
insert(tmp);
}
}
}
}
void ConstantTable::outputCPPDynamicImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (sym->declarationSet() && sym->isDynamic()) {
cg_printf("%s%s = \"%s\";\n", Option::ConstantPrefix,
CodeGenerator::FormatLabel(sym->getName()).c_str(),
CodeGenerator::EscapeLabel(sym->getName()).c_str());
}
}
}
void ConstantTable::collectCPPGlobalSymbols(StringPairSet &symbols,
CodeGenerator &cg,
AnalysisResultPtr ar) {
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (sym->declarationSet() && sym->isDynamic()) {
string varname = Option::ConstantPrefix +
CodeGenerator::FormatLabel(sym->getName());
symbols.insert(StringPair(varname, varname));
}
}
}
void ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
bool newline /* = true */) const {
bool printed = false;
BOOST_FOREACH(Symbol *sym, m_symbolVec) {
if (outputCPP(cg, ar, sym)) printed = true;
}
if (newline && printed) {
cg_printf("\n");
}
}
bool ConstantTable::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
const Symbol *sym) const {
bool decl = true;
if (cg.getContext() == CodeGenerator::CppConstantsDecl) {
decl = false;
}
if (!const_cast<Symbol*>(sym)->checkDefined() ||
sym->isDynamic()) {
return false;
}
if (sym->isSystem() && cg.getOutput() != CodeGenerator::SystemCPP) {
return false;
}
const string &name = sym->getName();
ConstructPtr value = sym->getValue();
cg_printf(decl ? "extern const " : "const ");
TypePtr type = sym->getFinalType();
bool isString = type->is(Type::KindOfString);
if (isString) {
cg_printf("StaticString");
} else {
type->outputCPPDecl(cg, ar, getBlockScope());
}
ClassScope *cls = dynamic_cast<ClassScope*>(&m_blockScope);
if (decl) {
if (!cls) {
cg_printf(" %s%s", Option::ConstantPrefix,
CodeGenerator::FormatLabel(name).c_str());
} else {
cg_printf(" %s%s%s%s", Option::ClassConstantPrefix,
cls->getId().c_str(),
Option::IdPrefix.c_str(),
CodeGenerator::FormatLabel(name).c_str());
}
} else {
if (!cls) {
cg_printf(" %s%s", Option::ConstantPrefix,
CodeGenerator::FormatLabel(name).c_str());
} else {
cg_printf(" %s%s%s%s", Option::ClassConstantPrefix,
cls->getId().c_str(),
Option::IdPrefix.c_str(),
CodeGenerator::FormatLabel(name).c_str());
}
cg_printf(isString ? "(" : " = ");
if (value) {
ExpressionPtr exp = dynamic_pointer_cast<Expression>(value);
if (isString && exp->isScalar()) {
ScalarExpressionPtr scalarExp =
dynamic_pointer_cast<ScalarExpression>(exp);
if (scalarExp) {
cg_printf("LITSTR_INIT(%s)",
scalarExp->getCPPLiteralString().c_str());
} else {
Variant v;
exp->getScalarValue(v);
cg_printf("LITSTR_INIT(\"%s\")",
CodeGenerator::EscapeLabel(v.toString().data()).c_str());
}
} else {
exp->outputCPP(cg, ar);
}
} else {
cg_printf("\"%s\"", CodeGenerator::EscapeLabel(name).c_str());
}
if (isString) {
cg_printf(")");
}
}
cg_printf(";\n");
return true;
}
bool ConstantTable::outputSingleConstant(CodeGenerator &cg,
AnalysisResultPtr ar,
const std::string &name) const {
const Symbol *sym = getSymbol(name);
return sym && outputCPP(cg, ar, sym);
}
void ConstantTable::outputCPPConstantSymbol(CodeGenerator &cg,
AnalysisResultPtr ar,
Symbol *sym) {
ClassScopeRawPtr cls = getClassScope();
if (sym->valueSet() &&
(cls || (!sym->isDynamic() &&
!ar->isConstantRedeclared(sym->getName())))) {
ExpressionPtr value = dynamic_pointer_cast<Expression>(sym->getValue());
Variant v;
if (value && value->getScalarValue(v)) {
int len;
string output = getEscapedText(v, len);
cg_printf("\"%s\", (const char *)%d, \"%s\",\n",
CodeGenerator::EscapeLabel(sym->getName()).c_str(),
len, output.c_str());
} else if (cls) {
cg_printf("\"%s\", (const char *)&%s%s, NULL,\n",
CodeGenerator::EscapeLabel(sym->getName()).c_str(),
Option::ClassStaticsCallbackPrefix, cls->getId().c_str());
} else {
cg_printf("\"%s\", (const char *)0, NULL,\n",
CodeGenerator::EscapeLabel(sym->getName()).c_str());
}
}
}
void ConstantTable::outputCPPClassMap(CodeGenerator &cg,
AnalysisResultPtr ar,
bool last /* = true */) {
for (unsigned int i = 0; i < m_symbolVec.size(); i++) {
outputCPPConstantSymbol(cg, ar, m_symbolVec[i]);
}
if (last) cg_printf("NULL,\n");
}
-20
Ver Arquivo
@@ -81,22 +81,6 @@ public:
* Generate all constant declarations for this symbol table.
*/
void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
bool newline = true) const;
void getCPPDynamicDecl(CodeGenerator &cg, AnalysisResultPtr ar,
Type2SymbolSetMap &type2names);
void outputCPPDynamicImpl(CodeGenerator &cg, AnalysisResultPtr ar);
bool outputSingleConstant(CodeGenerator &cg, AnalysisResultPtr ar,
const std::string &name) const;
void collectCPPGlobalSymbols(StringPairSet &symbols, CodeGenerator &cg,
AnalysisResultPtr ar);
/**
* Generate all class constants in class info map.
*/
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar,
bool last = true);
bool isRecursivelyDeclared(AnalysisResultConstPtr ar,
const std::string &name) const;
@@ -115,10 +99,6 @@ private:
ClassScopeRawPtr findBase(AnalysisResultConstPtr ar,
const std::string &name,
const std::vector<std::string> &bases) const;
bool outputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
const Symbol *sym) const;
void outputCPPConstantSymbol(CodeGenerator &cg, AnalysisResultPtr ar,
Symbol *sym);
};
///////////////////////////////////////////////////////////////////////////////
+98 -32
Ver Arquivo
@@ -296,10 +296,10 @@ static int32_t countStackValues(const std::vector<uchar>& immVec) {
#define DEC_MA std::vector<uchar>
#define DEC_BLA std::vector<Label*>&
#define DEC_SLA std::vector<StrOff>&
#define DEC_IVA int32
#define DEC_HA int32
#define DEC_IA int32
#define DEC_I64A int64
#define DEC_IVA int32_t
#define DEC_HA int32_t
#define DEC_IA int32_t
#define DEC_I64A int64_t
#define DEC_DA double
#define DEC_SA const StringData*
#define DEC_AA ArrayData*
@@ -650,7 +650,11 @@ static void checkJmpTargetEvalStack(const SymbolicStack& source,
if (source.size() != dest.size()) {
Logger::Warning("Emitter detected a point in the bytecode where the "
"depth of the stack is not the same for all possible "
"control flow paths");
"control flow paths. source size: %d. dest size: %d",
source.size(),
dest.size());
Logger::Warning("src stack : %s", source.pretty().c_str());
Logger::Warning("dest stack: %s", dest.pretty().c_str());
assert(false);
return;
}
@@ -784,7 +788,7 @@ bool SymbolicStack::getNotRef() const {
return se.notRef;
}
void SymbolicStack::setInt(int64 v) {
void SymbolicStack::setInt(int64_t v) {
assert(m_symStack.size());
m_symStack.back().intval = v;
}
@@ -930,7 +934,7 @@ int SymbolicStack::getLoc(int index) const {
return m_symStack[index].intval;
}
int64 SymbolicStack::getInt(int index) const {
int64_t SymbolicStack::getInt(int index) const {
assert(m_symStack.size() > size_t(index));
assert(StackSym::GetSymFlavor(m_symStack[index].sym) == StackSym::I);
return m_symStack[index].intval;
@@ -1092,7 +1096,7 @@ void MetaInfoBuilder::setForUnit(UnitEmitter& target) const {
vector<Offset> index1;
vector<Offset> index2;
vector<uint8> data;
vector<uint8_t> data;
index1.push_back(entries);
size_t sz1 = (2 + entries) * sizeof(Offset);
@@ -1112,8 +1116,8 @@ void MetaInfoBuilder::setForUnit(UnitEmitter& target) const {
data.push_back(mi.m_data << 1);
} else {
union {
uint32 val;
uint8 bytes[4];
uint32_t val;
uint8_t bytes[4];
} u;
u.val = (mi.m_data << 1) | 1;
for (int j = 0; j < 4; j++) {
@@ -1126,7 +1130,7 @@ void MetaInfoBuilder::setForUnit(UnitEmitter& target) const {
index2.push_back(sz1 + sz2 + data.size());
size_t size = sz1 + sz2 + data.size();
uint8* meta = (uint8*)malloc(size);
uint8_t* meta = (uint8_t*)malloc(size);
memcpy(meta, &index1[0], sz1);
memcpy(meta + sz1, &index2[0], sz2);
memcpy(meta + sz1 + sz2, &data[0], data.size());
@@ -1723,10 +1727,8 @@ void EmitterVisitor::visit(FileScopePtr file) {
tvWriteUninit(&mainReturn);
tvAsVariant(&mainReturn) = 1;
}
// Use _count as a flag for VMExecutionContext::evalUnit
// since its otherwise unused
mainReturn._count = !notMergeOnly;
m_ue.setMainReturn(&mainReturn);
m_ue.setMergeOnly(!notMergeOnly);
// If the exitHnd label was used, we need to emit some extra code
// to handle stray breaks
Label exit;
@@ -1953,7 +1955,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
case Statement::KindOfContinueStatement:
case Statement::KindOfBreakStatement: {
BreakStatementPtr bs(static_pointer_cast<BreakStatement>(s));
int64 n = bs->getDepth();
int64_t n = bs->getDepth();
if (n == 1) {
// Plain old "break;" or "continue;"
if (m_contTargets.empty()) {
@@ -1985,7 +1987,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
emitConvertToCell(e);
} else {
// Dynamic break/continue with statically known depth.
if (n > (int64)m_contTargets.size()) {
if (n > (int64_t)m_contTargets.size()) {
std::ostringstream msg;
msg << "Cannot break/continue " << n << " levels";
e.String(StringData::GetStaticString(msg.str()));
@@ -3647,7 +3649,6 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
// Key.
assert(key->isScalar());
TypedValue tvKey;
tvKey._count = 0;
if (key->is(Expression::KindOfConstantExpression)) {
ConstantExpressionPtr c(
static_pointer_cast<ConstantExpression>(key));
@@ -3671,11 +3672,11 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
ScalarExpressionPtr sval(
static_pointer_cast<ScalarExpression>(key));
const std::string* s;
int64 i;
int64_t i;
double d;
if (sval->getString(s)) {
StringData* sd = StringData::GetStaticString(*s);
int64 n = 0;
int64_t n = 0;
if (sd->isStrictlyInteger(n)) {
tvKey.m_data.num = n;
tvKey.m_type = KindOfInt64;
@@ -3781,7 +3782,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
StringData* className = newClosureName();
const static StringData* parentName =
StringData::GetStaticString("closure");
StringData::GetStaticString("Closure");
const Location* sLoc = ce->getLocation().get();
PreClassEmitter* pce = m_ue.newPreClassEmitter(
className, PreClass::AlwaysHoistable);
@@ -4003,9 +4004,9 @@ void EmitterVisitor::buildVectorImm(std::vector<uchar>& vectorImm,
encodeIvaToVector(vectorImm, m_evalStack.getLoc(i));
} else if (symFlavor == StackSym::T) {
assert(strid != -1);
encodeToVector<int32>(vectorImm, strid);
encodeToVector<int32_t>(vectorImm, strid);
} else if (symFlavor == StackSym::I) {
encodeToVector<int64>(vectorImm, m_evalStack.getInt(i));
encodeToVector<int64_t>(vectorImm, m_evalStack.getInt(i));
}
++i;
@@ -4839,7 +4840,7 @@ DataType EmitterVisitor::analyzeSwitch(SwitchStatementPtr sw,
} else {
return KindOfInvalid;
}
int64 n;
int64_t n;
bool isNonZero;
if (t == KindOfInt64) {
n = cval.asInt64Val();
@@ -4873,8 +4874,8 @@ DataType EmitterVisitor::analyzeSwitch(SwitchStatementPtr sw,
}
if (t == KindOfInt64) {
int64 base = caseMap.begin()->first;
int64 nTargets = caseMap.rbegin()->first - base + 1;
int64_t base = caseMap.begin()->first;
int64_t nTargets = caseMap.rbegin()->first - base + 1;
// Fail if the cases are too sparse
if ((float)caseMap.size() / nTargets < 0.5) {
return KindOfInvalid;
@@ -4892,8 +4893,8 @@ void EmitterVisitor::emitIntegerSwitch(Emitter& e, SwitchStatementPtr sw,
std::vector<Label>& caseLabels,
Label& done, const SwitchState& state) {
auto& caseMap = state.cases;
int64 base = caseMap.begin()->first;
int64 nTargets = caseMap.rbegin()->first - base + 1;
int64_t base = caseMap.begin()->first;
int64_t nTargets = caseMap.rbegin()->first - base + 1;
// It's on. Map case values to Labels, filling in the blanks as
// appropriate.
@@ -6081,9 +6082,17 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
PreClassEmitter* pce = m_ue.newPreClassEmitter(className, hoistable);
pce->init(sLoc->line0, sLoc->line1, m_ue.bcPos(), attr, parentName,
classDoc);
LocationPtr loc(new Location(*sLoc));
loc->line1 = loc->line0;
loc->char1 = loc->char0;
e.setTempLocation(loc);
if (hoistable != PreClass::AlwaysHoistable) {
e.DefCls(pce->id());
} else {
// To atatch the line number to for error reporting...
e.Nop();
}
e.setTempLocation(LocationPtr());
for (int i = firstInterface; i < nInterfaces; ++i) {
pce->addInterface(StringData::GetStaticString(bases[i]));
}
@@ -6150,6 +6159,9 @@ PreClass::Hoistable EmitterVisitor::emitClass(Emitter& e, ClassScopePtr cNode,
} else {
tvWriteUninit(&tvVal);
if (!(attrs & AttrStatic)) {
if (requiresDeepInit(vNode)) {
attrs = (Attr)(attrs | AttrDeepInit);
}
if (nonScalarPinitVec == nullptr) {
nonScalarPinitVec = new NonScalarVec();
}
@@ -6668,7 +6680,6 @@ StringData* EmitterVisitor::newClosureName() {
void EmitterVisitor::initScalar(TypedValue& tvVal, ExpressionPtr val) {
assert(val->isScalar());
tvVal.m_type = KindOfUninit;
tvVal._count = 0;
switch (val->getKindOf()) {
case Expression::KindOfConstantExpression: {
ConstantExpressionPtr ce(static_pointer_cast<ConstantExpression>(val));
@@ -6694,7 +6705,7 @@ void EmitterVisitor::initScalar(TypedValue& tvVal, ExpressionPtr val) {
tvVal.m_type = KindOfString;
break;
}
int64 i;
int64_t i;
if (sval->getInt(i)) {
tvVal.m_data.num = i;
tvVal.m_type = KindOfInt64;
@@ -6743,6 +6754,41 @@ void EmitterVisitor::initScalar(TypedValue& tvVal, ExpressionPtr val) {
}
}
bool EmitterVisitor::requiresDeepInit(ExpressionPtr initExpr) const {
switch (initExpr->getKindOf()) {
case Expression::KindOfScalarExpression:
case Expression::KindOfConstantExpression:
case Expression::KindOfClassConstantExpression:
return false;
case Expression::KindOfUnaryOpExpression: {
UnaryOpExpressionPtr u(
static_pointer_cast<UnaryOpExpression>(initExpr));
if (u->getOp() == T_ARRAY) {
ExpressionListPtr el =
static_pointer_cast<ExpressionList>(u->getExpression());
if (el) {
int n = el->getCount();
for (int i = 0; i < n; i++) {
ArrayPairExpressionPtr ap =
static_pointer_cast<ArrayPairExpression>((*el)[i]);
ExpressionPtr key = ap->getName();
if (requiresDeepInit(ap->getValue()) ||
(key && requiresDeepInit(key))) {
return true;
}
}
}
return false;
} else if (u->getOp() == '+' || u->getOp() == '-') {
return requiresDeepInit(u->getExpression());
}
// fall through
}
default:
return true;
}
}
Thunklet::~Thunklet() {}
using HPHP::Eval::PhpFile;
@@ -6952,9 +6998,8 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
TypedValue mainReturn;
mainReturn.m_data.num = 1;
mainReturn.m_type = KindOfBoolean;
// _count is the "Unit::isMergeOnly()" flag
mainReturn._count = 1;
ue->setMainReturn(&mainReturn);
ue->setMergeOnly(true);
MetaInfoBuilder metaInfo;
@@ -7075,6 +7120,27 @@ static Unit* emitHHBCNativeClassUnit(const HhbcExtClassInfo* builtinClasses,
cnsInfo->name.get(), (TypedValue*)(&val), empty_string.get());
}
}
{
ClassInfo::PropertyVec propVec = e.ci->getPropertiesVec();
for (unsigned i = 0; i < propVec.size(); ++i) {
const ClassInfo::PropertyInfo* propInfo = propVec[i];
assert(propInfo);
int attr = AttrNone;
if (propInfo->attribute & ClassInfo::IsProtected) attr |= AttrProtected;
else if (propInfo->attribute & ClassInfo::IsPrivate) attr |= AttrPrivate;
else attr |= AttrPublic;
if (propInfo->attribute & ClassInfo::IsStatic) attr |= AttrStatic;
TypedValue tvNull;
tvWriteNull(&tvNull);
pce->addProperty(
propInfo->name.get(),
Attr(attr),
propInfo->docComment ? StringData::GetStaticString(propInfo->docComment) : nullptr,
&tvNull
);
}
}
}
Peephole peephole(*ue, metaInfo);
@@ -7114,7 +7180,7 @@ static UnitEmitter* emitHHBCVisitor(AnalysisResultPtr ar, FileScopeRawPtr fsp) {
Logger::Error("Unable to open %s for write", fullPath.c_str());
} else {
CodeGenerator cg(&f, CodeGenerator::TextHHBC);
cg.printf("Hash: %llx%016llx\n", md5.q[0], md5.q[1]);
cg.printf("Hash: %" PRIx64 "%016" PRIx64 "\n", md5.q[0], md5.q[1]);
cg.printRaw(unit->toString().c_str());
f.close();
}
+9 -8
Ver Arquivo
@@ -110,10 +110,10 @@ public:
#define MA std::vector<uchar>
#define BLA std::vector<Label*>&
#define SLA std::vector<StrOff>&
#define IVA int32
#define HA int32
#define IA int32
#define I64A int64
#define IVA int32_t
#define HA int32_t
#define IA int32_t
#define I64A int64_t
#define DA double
#define SA const StringData*
#define AA ArrayData*
@@ -200,7 +200,7 @@ private:
DataType dt; // META_DATA_TYPE
} metaData;
const StringData* className;
int64 intval; // used for L and I symbolic flavors
int64_t intval; // used for L and I symbolic flavors
// If intval is an unnamed local temporary, this offset is the start
// of the region we are using it (which we will need to have a
@@ -237,7 +237,7 @@ public:
std::string pretty() const;
void push(char sym);
void setInt(int64 v);
void setInt(int64_t v);
void setString(const StringData* s);
void setKnownCls(const StringData* s, bool nonNull);
void setNotRef();
@@ -274,7 +274,7 @@ public:
ClassBaseType getClsBaseType(int index) const;
int getLoc(int index) const;
int64 getInt(int index) const;
int64_t getInt(int index) const;
Offset getUnnamedLocStart(int index) const;
void pushFDesc();
@@ -494,7 +494,7 @@ private:
typedef std::pair<Id, int> StrCase;
struct SwitchState : private boost::noncopyable {
SwitchState() : nonZeroI(-1), defI(-1) {}
std::map<int64, int> cases; // a map from int (or litstr id) to case index
std::map<int64_t, int> cases; // a map from int (or litstr id) to case index
std::vector<StrCase> caseOrder; // for string switches, a list of the
// <litstr id, case index> in the order
// they appear in the source
@@ -656,6 +656,7 @@ public:
StringData* newClosureName();
void initScalar(TypedValue& tvVal, ExpressionPtr val);
bool requiresDeepInit(ExpressionPtr initExpr) const;
void emitClassTraitPrecRule(PreClassEmitter* pce, TraitPrecStatementPtr rule);
void emitClassTraitAliasRule(PreClassEmitter* pce,
-468
Ver Arquivo
@@ -206,20 +206,6 @@ ExpressionPtr FileScope::getEffectiveImpl(AnalysisResultConstPtr ar) const {
return ExpressionPtr();
}
bool FileScope::canUseDummyPseudoMain(AnalysisResultConstPtr ar) const {
if (!m_pseudoMain) {
return false;
}
assert(!m_pseudoMain->isVolatile());
if (!Option::GenerateDummyPseudoMain ||
Option::KeepStatementsWithNoEffect) {
return false;
}
ExpressionPtr exp = getEffectiveImpl(ar);
Variant val;
return (exp && exp->getScalarValue(val) && val.same(true));
}
///////////////////////////////////////////////////////////////////////////////
void FileScope::declareConstant(AnalysisResultPtr ar, const string &name) {
@@ -238,7 +224,6 @@ void FileScope::addConstant(const string &name, TypePtr type,
void FileScope::addIncludeDependency(AnalysisResultPtr ar,
const string &file, bool byInlined) {
ar->addIncludeDependency(shared_from_this(), file);
if (byInlined) m_usedIncludesInline.insert(file);
}
void FileScope::addClassDependency(AnalysisResultPtr ar,
const string &classname) {
@@ -247,7 +232,6 @@ void FileScope::addClassDependency(AnalysisResultPtr ar,
void FileScope::addFunctionDependency(AnalysisResultPtr ar,
const string &funcname, bool byInlined) {
ar->addFunctionDependency(shared_from_this(), funcname);
if (byInlined) m_usedFuncsInline.insert(funcname);
}
void FileScope::addConstantDependency(AnalysisResultPtr ar,
const string &decname) {
@@ -507,455 +491,3 @@ void FileScope::serialize(JSON::DocTarget::OutputStream &out) const {
ms.done();
}
void FileScope::outputCPPHelper(CodeGenerator &cg, AnalysisResultPtr ar,
bool classes /* = true */) {
if (classes) {
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
it != m_classes.end(); ++it) {
BOOST_FOREACH(ClassScopePtr cls, it->second) {
cls->getStmt()->outputCPP(cg, ar);
}
}
}
for (StringToFunctionScopePtrMap::iterator it = m_functions.begin();
it != m_functions.end(); ++it) {
FunctionScopePtr func = it->second;
if (func->isLocalRedeclaring()) {
BOOST_FOREACH(func, m_redeclaredFunctions->find(it->first)->second) {
func->getStmt()->outputCPP(cg, ar);
}
} else {
func->getStmt()->outputCPP(cg, ar);
}
}
}
void FileScope::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
assert(cg.getContext() == CodeGenerator::CppImplementation);
cg.setContext(CodeGenerator::CppConstantsDecl);
getConstants()->outputCPP(cg, ar);
cg.setContext(CodeGenerator::CppImplementation);
cg_printf("/* preface starts */\n");
for (StringToFunctionScopePtrMap::iterator it = m_functions.begin();
it != m_functions.end(); ++it) {
FunctionScopePtr func = it->second;
if (func->isLocalRedeclaring()) {
BOOST_FOREACH(func, m_redeclaredFunctions->find(it->first)->second) {
func->outputCPPPreface(cg, ar);
}
} else {
func->outputCPPPreface(cg, ar);
}
}
BOOST_FOREACH(FunctionScopeRawPtr closure, m_usedClosures) {
closure->outputCPPPreface(cg, ar);
}
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
it != m_classes.end(); ++it) {
BOOST_FOREACH(ClassScopePtr cls, it->second) {
const FunctionScopePtrVec &funcs = cls->getFunctionsVec();
for (int i = 0, size = funcs.size(); i < size; ++i) {
FunctionScopePtr func = funcs[i];
func->outputCPPPreface(cg, ar);
}
}
}
cg_printf("/* preface finishes */\n");
outputCPPHelper(cg, ar);
if (Option::GenerateCPPMacros) {
bool hasRedec;
outputCPPJumpTableSupport(cg, ar, m_redeclaredFunctions, hasRedec);
if (Option::EnableEval >= Option::LimitedEval) {
outputCPPJumpTableEvalSupport(cg, ar, m_redeclaredFunctions, hasRedec);
}
outputCPPCallInfoTableSupport(cg, ar, m_redeclaredFunctions, hasRedec);
outputCPPHelperClassAllocSupport(cg, ar, m_redeclaredFunctions);
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
it != m_classes.end(); ++it) {
BOOST_FOREACH(ClassScopePtr cls, it->second) {
if (!cls->isInterface()) {
cls->outputCPPDynamicClassImpl(cg, ar);
}
}
}
}
}
void FileScope::outputCPPPseudoMain(CodeGenerator &cg, AnalysisResultPtr ar) {
assert(cg.getContext() == CodeGenerator::CppPseudoMain);
outputCPPHelper(cg, ar, false);
}
void FileScope::outputCPPForwardDeclarations(CodeGenerator &cg,
AnalysisResultPtr ar) {
cg.setContext(CodeGenerator::CppForwardDeclaration);
BOOST_FOREACH(ClassScopeRawPtr cls, m_usedClassesFullHeader) {
if (cls->isUserClass()) {
cg_printInclude(cls->getHeaderFilename());
}
}
bool first = true;
BOOST_FOREACH(const string &str, m_usedLiteralStringsHeader) {
int index = -1;
int stringId = cg.checkLiteralString(str, index, ar, BlockScopePtr());
always_assert(index != -1);
string lisnam = ar->getLiteralStringName(stringId, index);
if (!cg.ensureInNamespace() && first) cg_printf("\n");
first = false;
if (Option::UseStaticStringProxy) {
string proxyNam = ar->getLiteralStringName(stringId, index, true);
cg_printf("extern StaticStringProxy %s;\n", proxyNam.c_str());
cg_printf("#ifndef %s\n", lisnam.c_str());
cg_printf("#define %s (*(StaticString *)(&%s))\n",
lisnam.c_str(), proxyNam.c_str());
cg_printf("#endif\n");
} else {
cg_printf("extern StaticString %s;\n", lisnam.c_str());
}
}
first = true;
BOOST_FOREACH(const int64 &val, m_usedScalarVarIntegersHeader) {
int index = -1;
int hash = ar->checkScalarVarInteger(val, index);
always_assert(index != -1);
string name = ar->getScalarVarIntegerName(hash, index);
if (!cg.ensureInNamespace() && first) cg_printf("\n");
first = false;
cg_printf("extern const VarNR &%s;\n", name.c_str());
}
first = true;
BOOST_FOREACH(const double &val, m_usedScalarVarDoublesHeader) {
int index = -1;
int hash = ar->checkScalarVarDouble(val, index);
always_assert(index != -1);
string name = ar->getScalarVarDoubleName(hash, index);
if (!cg.ensureInNamespace() && first) cg_printf("\n");
first = false;
cg_printf("extern const VarNR &%s;\n", name.c_str());
}
first = true;
BOOST_FOREACH(const string &str, m_usedLitVarStringsHeader) {
int index = -1;
int stringId = cg.checkLiteralString(str, index, ar, BlockScopePtr());
always_assert(index != -1);
string lisnam = ar->getLitVarStringName(stringId, index);
if (!cg.ensureInNamespace() && first) cg_printf("\n");
first = false;
if (Option::UseStaticStringProxy) {
string proxyName = ar->getLitVarStringName(stringId, index, true);
cg_printf("extern VariantProxy %s;\n", proxyName.c_str());
cg_printf("#ifndef %s\n", lisnam.c_str());
cg_printf("#define %s (*(Variant *)&%s)\n",
lisnam.c_str(), proxyName.c_str());
cg_printf("#endif\n");
} else {
cg_printf("extern VarNR %s;\n", lisnam.c_str());
}
}
first = true;
BOOST_FOREACH(const string &str, m_usedDefaultValueScalarArrays) {
int index = -1;
int hash = ar->checkScalarArray(str, index);
always_assert(hash != -1 && index != -1);
string name = ar->getScalarArrayName(hash, index);
if (!cg.ensureInNamespace() && first) cg_printf("\n");
first = false;
cg_printf("extern StaticArray %s;\n", name.c_str());
}
first = true;
BOOST_FOREACH(const string &str, m_usedDefaultValueScalarVarArrays) {
int index = -1;
int hash = ar->checkScalarArray(str, index);
always_assert(hash != -1 && index != -1);
string name = ar->getScalarVarArrayName(hash, index);
if (!cg.ensureInNamespace() && first) cg_printf("\n");
first = false;
cg_printf("extern VarNR %s;\n", name.c_str());
}
first = true;
BOOST_FOREACH(const string &str, m_usedConstsHeader) {
BlockScopeConstPtr block = ar->findConstantDeclarer(str);
always_assert(block);
ConstantTableConstPtr constants = block->getConstants();
if (!cg.ensureInNamespace() && first) cg_printf("\n");
first = false;
constants->outputSingleConstant(cg, ar, str);
}
first = true;
BOOST_FOREACH(const CodeGenerator::UsedClassConst& item,
m_usedClassConstsHeader) {
ClassScopePtr cls = item.first;
if (!cg.ensureInNamespace() && first) cg_printf("\n");
first = false;
cls->getConstants()->outputSingleConstant(cg, ar, item.second);
}
BOOST_FOREACH(ClassScopeRawPtr usedClass, m_usedClassesHeader) {
if (!cg.ensureInNamespace() && first) cg_printf("\n");
first = false;
usedClass->outputForwardDeclaration(cg);
}
cg.ensureOutOfNamespace();
}
void FileScope::outputCPPDeclarations(CodeGenerator &cg,
AnalysisResultPtr ar) {
cg.printSection("Declarations");
cg.setContext(CodeGenerator::CppDeclaration);
if (cg.getOutput() == CodeGenerator::MonoCPP) {
cg.namespaceBegin();
outputCPPHelper(cg, ar);
cg.namespaceEnd();
} else {
std::set<FileScopePtr> done;
done.insert(shared_from_this());
// Class declarations cunningly expressed as includes so I don't
// have to worry about inheritance dependencies.
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
it != m_classes.end(); ++it) {
BOOST_FOREACH(ClassScopePtr cls, it->second) {
cg_printInclude(cls->getHeaderFilename());
}
}
BOOST_FOREACH(string name, m_usedFuncsInline) {
FunctionScopePtr func = ar->findFunction(name);
if (func) {
FileScopePtr fs = func->getContainingFile();
if (fs && done.find(fs) == done.end()) {
done.insert(fs);
cg_printInclude(fs->outputFilebase());
}
}
}
BOOST_FOREACH(string name, m_usedIncludesInline) {
FileScopePtr fs = ar->findFileScope(name);
if (fs && done.find(fs) == done.end()) {
done.insert(fs);
cg_printInclude(fs->outputFilebase());
}
}
cg.namespaceBegin();
cg.setContext(CodeGenerator::CppForwardDeclaration);
cg.printSection("Includes and Functions", false);
outputCPPHelper(cg, ar, false); // function forward declarations
cg.setContext(CodeGenerator::CppDeclaration);
outputCPPHelper(cg, ar, false); // function declarations (only inline)
cg.printSection("Constants");
if (cg.getOutput() != CodeGenerator::MonoCPP) {
getConstants()->outputCPP(cg, ar, false);
} else {
cg_printf("// (omitted in MonoCPP mode)\n");
}
cg.namespaceEnd();
}
}
void FileScope::outputCPPForwardStaticDecl(CodeGenerator &cg,
AnalysisResultPtr ar) {
string header = outputFilebase() + ".fws.h";
cg.headerBegin(header);
cg.namespaceBegin();
cg.printSection("1. Static Strings", false);
string str;
BOOST_FOREACH(str, m_usedLiteralStrings) {
if (m_usedLiteralStringsHeader.find(str) !=
m_usedLiteralStringsHeader.end()) {
continue;
}
int index = -1;
int stringId = cg.checkLiteralString(str, index, ar, BlockScopePtr());
always_assert(index != -1);
string lisnam = ar->getLiteralStringName(stringId, index);
if (Option::UseStaticStringProxy) {
string proxyNam = ar->getLiteralStringName(stringId, index, true);
cg_printf("extern StaticStringProxy %s;\n", proxyNam.c_str());
cg_printf("#ifndef %s\n", lisnam.c_str());
cg_printf("#define %s (*(StaticString *)(&%s))\n",
lisnam.c_str(), proxyNam.c_str());
cg_printf("#endif\n");
} else {
cg_printf("extern StaticString %s;\n", lisnam.c_str());
}
}
cg_printf("\n");
cg.printSection("2. Static Arrays", false);
BOOST_FOREACH(str, m_usedScalarArrays) {
if (m_usedDefaultValueScalarArrays.find(str) !=
m_usedDefaultValueScalarArrays.end()) {
continue;
}
int index = -1;
int hash = ar->checkScalarArray(str, index);
always_assert(hash != -1 && index != -1);
string name = ar->getScalarArrayName(hash, index);
cg_printf("extern StaticArray %s;\n", name.c_str());
}
if (Option::UseScalarVariant) {
cg_printf("\n");
cg.printSection("3. Static Variants", false);
int64 val;
BOOST_FOREACH(val, m_usedScalarVarIntegers) {
if (m_usedScalarVarIntegersHeader.find(val) !=
m_usedScalarVarIntegersHeader.end()) {
continue;
}
int index = -1;
int hash = ar->checkScalarVarInteger(val, index);
always_assert(index != -1);
string name = ar->getScalarVarIntegerName(hash, index);
cg_printf("extern const VarNR &%s;\n", name.c_str());
}
cg_printf("\n");
double dval;
BOOST_FOREACH(dval, m_usedScalarVarDoubles) {
if (m_usedScalarVarDoublesHeader.find(dval) !=
m_usedScalarVarDoublesHeader.end()) {
continue;
}
int index = -1;
int hash = ar->checkScalarVarDouble(dval, index);
always_assert(index != -1);
string name = ar->getScalarVarDoubleName(hash, index);
cg_printf("extern const VarNR &%s;\n", name.c_str());
}
cg_printf("\n");
BOOST_FOREACH(str, m_usedLitVarStrings) {
if (m_usedLitVarStringsHeader.find(str) !=
m_usedLitVarStringsHeader.end()) {
continue;
}
int index = -1;
int stringId = cg.checkLiteralString(str, index, ar, BlockScopePtr());
always_assert(index != -1);
string lisnam = ar->getLitVarStringName(stringId, index);
if (Option::UseStaticStringProxy) {
string proxyName = ar->getLitVarStringName(stringId, index, true);
cg_printf("extern VariantProxy %s;\n", proxyName.c_str());
cg_printf("#ifndef %s\n", lisnam.c_str());
cg_printf("#define %s (*(Variant *)&%s)\n",
lisnam.c_str(), proxyName.c_str());
cg_printf("#endif\n");
} else {
cg_printf("extern VarNR %s;\n", lisnam.c_str());
}
}
cg_printf("\n");
BOOST_FOREACH(str, m_usedScalarVarArrays) {
if (m_usedDefaultValueScalarVarArrays.find(str) !=
m_usedDefaultValueScalarVarArrays.end()) {
continue;
}
int index = -1;
int hash = ar->checkScalarArray(str, index);
always_assert(hash != -1 && index != -1);
string name = ar->getScalarVarArrayName(hash, index);
cg_printf("extern VarNR %s;\n", name.c_str());
}
cg_printf("\n");
}
cg.namespaceEnd();
cg_printf("\n");
cg.headerEnd(header);
}
void FileScope::outputCPPDeclHeader(CodeGenerator &cg, AnalysisResultPtr ar) {
cg.setFileOrClassHeader(true);
string header = outputFilebase() + ".h";
cg.headerBegin(header);
if (Option::GenerateCppLibCode ||
cg.getOutput() == CodeGenerator::SystemCPP) {
cg.printBasicIncludes();
}
outputCPPForwardDeclarations(cg, ar);
outputCPPDeclarations(cg, ar);
cg.headerEnd(header);
}
void FileScope::outputCPPClassHeaders(AnalysisResultPtr ar,
CodeGenerator::Output output) {
ClassScopePtr cls;
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
it != m_classes.end(); ++it) {
BOOST_FOREACH(ClassScopePtr cls, it->second) {
cls->outputCPPHeader(ar, output);
}
}
}
void FileScope::outputCPPFFI(CodeGenerator &cg,
AnalysisResultPtr ar) {
cg.setContext(CodeGenerator::CppFFIDecl);
cg.useStream(CodeGenerator::PrimaryStream);
outputCPPHelper(cg, ar, true);
cg.useStream(CodeGenerator::ImplFile);
cg.setContext(CodeGenerator::CppFFIImpl);
cg_printInclude(outputFilebase() + ".h");
outputCPPHelper(cg, ar, true);
}
void FileScope::outputHSFFI(CodeGenerator &cg,
AnalysisResultPtr ar) {
cg.setContext(CodeGenerator::HsFFI);
outputCPPHelper(cg, ar, false);
}
void FileScope::outputJavaFFI(CodeGenerator &cg, AnalysisResultPtr ar) {
// first, generate methods in HphpMain.java
for (StringToFunctionScopePtrMap::iterator it = m_functions.begin();
it != m_functions.end(); ++it) {
FunctionScopePtr func = it->second;
if (func->isLocalRedeclaring()) {
BOOST_FOREACH(func, m_redeclaredFunctions->find(it->first)->second) {
func->getStmt()->outputCPP(cg, ar);
}
} else {
func->getStmt()->outputCPP(cg, ar);
}
}
// for each php class or interface, generate a Java file
for (StringToClassScopePtrVecMap::iterator it = m_classes.begin();
it != m_classes.end(); ++it) {
BOOST_FOREACH(ClassScopePtr cls, it->second) {
cls->getStmt()->outputCPP(cg, ar);
}
}
}
void FileScope::outputJavaFFICPPStub(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (cg.getContext() == CodeGenerator::JavaFFICppImpl) {
// java_stubs.h doesn't need the extra include
cg_printInclude(outputFilebase() + ".h");
}
outputCPPHelper(cg, ar, true);
}
void FileScope::outputSwigFFIStubs(CodeGenerator &cg, AnalysisResultPtr ar) {
// currently only support toplevel functions
outputCPPHelper(cg, ar, false);
}
+2 -108
Ver Arquivo
@@ -48,8 +48,8 @@ public:
ContainsDynamicVariable = 0x001,
ContainsLDynamicVariable = 0x002,
VariableArgument = 0x004,
ContainsExtract = 0x008, // need special VariableTable
ContainsCompact = 0x010, // need RVariableTable + exists()
ContainsExtract = 0x008, // contains call to extract()
ContainsCompact = 0x010, // contains call to compact()
ContainsReference = 0x020, // returns ref or has ref parameters
ReferenceVariableArgument = 0x040, // like sscanf or fscanf
ContainsUnset = 0x080, // need special handling
@@ -100,8 +100,6 @@ public:
*/
ExpressionPtr getEffectiveImpl(AnalysisResultConstPtr ar) const;
bool canUseDummyPseudoMain(AnalysisResultConstPtr ar) const;
/**
* Parser functions. Parser only deals with a FileScope object, and these
* are the only functions a parser calls upon analysis results.
@@ -115,73 +113,6 @@ public:
const StringToFunctionScopePtrVecMap *getRedecFunctions() {
return m_redeclaredFunctions;
}
void addUsedClosure(FunctionScopeRawPtr closure) {
m_usedClosures.insert(closure);
}
void addUsedLiteralString(std::string s) {
m_usedLiteralStrings.insert(s);
}
void addUsedLitVarString(std::string s) {
m_usedLitVarStrings.insert(s);
}
std::set<std::string> &getUsedLiteralStrings() {
return m_usedLiteralStrings;
}
std::set<std::string> &getUsedLitVarStrings() {
return m_usedLitVarStrings;
}
void addUsedLiteralStringHeader(std::string s) {
m_usedLiteralStringsHeader.insert(s);
}
void addUsedLitVarStringHeader(std::string s) {
m_usedLitVarStringsHeader.insert(s);
}
void addUsedScalarVarInteger(int64 i) {
m_usedScalarVarIntegers.insert(i);
}
std::set<int64> &getUsedScalarVarIntegers() {
return m_usedScalarVarIntegers;
}
void addUsedScalarVarIntegerHeader(int64 i) {
m_usedScalarVarIntegersHeader.insert(i);
}
void addUsedScalarVarDouble(double d) {
m_usedScalarVarDoubles.insert(d);
}
std::set<double> &getUsedScalarVarDoubles() {
return m_usedScalarVarDoubles;
}
void addUsedScalarVarDoubleHeader(double d) {
m_usedScalarVarDoublesHeader.insert(d);
}
void addUsedScalarArray(std::string s) {
m_usedScalarArrays.insert(s);
}
void addUsedScalarVarArray(std::string s) {
m_usedScalarVarArrays.insert(s);
}
void addUsedDefaultValueScalarArray(std::string s) {
m_usedDefaultValueScalarArrays.insert(s);
}
void addUsedDefaultValueScalarVarArray(std::string s) {
m_usedDefaultValueScalarVarArrays.insert(s);
}
void addUsedConstHeader(const std::string &s) {
m_usedConstsHeader.insert(s);
}
void addUsedClassConstHeader(ClassScopeRawPtr cls, const std::string &s) {
m_usedClassConstsHeader.insert(CodeGenerator::UsedClassConst(cls, s));
}
void addUsedClassHeader(ClassScopeRawPtr s) {
m_usedClassesHeader.insert(s);
}
void addUsedClassFullHeader(ClassScopeRawPtr s) {
m_usedClassesFullHeader.insert(s);
}
/**
* For separate compilation
@@ -244,22 +175,6 @@ public:
FunctionScopeRawPtr getPseudoMain() const {
return m_pseudoMain;
}
void outputCPPForwardStaticDecl(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPDeclHeader(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPForwardDeclarations(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPDeclarations(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPClassHeaders(AnalysisResultPtr ar,
CodeGenerator::Output output);
void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPPseudoMain(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPFFI(CodeGenerator &cg, AnalysisResultPtr ar);
void outputHSFFI(CodeGenerator &cg, AnalysisResultPtr ar);
void outputJavaFFI(CodeGenerator &cg, AnalysisResultPtr ar);
void outputJavaFFICPPStub(CodeGenerator &cg, AnalysisResultPtr ar);
void outputSwigFFIStubs(CodeGenerator &cg, AnalysisResultPtr ar);
FileScopePtr shared_from_this() {
return boost::static_pointer_cast<FileScope>
@@ -282,25 +197,6 @@ private:
vertex_descriptor m_vertex;
std::set<FunctionScopeRawPtr> m_usedClosures;
std::set<std::string> m_usedFuncsInline;
CodeGenerator::ClassScopeSet m_usedClassesHeader;
CodeGenerator::ClassScopeSet m_usedClassesFullHeader;
std::set<std::string> m_usedConstsHeader;
CodeGenerator::UsedClassConstSet m_usedClassConstsHeader;
std::set<std::string> m_usedIncludesInline;
std::set<std::string> m_usedLiteralStrings;
std::set<std::string> m_usedLitVarStrings;
std::set<std::string> m_usedLiteralStringsHeader;
std::set<std::string> m_usedLitVarStringsHeader;
std::set<int64> m_usedScalarVarIntegers;
std::set<int64> m_usedScalarVarIntegersHeader;
std::set<double> m_usedScalarVarDoubles;
std::set<double> m_usedScalarVarDoublesHeader;
std::set<std::string> m_usedScalarArrays;
std::set<std::string> m_usedScalarVarArrays;
std::set<std::string> m_usedDefaultValueScalarArrays;
std::set<std::string> m_usedDefaultValueScalarVarArrays;
std::string m_pseudoMainName;
std::set<std::string> m_pseudoMainVariables;
BlockScopeSet m_providedDefs;
@@ -308,8 +204,6 @@ private:
FunctionScopePtr createPseudoMain(AnalysisResultConstPtr ar);
void setFileLevel(StatementListPtr stmt);
void outputCPPHelper(CodeGenerator &cg, AnalysisResultPtr ar,
bool classes = true);
};
///////////////////////////////////////////////////////////////////////////////
-402
Ver Arquivo
@@ -78,405 +78,3 @@ void FunctionContainer::getFunctionsFlattened(
}
}
}
class FunctionIterator {
public:
FunctionIterator(const StringToFunctionScopePtrVecMap &mmap,
bool &hasRedec) : m_mmap(&mmap), m_smap(0),
m_miter(mmap.begin()),
m_hasRedec(hasRedec) {
setup();
}
FunctionIterator(const StringToFunctionScopePtrMap &smap,
const StringToFunctionScopePtrVecMap *mmap,
bool &hasRedec) : m_mmap(mmap), m_smap(&smap),
m_siter(smap.begin()),
m_hasRedec(hasRedec) {
setup();
}
bool ready() const {
if (m_smap) {
return m_siter != m_smap->end();
} else {
return m_miter != m_mmap->end();
}
}
bool firstInner() const {
if (m_smap && !m_siter->second->isLocalRedeclaring()) {
return true;
}
return m_innerIter == m_miter->second.begin();
}
void next() {
if (m_smap && !m_siter->second->isLocalRedeclaring()) {
++m_siter;
setup();
return;
}
++m_innerIter;
if (m_innerIter == m_miter->second.end()) {
if (m_smap) {
++m_siter;
} else {
++m_miter;
}
setup();
}
}
const string &name() const {
return m_smap ? m_siter->first : m_miter->first;
}
FunctionScopePtr get() const {
return m_smap && !m_siter->second->isLocalRedeclaring() ?
m_siter->second : *m_innerIter;
}
private:
const StringToFunctionScopePtrVecMap *m_mmap;
const StringToFunctionScopePtrMap *m_smap;
StringToFunctionScopePtrVecMap::const_iterator m_miter;
FunctionScopePtrVec::const_iterator m_innerIter;
StringToFunctionScopePtrMap::const_iterator m_siter;
bool &m_hasRedec;
void setup() {
if (ready()) {
if (m_smap) {
if (!m_siter->second->isRedeclaring()) {
return;
}
m_hasRedec = true;
if (!m_siter->second->isLocalRedeclaring()) {
return;
}
m_miter = m_mmap->find(m_siter->first);
} else {
if (m_miter->second.size() != 1) {
m_hasRedec = true;
}
}
m_innerIter = m_miter->second.begin();
}
}
};
void FunctionContainer::outputCPPJumpTableSupportMethod
(CodeGenerator &cg, AnalysisResultPtr ar, FunctionScopePtr func,
const char *funcPrefix) {
string name = func->getId();
const char *cname = name.c_str();
string origName = !func->inPseudoMain() ? func->getOriginalName() :
("run_init::" + func->getContainingFile()->getName());
cg_printf("Variant");
if (Option::FunctionSections.find(origName) !=
Option::FunctionSections.end()) {
string funcSection = Option::FunctionSections[origName];
if (!funcSection.empty()) {
cg_printf(" __attribute__ ((section (\".text.%s\")))",
funcSection.c_str());
}
}
cg_indentBegin(" %s%s(void *extra, int count, "
"INVOKE_FEW_ARGS_IMPL_ARGS) {\n",
Option::InvokeFewArgsPrefix, cname);
func->outputCPPDynamicInvoke(cg, ar, funcPrefix, cname, false, true);
cg_indentEnd("}\n");
cg_indentBegin("Variant %s%s(void *extra, CArrRef params) {\n",
Option::InvokePrefix, cname);
if (func->getMaxParamCount() <= Option::InvokeFewArgsCount &&
!func->isVariableArgument()) {
if (Option::InvokeWithSpecificArgs && !func->getMaxParamCount() &&
!ar->isSystem() && !ar->isSepExtension()) {
// For functions with no parameter, we can combine the i_ wrapper and
// the ifa_ wrapper.
cg_printf("return ((CallInfo::FuncInvoker0Args)&%s%s)(extra, 0);\n",
Option::InvokeFewArgsPrefix, cname);
} else {
cg_printf("return invoke_func_few_handler(extra, params, &%s%s);\n",
Option::InvokeFewArgsPrefix, cname);
}
} else {
FunctionScope::OutputCPPDynamicInvokeCount(cg);
func->outputCPPDynamicInvoke(cg, ar, funcPrefix, cname);
}
cg_indentEnd("}\n");
}
void
FunctionContainer::outputCPPHelperClassAllocSupport(
CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec) {
bool hasRedeclared;
for (FunctionIterator fit(m_functions, redec, hasRedeclared); fit.ready();
fit.next()) {
FunctionScopePtr func = fit.get();
func->outputCPPHelperClassAlloc(cg, ar);
}
}
void FunctionContainer::outputCPPJumpTableSupport(
CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec, bool &hasRedeclared,
vector<const char *> *funcs /* = NULL */) {
bool systemcpp = cg.getOutput() == CodeGenerator::SystemCPP;
const char *funcPrefix = Option::FunctionPrefix;
if (systemcpp) funcPrefix = Option::BuiltinFunctionPrefix;
// output invoke support methods
for (FunctionIterator fit(m_functions, redec, hasRedeclared); fit.ready();
fit.next()) {
FunctionScopePtr func = fit.get();
if (func->inPseudoMain() || !(systemcpp || func->isDynamic())) continue;
if (funcs && fit.firstInner()) {
funcs->push_back(fit.name().c_str());
}
outputCPPJumpTableSupportMethod(cg, ar, func, funcPrefix);
}
}
void FunctionContainer::outputCPPCallInfoTableSupport(
CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec, bool &hasRedeclared,
vector<const char *> *funcs /* = NULL */) {
bool systemcpp = cg.getOutput() == CodeGenerator::SystemCPP;
for (FunctionIterator fit(m_functions, redec, hasRedeclared); fit.ready();
fit.next()) {
FunctionScopePtr func = fit.get();
if (func->inPseudoMain() || !(systemcpp || func->isDynamic())) continue;
if (funcs && fit.firstInner()) {
funcs->push_back(fit.name().c_str());
}
func->outputCPPCallInfo(cg, ar);
}
}
void FunctionContainer::outputCPPJumpTableEvalSupport(
CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec,
bool &hasRedeclared) {
bool systemcpp = cg.getOutput() == CodeGenerator::SystemCPP;
// output invoke support methods
for (FunctionIterator fit(m_functions, redec, hasRedeclared); fit.ready();
fit.next()) {
FunctionScopePtr func = fit.get();
if (func->inPseudoMain() ||
(!systemcpp && (!func->isUserFunction() ||
!(func->isSepExtension() || func->isDynamic())))) {
continue;
}
string sname = func->getId();
}
}
void FunctionContainer::outputGetCallInfoHeader(CodeGenerator &cg,
const char *suffix,
bool needGlobals) {
cg_indentBegin("bool get_call_info%s(const CallInfo *&ci, void *&extra, "
"const char *s, strhash_t hash) {\n", suffix ? suffix : "");
if (needGlobals) cg.printDeclareGlobals();
cg_printf("extra = NULL;\n");
if (!suffix && (!Option::DynamicInvokeFunctions.empty() ||
Option::EnableEval == Option::FullEval)) {
cg_printf("const char *ss = get_renamed_function(s);\n");
cg_printf("if (ss != s) { s = ss; hash = -1;};\n");
}
}
void FunctionContainer::outputGetCallInfoTail(CodeGenerator &cg,
bool system) {
if (system) {
cg_printf("return false;\n");
} else {
cg_printf("return get_call_info_builtin(ci, extra, s, hash);\n");
}
cg_indentEnd("}\n");
}
void FunctionContainer::outputCPPHashTableGetCallInfo(
CodeGenerator &cg, bool system, bool noEval,
const StringToFunctionScopePtrMap *functions,
const vector<const char *> &funcs) {
assert(cg.getCurrentIndentation() == 0);
const char text1[] =
"\n"
"struct hashNodeFunc {\n"
" strhash_t hash;\n"
" bool offset;\n"
" bool end;\n"
" const char *name;\n"
" const void *data;\n"
"};\n"
"static const hashNodeFunc funcBuckets[] = {\n";
const char text3[] =
"static inline const hashNodeFunc *"
"findFunc(const char *name, strhash_t hash) {\n"
" const hashNodeFunc *p = funcMapTable[hash & %d];\n"
" if (UNLIKELY(!p)) return NULL;\n"
" do {\n"
" if (LIKELY(p->hash == hash) && (LIKELY(p->name==name)||"
"LIKELY(!strcasecmp(p->name, name)))) return p;\n"
" } while (!p++->end);\n"
" return NULL;\n"
"}\n"
"\n";
const char text4[] =
" if (hash < 0) hash = hash_string(s);\n"
" const hashNodeFunc *p = findFunc(s, hash);\n"
" if (LIKELY(p!=0)) {\n"
" if (UNLIKELY(p->offset)) {\n"
" DECLARE_GLOBAL_VARIABLES(g);\n"
" const char *addr = (const char *)g + (int64)p->data;\n"
" ci = *(const CallInfo **)addr;\n"
" return ci != 0;\n"
" } else {\n"
" ci = (const CallInfo *)p->data;\n"
" return true;\n"
" }\n"
" }\n";
const char text4s[] =
" if (hash < 0) hash = hash_string(s);\n"
" const hashNodeFunc *p = findFunc(s, hash);\n"
" if (LIKELY(p!=0)) {\n"
" ci = (const CallInfo *)p->data;\n"
" return true;\n"
" }\n";
int numEntries = funcs.size();
if (!noEval && numEntries > 0) {
JumpTable jt(cg, funcs, true, true, true, true);
cg_print(text1);
vector<int> offsets;
int prev = -1;
for (int n = 0; jt.ready(); ++n, jt.next()) {
int cur = jt.current();
if (prev != cur) {
while (++prev != cur) {
offsets.push_back(-1);
}
offsets.push_back(n);
}
const char *name = jt.key();
StringToFunctionScopePtrMap::const_iterator iterFuncs =
functions->find(name);
assert(iterFuncs != functions->end());
// We have assumptions that function names do not contain ".."
// (e.g., call_user_func0 ~ call_user_func6)
always_assert(!strstr(name, ".."));
FunctionScopePtr func = iterFuncs->second;
cg_printf(" {" STRHASH_FMT ",%d,%d,\"%s\",",
hash_string_i(name),
(int)func->isRedeclaring(), (int)jt.last(),
CodeGenerator::EscapeLabel(name).c_str());
if (func->isRedeclaring()) {
always_assert(!system);
string lname(CodeGenerator::FormatLabel(name));
cg_printf("(const void *)(offsetof(GlobalVariables, GCI(%s)))",
lname.c_str());
} else {
cg_printf("&%s%s",
Option::CallInfoPrefix, func->getId().c_str());
}
cg_printf("},\n");
}
cg_printf("};\n");
cg_indentBegin("static const hashNodeFunc *funcMapTable[] = {\n");
for (int i = 0, e = jt.size(), s = offsets.size(); i < e; i++) {
int o = i < s ? offsets[i] : -1;
if (o < 0) {
cg_printf("0,");
} else {
cg_printf("funcBuckets+%d,", o);
}
if ((i & 7) == 7) cg_printf("\n");
}
cg_printf("\n");
cg_indentEnd("};\n");
cg_printf(text3, jt.size() - 1);
}
outputGetCallInfoHeader(cg, system ? "_builtin" : noEval ? "_no_eval" : 0,
false);
cg_indentEnd();
if (numEntries > 0) {
cg_print(system ? text4s : text4);
}
cg_indentBegin(" ");
outputGetCallInfoTail(cg, system);
}
void FunctionContainer::outputCPPCodeInfoTable(
CodeGenerator &cg, AnalysisResultPtr ar, bool useSwitch,
const StringToFunctionScopePtrMap &functions) {
bool needGlobals = false;
vector<const char *> funcs;
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
if (system) {
outputCPPCallInfoTableSupport(cg, ar, 0, needGlobals, nullptr);
}
for (StringToFunctionScopePtrMap::const_iterator iter = functions.begin(),
end = functions.end(); iter != end; ++iter) {
FunctionScopePtr func = iter->second;
if (!func->inPseudoMain() &&
(system || func->isDynamic() || func->isSepExtension())) {
funcs.push_back(iter->first.c_str());
if (!system && !func->isRedeclaring() && !func->isSepExtension()) {
cg_printf("extern const CallInfo %s%s;\n",
Option::CallInfoPrefix, func->getId().c_str());
}
}
}
if (!useSwitch) {
outputCPPHashTableGetCallInfo(cg, system, false, &functions, funcs);
if (!system) {
outputCPPHashTableGetCallInfo(cg, system, true, &functions, funcs);
}
return;
}
if (!system) cg_printf("static ");
outputGetCallInfoHeader(cg, system ? "_builtin" : "_impl", needGlobals);
for (JumpTable fit(cg, funcs, true, true, false); fit.ready(); fit.next()) {
const char *name = fit.key();
StringToFunctionScopePtrMap::const_iterator iterFuncs =
functions.find(name);
assert(iterFuncs != functions.end());
cg_indentBegin("HASH_GUARD(" STRHASH_FMT ", %s) {\n",
hash_string_i(name),
CodeGenerator::EscapeLabel(name).c_str());
if (iterFuncs->second->isRedeclaring()) {
string lname(CodeGenerator::FormatLabel(name));
cg_printf("ci = &g->GCI(%s)->ci;\n", lname.c_str());
} else {
cg_printf("ci = &%s%s;\n", Option::CallInfoPrefix,
iterFuncs->second->getId().c_str());
}
cg_printf("return true;\n");
cg_indentEnd("}\n");
}
outputGetCallInfoTail(cg, system);
if (system) return;
outputGetCallInfoHeader(cg, 0, false);
cg_printf("return get_call_info_impl(ci, extra, s, hash);\n");
cg_indentEnd("}\n");
outputGetCallInfoHeader(cg, "_no_eval", false);
cg_printf("return get_call_info_impl(ci, extra, s, hash);\n");
cg_indentEnd("}\n");
}
-34
Ver Arquivo
@@ -18,7 +18,6 @@
#define __FUNCTION_CONTAINER_H__
#include <compiler/hphp.h>
#include <compiler/util/jump_table.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
@@ -43,49 +42,16 @@ public:
void countReturnTypes(std::map<std::string, int> &counts,
const StringToFunctionScopePtrVecMap *redec);
/**
* Code generation functions.
*/
void outputCPPJumpTable(CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec);
const StringToFunctionScopePtrMap &getFunctions() const {
return m_functions;
}
void getFunctionsFlattened(const StringToFunctionScopePtrVecMap *redec,
FunctionScopePtrVec &funcs,
bool excludePseudoMains = false) const;
void outputCPPCodeInfoTable(
CodeGenerator &cg, AnalysisResultPtr ar, bool useSwitch,
const StringToFunctionScopePtrMap &functions);
protected:
// name => functions. Order of declaration
StringToFunctionScopePtrMap m_functions;
void outputCPPJumpTableSupport(CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec,
bool &hasRedeclared,
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 = nullptr);
void outputCPPJumpTableSupportMethod(CodeGenerator &cg, AnalysisResultPtr ar,
FunctionScopePtr func,
const char *funcPrefix);
void outputCPPHelperClassAllocSupport(
CodeGenerator &cg, AnalysisResultPtr ar,
const StringToFunctionScopePtrVecMap *redec);
private:
void outputGetCallInfoHeader(CodeGenerator &cg, const char *suffix,
bool needGlobals);
void outputGetCallInfoTail(CodeGenerator &cg, bool system);
void outputCPPHashTableGetCallInfo(
CodeGenerator &cg, bool system, bool noEval,
const StringToFunctionScopePtrMap *functions,
const std::vector<const char *> &funcs);
};
///////////////////////////////////////////////////////////////////////////////
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+10 -105
Ver Arquivo
@@ -176,6 +176,13 @@ public:
m_volatile = false;
}
/**
* Tell this function about another outer scope that contains it.
*/
void addClonedTraitOuterScope(FunctionScopePtr scope) {
m_clonedTraitOuterScope.push_back(scope);
}
/**
* Get/set original name of the function, without case being lowered.
*/
@@ -237,16 +244,10 @@ public:
* Whether this function contains a usage of $this
*/
bool containsThis() const { return m_containsThis;}
void setContainsThis(bool f=true) { m_containsThis = f;}
void setContainsThis(bool f = true);
bool containsBareThis() const { return m_containsBareThis; }
bool containsRefThis() const { return m_containsBareThis & 2; }
void setContainsBareThis(bool f, bool ref = false) {
if (f) {
m_containsBareThis |= ref ? 2 : 1;
} else {
m_containsBareThis = 0;
}
}
void setContainsBareThis(bool f, bool ref = false);
/**
* How many parameters a caller should provide.
*/
@@ -270,7 +271,6 @@ public:
void fixRetExprs();
bool needsTypeCheckWrapper() const;
const char *getPrefix(AnalysisResultPtr ar, ExpressionListPtr params);
void setOptFunction(FunctionOptPtr fn) { m_optFunction = fn; }
FunctionOptPtr getOptFunction() const { return m_optFunction; }
@@ -352,92 +352,6 @@ public:
* Override BlockScope::outputPHP() to generate return type.
*/
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* Override to preface with call temps.
*/
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* Generate parameter declaration.
*/
void outputCPPParamsDecl(CodeGenerator &cg, AnalysisResultPtr ar,
ExpressionListPtr params, bool showDefault);
/**
* This one is a special version that doesn't require a params expression.
* It's for use with extension functions. It only works for the
* implementation since it ignores optional arguments.
*/
void outputCPPParamsImpl(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* If inside this function, we have to make a call to an implementation
* function that has the same signature, how does the parameter list
* look like?
*/
void outputCPPParamsCall(CodeGenerator &cg, AnalysisResultPtr ar,
bool aggregateParams);
/**
* How does a caller prepare parameters.
*/
static void OutputCPPArguments(ExpressionListPtr params,
FunctionScopePtr func,
CodeGenerator &cg, AnalysisResultPtr ar,
int extraArg, bool variableArgument,
int extraArgArrayId = -1,
int extraArgArrayHash = -1,
int extraArgArrayIndex = -1,
bool ignoreFuncParamTypes = false);
/**
* Only generate arguments that have effects. This is for keeping those
* parameters around when generating a error-raising function call, so to
* avoid "unused" variable compiler warnings.
*/
static void OutputCPPEffectiveArguments(ExpressionListPtr params,
CodeGenerator &cg,
AnalysisResultPtr ar);
/**
* Generate invoke proxy.
*/
static void OutputCPPDynamicInvokeCount(CodeGenerator &cg);
void outputCPPDynamicInvoke(CodeGenerator &cg, AnalysisResultPtr ar,
const char *funcPrefix,
const char *name,
bool voidWrapperOff = false,
bool fewArgs = false,
bool ret = true,
const char *extraArg = nullptr,
bool constructor = false,
const char *instance = nullptr,
const char *class_name = "");
void outputCPPDef(CodeGenerator &cg);
/**
* ...so ClassStatement can call them for classes that don't have
* constructors defined
*/
void outputCPPCreateDecl(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPCreateImpl(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* output functions
*/
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar);
void outputMethodWrapper(CodeGenerator &cg, AnalysisResultPtr ar,
const char *clsToConstruct);
/**
* Output CallInfo instance for this function.
*/
void outputCPPCallInfo(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPPreface(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPHelperClassAlloc(CodeGenerator &cg,
AnalysisResultPtr ar);
/**
* Serialize the iface, not everything.
*/
@@ -518,14 +432,6 @@ public:
};
private:
bool outputCPPArrayCreate(CodeGenerator &cg,
AnalysisResultPtr ar,
int m_maxParam);
void outputCPPSubClassParam(CodeGenerator &cg,
AnalysisResultPtr ar,
ParameterExpressionPtr param);
void init(AnalysisResultConstPtr ar);
static StringToFunctionInfoPtrMap s_refParamInfo;
@@ -582,13 +488,12 @@ private:
StatementPtr m_stmtCloned; // cloned method body stmt
int m_inlineIndex;
FunctionOptPtr m_optFunction;
int outputCPPInvokeArgCountCheck(CodeGenerator &cg, AnalysisResultPtr ar,
bool ret, bool constructor, int maxCount);
ExpressionPtrVec m_retExprsToFix;
ExpressionListPtr m_closureVars;
ExpressionListPtr m_closureValues;
ReadWriteMutex m_inlineMutex;
unsigned m_nextID; // used when cloning generators for traits
std::list<FunctionScopeRawPtr> m_clonedTraitOuterScope;
};
///////////////////////////////////////////////////////////////////////////////
+2 -17
Ver Arquivo
@@ -461,25 +461,11 @@ bool LiveDict::color(TypePtr type) {
if (Type::SameType(type, e->getCPPType())) {
SimpleVariablePtr sv(
static_pointer_cast<SimpleVariable>(e));
bool isGenParam = false;
if (sv->getFunctionScope()->isGenerator()) {
// do not allow coalescing of symbols which are parameters/use vars
// in the generator (sym->isParameter() will be false b/c we are in
// the scope of the generator function)
FunctionScopeRawPtr origScope(sv->getFunctionScope()->getOrigGenFS());
assert(origScope);
Symbol *origSym =
origScope->getVariables()->getSymbol(sv->getName());
if (origSym &&
(origSym->isParameter() || origSym->isClosureVar())) {
isGenParam = true;
}
}
Symbol *sym = sv->getSymbol();
if (sym &&
!sym->isGlobal() &&
!sym->isParameter() &&
!isGenParam &&
!sym->isGeneratorParameter() &&
!sym->isClosureVar() &&
!sym->isStatic() &&
!e->isThis()) {
@@ -623,9 +609,8 @@ public:
always_assert(e && e->is(Expression::KindOfSimpleVariable));
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
Symbol *sym = sv->getSymbol();
bool inGen = sv->getFunctionScope()->isGenerator();
if (!sym || sym->isGlobal() || sym->isStatic() || sym->isParameter() ||
sym->isClosureVar() || sv->isThis() || inGen) {
sym->isGeneratorParameter() || sym->isClosureVar() || sv->isThis()) {
continue;
}
+11 -1
Ver Arquivo
@@ -115,6 +115,8 @@ public:
bool isIndirectAltered() const { return m_flags.m_indirectAltered; }
bool isReferenced() const { return !m_flags.m_notReferenced; }
bool isHidden() const { return m_flags.m_hidden; }
bool isGeneratorParameter() const { return m_flags.m_generatorParameter; }
bool isRefGeneratorParameter() const { return m_flags.m_refGeneratorParameter; }
bool isClosureVar() const { return m_flags.m_closureVar; }
bool isRefClosureVar() const { return m_flags.m_refClosureVar; }
bool isPassClosureVar() const { return m_flags.m_passClosureVar; }
@@ -140,6 +142,8 @@ public:
void setIndirectAltered() { m_flags.m_indirectAltered = true; }
void setReferenced() { m_flags.m_notReferenced = false; }
void setHidden() { m_flags.m_hidden = true; }
void setGeneratorParameter() { m_flags.m_generatorParameter = true; }
void setRefGeneratorParameter() { m_flags.m_refGeneratorParameter = true; }
void setClosureVar() { m_flags.m_closureVar = true; }
void setRefClosureVar() { m_flags.m_refClosureVar = true; }
void setPassClosureVar() { m_flags.m_passClosureVar = true; }
@@ -185,7 +189,7 @@ private:
std::string m_name;
unsigned int m_hash;
union {
unsigned m_flags_val;
uint64_t m_flags_val;
struct {
/* internal */
unsigned m_declaration_set : 1;
@@ -219,6 +223,8 @@ private:
unsigned m_indirectAltered : 1;
unsigned m_notReferenced : 1;
unsigned m_hidden : 1;
unsigned m_generatorParameter : 1;
unsigned m_refGeneratorParameter : 1;
unsigned m_closureVar : 1;
unsigned m_refClosureVar : 1;
unsigned m_passClosureVar : 1;
@@ -227,6 +233,10 @@ private:
unsigned m_stashedVal : 1;
unsigned m_reseated : 1;
} m_flags;
static_assert(
sizeof(m_flags_val) == sizeof(m_flags),
"m_flags_val must cover all the flags");
};
ConstructPtr m_declaration;
ConstructPtr m_value;
-91
Ver Arquivo
@@ -589,37 +589,6 @@ ClassScopePtr Type::getClass(AnalysisResultConstPtr ar,
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;
@@ -646,66 +615,6 @@ DataType Type::getHhvmDataType() const {
}
}
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";
-26
Ver Arquivo
@@ -225,35 +225,9 @@ public:
ClassScopePtr getClass(AnalysisResultConstPtr ar,
BlockScopeRawPtr scope) const;
/**
* Generate type specifier in C++.
*/
std::string getCPPDecl(AnalysisResultConstPtr ar,
BlockScopeRawPtr scope,
CodeGenerator *cg = 0);
DataType getDataType() const;
DataType getHhvmDataType() const;
void outputCPPDecl(CodeGenerator &cg, AnalysisResultConstPtr ar,
BlockScopeRawPtr scope);
/**
* Generate type conversion in C++.
*/
void outputCPPFastObjectCast(CodeGenerator &cg,
AnalysisResultConstPtr ar,
BlockScopeRawPtr scope,
bool isConst);
void outputCPPCast(CodeGenerator &cg, AnalysisResultConstPtr ar,
BlockScopeRawPtr scope);
/**
* Generate variable initialization code.
*/
const char *getCPPInitializer();
/**
* Type hint names in PHP.
*/
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
-52
Ver Arquivo
@@ -137,15 +137,6 @@ public:
virtual bool isInherited(const std::string &name) const;
const char *getVariablePrefix(const std::string &name) const;
const char *getVariablePrefix(const Symbol *sym) const;
std::string getVariableName(AnalysisResultConstPtr ar,
const std::string &name) const;
std::string getVariableName(AnalysisResultConstPtr ar,
const Symbol *sym) const;
std::string getGlobalVariableName(AnalysisResultConstPtr ar,
const std::string &name) const;
void getLocalVariableNames(std::vector<std::string> &syms) const;
/**
@@ -289,33 +280,6 @@ public:
* Generate all variable declarations for this symbol table.
*/
void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
bool outputCPPPropertyDecl(CodeGenerator &cg, AnalysisResultPtr ar,
bool dynamicObject = false);
void outputCPPClassMap(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPStaticVariables(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPStaticLocals(CodeGenerator &cg, AnalysisResultPtr ar,
bool forInitList);
void outputCPPGlobalVariablesDtorIncludes(CodeGenerator &cg,
AnalysisResultPtr ar);
void outputCPPGlobalVariablesDtor(CodeGenerator &cg);
void outputCPPGVHashTableGetImpl(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPGlobalVariablesGetImpl(CodeGenerator &cg,
AnalysisResultPtr ar);
void outputCPPGVHashTableExists(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPGlobalVariablesExists(CodeGenerator &cg,
AnalysisResultPtr ar);
void outputCPPGVHashTableGetIndex(CodeGenerator &cg,
AnalysisResultPtr ar);
void outputCPPGlobalVariablesGetIndex(CodeGenerator &cg,
AnalysisResultPtr ar);
void outputCPPGlobalVariablesMethods(CodeGenerator &cg,
AnalysisResultPtr ar);
void collectCPPGlobalSymbols(StringPairSetVec &symbols, CodeGenerator &cg,
AnalysisResultPtr ar);
/**
* Whether or not the specified jump table is empty.
*/
@@ -383,22 +347,6 @@ private:
TypePtr type, bool coerce);
virtual void dumpStats(std::map<std::string, int> &typeCounts);
void outputCPPGlobalVariablesHeader(CodeGenerator &cg,
AnalysisResultPtr ar);
void outputCPPGlobalVariablesImpl(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPVariableTable(CodeGenerator &cg, AnalysisResultPtr ar,
const char *paramPrefix);
bool outputCPPJumpTable(CodeGenerator &cg, AnalysisResultPtr ar,
const char *prefix, bool defineHash,
bool variantOnly, StaticSelection staticVar,
JumpTableType type = JumpReturn,
PrivateSelection privateVar = NonPrivate,
bool *declaredGlobals = nullptr);
bool outputCPPPrivateSelector(CodeGenerator &cg, AnalysisResultPtr ar,
const char *op, const char *args);
void outputCPPVariableInit(CodeGenerator &cg, AnalysisResultPtr ar,
bool inPseudoMain, const std::string &name);
void checkSystemGVOrder(SymbolSet &variants, unsigned int max);
};
+4 -4
Ver Arquivo
@@ -183,7 +183,7 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
if (sep) {
fs->setSepExtension();
}
int flags = (int)(int64)(*p++);
int flags = (int)(int64_t)(*p++);
if (flags & ClassInfo::IsAbstract) {
fs->addModifier(T_ABSTRACT);
}
@@ -209,7 +209,7 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
p++;
// Parse properties
while (*p) {
int flags = (int)(int64)(*p++);
int flags = (int)(int64_t)(*p++);
ModifierExpressionPtr modifiers(
new ModifierExpression(BlockScopePtr(), LocationPtr()));
if (flags & ClassInfo::IsProtected) {
@@ -233,7 +233,7 @@ void BuiltinSymbols::ParseExtClasses(AnalysisResultPtr ar, const char **p,
}
p++;
int flags = (int)(int64)(*p++);
int flags = (int)(int64_t)(*p++);
cl->setClassInfoAttribute(flags);
if (flags & ClassInfo::HasDocComment) {
cl->setDocComment(*p++);
@@ -295,7 +295,7 @@ FunctionScopePtr BuiltinSymbols::ParseExtFunction(AnalysisResultPtr ar,
index++;
}
int flags = (int)(int64)(*p++);
int flags = (int)(int64_t)(*p++);
f->setClassInfoAttribute(flags);
if (flags & ClassInfo::HasDocComment) {
f->setDocComment(*p++);
+1 -236
Ver Arquivo
@@ -61,8 +61,7 @@ CodeGenerator::CodeGenerator(std::ostream *primary,
Output output /* = PickledPHP */,
const std::string *filename /* = NULL */)
: m_out(nullptr), m_output(output),
m_hoistedClasses(0), m_collectHoistedClasses(false),
m_context(NoContext), m_insideScalarArray(false), m_itemIndex(-1) {
m_context(NoContext), m_itemIndex(-1) {
for (int i = 0; i < StreamCount; i++) {
m_streams[i] = nullptr;
m_indentation[i] = 0;
@@ -140,46 +139,6 @@ void CodeGenerator::indentEnd() {
m_indentation[m_curStream]--;
}
bool CodeGenerator::wrapExpressionBegin() {
if (!m_wrappedExpression[m_curStream]) {
m_wrappedExpression[m_curStream] = true;
m_referenceTempsUsed[m_curStream] = false;
m_localId[m_curStream] = 0;
setInExpression(true);
indentBegin("{\n");
return true;
}
return false;
}
bool CodeGenerator::wrapExpressionEnd() {
if (m_wrappedExpression[m_curStream]) {
if (m_referenceTempsUsed[m_curStream]) {
printf("%s.unset();\n", m_referenceTemps[m_curStream].c_str());
}
m_wrappedExpression[m_curStream] = false;
indentEnd("}\n");
return true;
}
return false;
}
void CodeGenerator::genReferenceTemp(ConstructPtr cp) {
string &rt = m_referenceTemps[m_curStream];
rt = (string)Option::TempPrefix + "_ref";
printf("Variant %s;\n", rt.c_str());
}
const string &CodeGenerator::getReferenceTemp() {
static string empty = "";
if (m_wrappedExpression[m_curStream] &&
!m_referenceTemps[m_curStream].empty()) {
m_referenceTempsUsed[m_curStream] = true;
return m_referenceTemps[m_curStream];
}
return empty;
}
bool CodeGenerator::inComments() const {
return m_inComments[m_curStream] > 0;
}
@@ -248,20 +207,6 @@ bool CodeGenerator::ensureOutOfNamespace() {
return true;
}
void CodeGenerator::headerBegin(const std::string &file) {
string formatted = getFormattedName(file);
printf("\n");
printf("#ifndef __GENERATED_%s__\n", formatted.c_str());
printf("#define __GENERATED_%s__\n", formatted.c_str());
printf("\n");
}
void CodeGenerator::headerEnd(const std::string &file) {
string formatted = getFormattedName(file);
printf("\n");
printf("#endif // __GENERATED_%s__\n", formatted.c_str());
}
void CodeGenerator::ifdefBegin(bool ifdef, const char *fmt, ...) {
printf(ifdef ? "#ifdef " : "#ifndef ");
va_list ap; va_start(ap, fmt); print(fmt, ap); va_end(ap);
@@ -274,59 +219,6 @@ void CodeGenerator::ifdefEnd(const char *fmt, ...) {
printf("\n");
}
void CodeGenerator::printInclude(const std::string &file) {
assert(!file.empty());
string formatted = file;
if (file[0] != '"' && file[0] != '<') {
if (file.substr(file.length() - 2) != ".h") {
formatted += ".h";
}
formatted = string("<") + formatted + '>';
}
printf("%s %s\n", HASH_INCLUDE, formatted.c_str());
}
void CodeGenerator::printBasicIncludes() {
if (Option::GenerateCPPMain) {
printInclude("<runtime/base/hphp.h>");
printInclude(string(Option::SystemFilePrefix) +
"literal_strings_remap.h");
printInclude(string(Option::SystemFilePrefix) +
"scalar_arrays_remap.h");
if (Option::UseScalarVariant) {
printInclude(string(Option::SystemFilePrefix) +
"scalar_integers_remap.h");
}
printInclude(string(Option::SystemFilePrefix) + "global_variables.h");
if (Option::GenArrayCreate) {
printInclude(string(Option::SystemFilePrefix) + "cpputil.h");
}
} else if (getOutput() == CodeGenerator::SystemCPP) {
printInclude("<runtime/base/hphp_system.h>");
printInclude(string("system/gen/") + Option::SystemFilePrefix +
"literal_strings_remap.h");
printInclude(string("system/gen/") + Option::SystemFilePrefix +
"scalar_arrays_remap.h");
}
}
void CodeGenerator::printDeclareGlobals() {
if (getOutput() == SystemCPP) {
printf("DECLARE_SYSTEM_GLOBALS(g);\n");
} else {
printf("DECLARE_GLOBAL_VARIABLES(g);\n");
}
}
void CodeGenerator::printStartOfJumpTable(int tableSize) {
if (Util::isPowerOfTwo(tableSize)) {
indentBegin("switch (hash & %d) {\n", tableSize-1);
} else {
indentBegin("switch (hash %% %d) {\n", tableSize);
}
}
void CodeGenerator::printDocComment(const std::string comment) {
if (comment.empty()) return;
string escaped;
@@ -342,24 +234,6 @@ void CodeGenerator::printDocComment(const std::string comment) {
printf("\n");
}
void CodeGenerator::printImplStarter() {
printf("%s\n", STARTER_MARKER);
}
void CodeGenerator::printImplSplitter() {
printf("%s\n", SPLITTER_MARKER);
}
const char *CodeGenerator::getGlobals(AnalysisResultPtr ar) {
if (m_context == CppParameterDefaultValueDecl ||
m_context == CppParameterDefaultValueImpl) {
return (m_output == CodeGenerator::SystemCPP) ?
"get_system_globals()" : "get_global_variables()";
}
if (m_output == CodeGenerator::SystemCPP) return "get_system_globals()";
return "g";
}
std::string CodeGenerator::FormatLabel(const std::string &name) {
string ret;
ret.reserve(name.size());
@@ -523,14 +397,6 @@ int CodeGenerator::callInfoTop() {
return m_callInfos.back();
}
bool CodeGenerator::getInsideScalarArray() {
return m_insideScalarArray;
}
void CodeGenerator::setInsideScalarArray(bool flag) {
m_insideScalarArray = flag;
}
void CodeGenerator::addLabelId(const char *name, int labelId) {
if (!strcmp(name, "break")) {
m_breakLabelIds.insert(labelId);
@@ -552,107 +418,6 @@ bool CodeGenerator::findLabelId(const char *name, int labelId) {
return false;
}
int CodeGenerator::checkLiteralString(const std::string &str, int &index,
AnalysisResultPtr ar, BlockScopePtr bs,
bool scalarVariant /* = false */) {
always_assert(getContext() != CodeGenerator::CppConstantsDecl &&
getContext() != CodeGenerator::CppClassConstantsImpl);
int stringId = ar->getLiteralStringId(str, index);
if (m_literalScope) {
bs = m_literalScope;
}
if (bs && bs != ar) {
FileScopePtr fs = bs->getContainingFile();
if (fs) {
fs->addUsedLiteralString(str);
if (scalarVariant) fs->addUsedLitVarString(str);
if (isFileOrClassHeader()) {
ClassScopePtr cs = bs->getContainingClass();
if (cs) {
cs->addUsedLiteralStringHeader(str);
if (scalarVariant) cs->addUsedLitVarStringHeader(str);
} else {
fs->addUsedLiteralStringHeader(str);
if (scalarVariant) fs->addUsedLitVarStringHeader(str);
}
}
}
}
return stringId;
}
string CodeGenerator::printNamedString(const string &str,
const string &escaped, AnalysisResultPtr ar, BlockScopeRawPtr bs,
bool print) {
int index = -1;
bool scalarVariant = !print;
int stringId = checkLiteralString(str, index, ar, bs, scalarVariant);
always_assert(index >= 0);
string lisnam = ar->getLiteralStringName(stringId, index);
if (print) {
printf("NAMSTR(%s, \"%s\")", lisnam.c_str(), escaped.c_str());
}
return lisnam;
}
string CodeGenerator::printString(const string &str, AnalysisResultPtr ar,
BlockScopeRawPtr bs,
bool stringWrapper /* = true */) {
bool isBinary = false;
string escaped = EscapeLabel(str, &isBinary);
if (bs) {
return printNamedString(str, escaped, ar, bs, true);
}
if (isBinary) {
if (stringWrapper) {
printf("String(\"%s\", %d, AttachLiteral)",
escaped.c_str(), (int)str.length());
} else {
printf("\"%s\", %d", escaped.c_str(), (int)str.length());
}
} else {
printf("\"%s\"", escaped.c_str());
}
return "";
}
string CodeGenerator::printString(const std::string &str, AnalysisResultPtr ar,
ConstructPtr cs,
bool stringWrapper /* = true */) {
return printString(str, ar, (BlockScopePtr)cs->getScope(), stringWrapper);
}
void CodeGenerator::beginHoistedClasses() {
m_hoistedClasses = new std::set<string,stdltistr>();
m_collectHoistedClasses = true;
}
void CodeGenerator::endHoistedClasses() {
delete m_hoistedClasses;
m_hoistedClasses = 0;
}
void CodeGenerator::collectHoistedClasses(bool flag) {
m_collectHoistedClasses = flag;
}
void CodeGenerator::addHoistedClass(const string &cls) {
if (m_hoistedClasses && m_collectHoistedClasses) {
m_hoistedClasses->insert(cls);
}
}
bool CodeGenerator::checkHoistedClass(const string &cls) {
if (m_hoistedClasses) {
if (m_hoistedClasses->find(cls) != m_hoistedClasses->end()) {
return true;
}
addHoistedClass(cls);
}
return false;
}
int CodeGenerator::ClassScopeCompare::cmp(const ClassScopeRawPtr &p1,
const ClassScopeRawPtr &p2) const {
int d = p1->getRedeclaringId() - p2->getRedeclaringId();
-40
Ver Arquivo
@@ -163,17 +163,6 @@ public:
void indentEnd(const char *fmt, ...) ATTRIBUTE_PRINTF(2,3);
void indentEnd();
void printRaw(const char *msg) { print(msg, false);}
bool wrapExpressionBegin();
bool wrapExpressionEnd();
void genReferenceTemp(ConstructPtr scope);
void clearRefereceTemp() { m_referenceTemps[m_curStream].clear(); }
const std::string &getReferenceTemp();
bool hasReferenceTemp() const {
return !m_referenceTemps[m_curStream].empty();
}
void setReferenceTempUsed(bool flag) {
m_referenceTempsUsed[m_curStream] = flag;
}
/**
* Pre-formatted outputs.
*/
@@ -183,17 +172,9 @@ public:
void namespaceEnd();
bool ensureInNamespace();
bool ensureOutOfNamespace();
void headerBegin(const std::string &file);
void headerEnd(const std::string &file);
void ifdefBegin(bool ifdef, const char *fmt, ...) ATTRIBUTE_PRINTF(3,4);
void ifdefEnd(const char *fmt, ...) ATTRIBUTE_PRINTF(2,3);
void printInclude(const std::string &file);
void printBasicIncludes();
void printDeclareGlobals();
void printStartOfJumpTable(int tableSize);
void printDocComment(const std::string comment);
void printImplStarter(); // end of includes
void printImplSplitter(); // marker to split .cpp into smaller files
const char *getGlobals(AnalysisResultPtr ar);
static std::string FormatLabel(const std::string &name);
static std::string EscapeLabel(const std::string &name, bool *binary = nullptr);
@@ -268,31 +249,13 @@ public:
m_loopStatement = loop;
}
void setInsideScalarArray(bool flag);
bool getInsideScalarArray();
void setFileOrClassHeader(bool value) { m_inFileOrClassHeader = value; }
bool isFileOrClassHeader() { return m_inFileOrClassHeader; }
void beginHoistedClasses();
void endHoistedClasses();
void collectHoistedClasses(bool flag);
void addHoistedClass(const std::string &cls);
bool checkHoistedClass(const std::string &cls);
void setScalarVariant() { m_scalarVariant = true; }
bool hasScalarVariant() { return m_scalarVariant; }
void clearScalarVariant() { m_scalarVariant = false; }
void setInitListFirstElem() { m_initListFirstElem = true; }
bool hasInitListFirstElem() { return m_initListFirstElem; }
void clearInitListFirstElem() { m_initListFirstElem = false; }
const StringToClassScopePtrVecMap &getClasses() const { return m_classes; }
void addClass(const std::string &name, ClassScopePtr cls) {
m_classes[name].push_back(cls);
}
void clearClasses() { m_classes.clear(); }
bool insertDeclaredClosure(const FunctionScope *f) {
return m_declaredClosures.insert(f).second;
}
@@ -321,8 +284,6 @@ private:
bool m_inFileOrClassHeader;
bool m_inNamespace;
int m_localId[StreamCount];
std::set<std::string, stdltistr> *m_hoistedClasses;
bool m_collectHoistedClasses;
static int s_idLambda;
std::map<std::string, int> m_idCounters;
@@ -332,7 +293,6 @@ private:
std::set<int> m_contLabelIds; // continue labels referenced
std::deque<int> m_callInfos;
LoopStatementPtr m_loopStatement;
bool m_insideScalarArray;
StringToClassScopePtrVecMap m_classes;
std::set<const FunctionScope*> m_declaredClosures;
FileScopeRawPtr m_literalScope;
+26 -146
Ver Arquivo
@@ -38,10 +38,10 @@
#include <util/timer.h>
#include <util/hdf.h>
#include <util/async_func.h>
#include <runtime/base/program_functions.h>
#include <runtime/base/memory/smart_allocator.h>
#include <runtime/base/externals.h>
#include <runtime/base/thread_init_fini.h>
#include <runtime/base/compiler_id.h>
#include <runtime/vm/repo.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -49,6 +49,8 @@
#include <system/lib/systemlib.h>
#include <compiler/compiler.h>
#include "hhvm/process_init.h"
using namespace boost::program_options;
using std::cout;
@@ -97,9 +99,7 @@ struct CompilerOptions {
int clusterCount;
int optimizeLevel;
string filecache;
string rttiDirectory;
string javaRoot;
bool generateFFI;
bool dump;
string docjson;
bool coredump;
@@ -124,7 +124,7 @@ public:
struct stat sb;
stat(m_name, &sb);
Logger::Info("%dMB %s saved", (int64)sb.st_size/(1024*1024), m_name);
Logger::Info("%dMB %s saved", (int64_t)sb.st_size/(1024*1024), m_name);
}
private:
@@ -144,13 +144,10 @@ int phpTarget(const CompilerOptions &po, AnalysisResultPtr ar);
void hhbcTargetInit(const CompilerOptions &po, AnalysisResultPtr ar);
int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
AsyncFileCacheSaver &fcThread);
int cppTarget(const CompilerOptions &po, AnalysisResultPtr ar,
AsyncFileCacheSaver &fcThread, bool allowSys = true);
int runTargetCheck(const CompilerOptions &po, AnalysisResultPtr ar,
AsyncFileCacheSaver &fcThread);
int buildTarget(const CompilerOptions &po);
int runTarget(const CompilerOptions &po);
int generateSepExtCpp(const CompilerOptions &po, AnalysisResultPtr ar);
///////////////////////////////////////////////////////////////////////////////
@@ -186,11 +183,7 @@ int compiler_main(int argc, char **argv) {
}
}
if (ret == 0) {
if (po.target == "cpp") {
if (po.format == "exe" || po.format == "lib") {
ret = buildTarget(po);
}
} else if (po.target == "run") {
if (po.target == "run") {
ret = runTarget(po);
}
}
@@ -224,8 +217,6 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
"analyze | "
"php | "
"hhbc | "
"cpp | "
"sep-ext-cpp | "
"filecache | "
"run (default)")
("format,f", value<string>(&po.format),
@@ -234,7 +225,6 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
"php: trimmed (default) | inlined | pickled | typeinfo |"
" <any combination of them by any separator>; \n"
"hhbc: binary (default) | text; \n"
"cpp: cluster (default) | file | sys | exe | lib; \n"
"run: cluster (default) | file")
("cluster-count", value<int>(&po.clusterCount)->default_value(0),
"Cluster by file sizes and output roughly these many number of files. "
@@ -327,14 +317,6 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
("file-cache",
value<string>(&po.filecache),
"if specified, generate a static file cache with this file name")
("rtti-directory", value<string>(&po.rttiDirectory)->default_value(""),
"the directory of rtti profiling data")
("java-root",
value<string>(&po.javaRoot)->default_value("php"),
"the root package of generated Java FFI classes")
("generate-ffi",
value<bool>(&po.generateFFI)->default_value(false),
"generate ffi stubs")
("dump",
value<bool>(&po.dump)->default_value(false),
"dump the program graph")
@@ -361,9 +343,7 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
"files according to preprocessed file sizes, instead of original file "
"sizes (default). Run bin/ppp.php to generate an HDF configuration file "
"to specify here.")
#ifdef COMPILER_ID
("compiler-id", "display the git hash for the compiler id")
#endif
("repo-schema", "display the repo schema id used by this app")
("taint-status", "check if the compiler was built with taint enabled")
;
@@ -402,19 +382,15 @@ int prepareOptions(CompilerOptions &po, int argc, char **argv) {
#define HPHP_VERSION(v) cout << HPHP_COMPILER_STR #v << "\n";
#include "../version"
#ifdef COMPILER_ID
cout << "Compiler: " << COMPILER_ID << "\n";
#endif
cout << "Compiler: " << kCompilerId << "\n";
cout << "Repo schema: " << VM::Repo::kSchemaId << "\n";
return 1;
}
#ifdef COMPILER_ID
if (vm.count("compiler-id")) {
cout << COMPILER_ID << "\n";
cout << kCompilerId << "\n";
return 1;
}
#endif
if (vm.count("repo-schema")) {
cout << VM::Repo::kSchemaId << "\n";
@@ -428,8 +404,7 @@ cout << "Compiler: " << COMPILER_ID << "\n";
return 1;
}
if (hhvm &&
(po.target == "hhbc" || po.target == "run") &&
if ((po.target == "hhbc" || po.target == "run") &&
po.format.find("exe") == string::npos) {
if (po.program == "program") {
po.program = "hhvm.hhbc";
@@ -445,12 +420,6 @@ cout << "Compiler: " << COMPILER_ID << "\n";
Logger::LogLevel = Logger::LogInfo;
}
// config and system
Option::GenerateCPPMain = true;
if (po.noMetaInfo) {
Option::GenerateCPPMetaInfo = false;
Option::GenerateCPPMacros = false;
}
Option::FlAnnotate = po.fl_annotate;
Hdf config;
@@ -504,14 +473,8 @@ cout << "Compiler: " << COMPILER_ID << "\n";
(Util::format_pattern(po.excludeStaticPatterns[i], true));
}
if (po.target == "cpp" && po.format == "sys") {
BuiltinSymbols::NoSuperGlobals = true; // so to generate super globals
Option::AnalyzePerfectVirtuals = false;
}
Option::SystemGen = (po.target == "cpp" && po.format == "sys") ;
if (hhvm && (po.target == "hhbc" || po.target == "run")) {
Option::OutputHHBC = true;
Option::OutputHHBC = true;
if (po.target == "hhbc" || po.target == "run") {
Option::AnalyzePerfectVirtuals = false;
}
@@ -519,24 +482,22 @@ cout << "Compiler: " << COMPILER_ID << "\n";
Option::PreprocessedPartitionConfig = po.ppp;
if (po.format.empty()) {
if (po.target == "cpp") {
po.format = "cluster";
} else if (po.target == "php") {
if (po.target == "php") {
po.format = "trimmed";
} else if (po.target == "run") {
po.format = hhvm ? "binary" : "cluster";
} else if (hhvm && po.target == "hhbc") {
po.format = "binary";
} else if (po.target == "hhbc") {
po.format = "binary";
}
}
if (!po.docjson.empty()) {
if (po.target != "cpp" &&
po.target != "run" &&
if (po.target != "run" &&
po.target != "hhbc" &&
po.target != "analyze") {
Logger::Error(
"Cannot generate doc JSON file unless target is "
"'cpp', 'run', or 'analyze'");
"'hhbc', 'run', or 'analyze'");
} else {
Option::DocJson = po.docjson;
}
@@ -561,11 +522,6 @@ cout << "Compiler: " << COMPILER_ID << "\n";
}
}
if (po.generateFFI) {
Option::GenerateFFI = true;
Option::JavaFFIRootPackage = po.javaRoot;
}
return 0;
}
@@ -597,6 +553,7 @@ int process(const CompilerOptions &po) {
return lintTarget(po);
}
register_process_init();
init_thread_locals();
Timer timer(Timer::WallTime);
@@ -606,7 +563,7 @@ int process(const CompilerOptions &po) {
Package package(po.inputDir.c_str());
ar = package.getAnalysisResult();
if (hhvm && (po.target == "hhbc" || po.target == "run")) {
if (po.target == "hhbc" || po.target == "run") {
hhbcTargetInit(po, ar);
}
@@ -621,14 +578,10 @@ int process(const CompilerOptions &po) {
BuiltinSymbols::LoadSuperGlobals();
ClassInfo::Load();
if (po.format == "sys") ar->setSystem();
bool isPickledPHP = (po.target == "php" && po.format == "pickled");
if (!isPickledPHP) {
if (!BuiltinSymbols::Load(ar,
(po.target == "cpp" && po.format == "sys")
|| (po.target == "hhbc" && !Option::WholeProgram)
)) {
po.target == "hhbc" && !Option::WholeProgram)) {
return false;
}
if (po.target == "hhbc" && !Option::WholeProgram) {
@@ -636,6 +589,9 @@ int process(const CompilerOptions &po) {
} else {
ar->loadBuiltins();
}
if (!Option::SystemGen) {
hphp_process_init();
}
}
{
@@ -702,17 +658,12 @@ int process(const CompilerOptions &po) {
ret = analyzeTarget(po, ar);
} else if (po.target == "php") {
ret = phpTarget(po, ar);
} else if (hhvm && po.target == "hhbc") {
} else if (po.target == "hhbc") {
ret = hhbcTarget(po, ar, fileCacheThread);
} else if (po.target == "cpp") {
ret = cppTarget(po, ar, fileCacheThread);
} else if (po.target == "run") {
ret = runTargetCheck(po, ar, fileCacheThread);
} else if (po.target == "filecache") {
// do nothing
} else if (po.target == "sep-ext-cpp") {
ar->setSepExtension();
ret = generateSepExtCpp(po, ar);
} else {
Logger::Error("Unknown target: %s", po.target.c_str());
return 1;
@@ -968,69 +919,6 @@ int hhbcTarget(const CompilerOptions &po, AnalysisResultPtr ar,
///////////////////////////////////////////////////////////////////////////////
int cppTarget(const CompilerOptions &po, AnalysisResultPtr ar,
AsyncFileCacheSaver &fcThread, bool allowSys /* = true */) {
int ret = 0;
int clusterCount = po.clusterCount;
// format
CodeGenerator::Output format = CodeGenerator::InvalidOutput;
if (po.format == "file") {
clusterCount = 0;
format = CodeGenerator::FileCPP;
} else if (po.format == "cluster") {
format = CodeGenerator::ClusterCPP;
} else if (po.format == "sys" && allowSys) {
clusterCount = 0;
format = CodeGenerator::SystemCPP;
ar->setSystem();
} else if (po.format == "exe" || po.format == "lib") {
format = CodeGenerator::ClusterCPP;
}
if (format == CodeGenerator::InvalidOutput) {
Logger::Error("Unknown format for CPP target: %s", po.format.c_str());
return 1;
}
if (!Option::RTTIOutputFile.empty()) {
if (!po.rttiDirectory.empty()) {
Option::UseRTTIProfileData = true;
ar->cloneRTTIFuncs(po.rttiDirectory.c_str());
} else {
Option::GenRTTIProfileData = true;
}
}
ret = analyzeTarget(po, ar);
{
Timer timer(Timer::WallTime, "creating CPP files");
if (po.syncDir.empty()) {
ar->setOutputPath(po.outputDir);
ar->outputAllCPP(format, clusterCount, nullptr);
} else {
ar->setOutputPath(po.syncDir);
ar->outputAllCPP(format, clusterCount, &po.outputDir);
if (!po.filecache.empty()) {
fcThread.waitForEnd();
}
Util::syncdir(po.outputDir, po.syncDir);
boost::filesystem::remove_all(po.syncDir);
}
}
return ret;
}
///////////////////////////////////////////////////////////////////////////////
int generateSepExtCpp(const CompilerOptions &po, AnalysisResultPtr ar) {
ar->outputCPPSepExtensionImpl(po.outputFile);
return 0;
}
///////////////////////////////////////////////////////////////////////////////
int buildTarget(const CompilerOptions &po) {
const char *HPHP_HOME = getenv("HPHP_HOME");
if (!HPHP_HOME || !*HPHP_HOME) {
@@ -1042,7 +930,6 @@ int buildTarget(const CompilerOptions &po) {
if (getenv("SHOW_LINK")) flags += "SHOW_LINK=1 ";
if (getenv("SHOW_COMPILE")) flags += "SHOW_COMPILE=1 ";
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(), nullptr};
@@ -1071,11 +958,7 @@ int buildTarget(const CompilerOptions &po) {
int runTargetCheck(const CompilerOptions &po, AnalysisResultPtr ar,
AsyncFileCacheSaver &fcThread) {
// generate code
if (po.format == "sep") return 1;
if (hhvm ?
hhbcTarget(po, ar, fcThread) :
cppTarget(po, ar, fcThread, false)) {
if (hhbcTarget(po, ar, fcThread)) {
return 1;
}
@@ -1089,10 +972,7 @@ int runTargetCheck(const CompilerOptions &po, AnalysisResultPtr ar,
}
int runTarget(const CompilerOptions &po) {
int ret = hhvm ? 0 : buildTarget(po);
if (ret) {
return ret;
}
int ret = 0;
// If there are more than one input files, we need one extra arg to run.
// If it's missing, we will stop right here, with compiled code.
@@ -1103,7 +983,7 @@ int runTarget(const CompilerOptions &po) {
// run the executable
string cmd;
if (hhvm && po.format.find("exe") == string::npos) {
if (po.format.find("exe") == string::npos) {
char buf[PATH_MAX];
if (!realpath("/proc/self/exe", buf)) return -1;
+3 -3
Ver Arquivo
@@ -313,7 +313,7 @@ void Construct::dumpNode(int spc) {
}
std::cout << "-> 0x" << std::hex << std::setfill('0')
<< std::setw(10) << (int64)this << std::dec;
<< std::setw(10) << (int64_t)this << std::dec;
std::cout << " " << name << "(" << type << ") ";
if (id) {
@@ -322,12 +322,12 @@ void Construct::dumpNode(int spc) {
if (idPtr) {
std::cout << "idp=0x" <<
std::hex << std::setfill('0') << std::setw(10) <<
(int64)idPtr.get() << " ";
(int64_t)idPtr.get() << " ";
}
if (idCsePtr) {
std::cout << "idcsep=0x" <<
std::hex << std::setfill('0') << std::setw(10) <<
(int64)idCsePtr.get() << " ";
(int64_t)idCsePtr.get() << " ";
}
if (value != "") {
-1
Ver Arquivo
@@ -246,7 +246,6 @@ public:
* Called when generating code.
*/
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
/**
* Implements JSON::CodeError::ISerializable.
@@ -79,8 +79,7 @@ void ArrayElementExpression::setContext(Context context) {
if (m_variable->is(Expression::KindOfObjectPropertyExpression)) {
m_variable->clearContext(Expression::NoLValueWrapper);
}
// special case for $GLOBALS[], see the if (m_global) check in
// ArrayElementExpression::outputCPPImpl, we do not need lvalue wrapper
// special case for $GLOBALS[], we do not need lvalue wrapper
if (m_variable->is(Expression::KindOfSimpleVariable)) {
SimpleVariablePtr var =
dynamic_pointer_cast<SimpleVariable>(m_variable);
@@ -410,209 +409,3 @@ void ArrayElementExpression::outputPHP(CodeGenerator &cg,
cg_printf("]");
}
}
bool ArrayElementExpression::preOutputCPP(CodeGenerator &cg,
AnalysisResultPtr ar, int state) {
return preOutputOffsetLHS(cg, ar, state);
}
void ArrayElementExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (m_global) {
if (!m_globalName.empty()) {
VariableTablePtr variables = getScope()->getVariables();
string name = variables->getGlobalVariableName(ar, m_globalName);
cg_printf("g->%s", name.c_str());
} else {
cg_printf("((LVariableTable *)g)->get(");
m_offset->outputCPP(cg, ar);
cg_printf(")");
}
} else {
TypePtr type = m_variable->getType();
if (hasContext(UnsetContext)) {
cg_printf("unsetLval(");
m_variable->outputCPP(cg, ar);
cg_printf(", ");
} else {
if (m_variable->is(Expression::KindOfScalarExpression) ||
(type && (type->isInteger() ||
type->is(Type::KindOfDouble) ||
type->is(Type::KindOfObject) ||
type->is(Type::KindOfBoolean)))) {
cg_printf(type && type->is(Type::KindOfString) ? "((String)" :
"((Variant)");
m_variable->outputCPP(cg, ar);
cg_printf(")");
} else {
m_variable->outputCPP(cg, ar);
}
}
if (m_offset) {
bool lvalAt = false;
bool rvalAt = false;
bool byRef = false;
bool arrRef = false;
const char *sep = ", AccessFlags::";
bool isArrayType = type && type->is(Type::KindOfArray);
bool isStringType = type && type->is(Type::KindOfString);
bool isRealChainRoot = isChainRoot() && hasCPPCseTemp();
TypePtr t;
bool hasCseStore = isRealChainRoot && GetCseTempInfo(
ar,
static_pointer_cast<Expression>(shared_from_this()),
t);
if (hasContext(UnsetContext)) {
// do nothing
} else if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) {
assert(!isRealChainRoot); // TODO: handle this case
cg_printf(".argvalAt(cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum);
} else if (m_context & (LValue|RefValue|DeepReference)) {
// if we see an array access element in LValue context, the
// type inference pass will never infer its type to be a string
assert(!isStringType);
if (isRealChainRoot && !isArrayType) {
// chain roots for non array types (variants) should call
// lvalRef()
cg_printf(".lvalRef(");
} else {
cg_printf(".lvalAt(");
}
lvalAt = true;
} else {
byRef =
((m_context & AccessContext) || isRealChainRoot) && !isStringType;
arrRef = byRef && isArrayType;
cg_printf(".rval%s%s(",
arrRef || !byRef ? "At" : "", byRef ? "Ref" : "");
rvalAt = true;
}
m_offset->outputCPP(cg, ar);
if (!isStringType) {
if (rvalAt) {
if (byRef && !arrRef) {
string tmp;
if (hasCseStore) {
tmp = string(Option::CseTempStoragePrefix) + m_cppCseTemp;
} else {
tmp = cg.getReferenceTemp();
}
cg_printf(", %s", tmp.empty() ? "Variant()" : tmp.c_str());
}
if (!hasContext(ExistContext)) {
cg_printf(", AccessFlags::Error"); // raise undefined index error
sep = "_";
}
} else if (lvalAt) {
if (hasCseStore && !isArrayType) {
cg_printf(", %s%s",
Option::CseTempStoragePrefix, m_cppCseTemp.c_str());
}
if (hasContext(AccessContext)) {
// Dont copy the array if the element is an object, or
// is referenced.
// This is safe in AccessContext (the parent is an ArrayElement,
// or an ObjectProperty) because applying [] to an object will
// either invoke OffsetGet, or fatal, and modifications to a
// referenced element would be reflected in all copies
// of the array anyway.
cg_printf(", AccessFlags::CheckExist");
sep = "_";
}
}
ScalarExpressionPtr sc =
dynamic_pointer_cast<ScalarExpression>(m_offset);
if (!hasContext(UnsetContext) && sc && sc->isLiteralString()) {
String s(sc->getLiteralString());
int64 n;
if (!s.get()->isStrictlyInteger(n)) {
if (lvalAt || rvalAt) {
cg_printf("%sKey", sep);
} else {
cg_printf(", true"); // skip toKey() at run time
}
}
}
}
cg_printf(")");
} else {
cg_printf(".lvalAt()");
}
}
}
void ArrayElementExpression::outputCPPExistTest(CodeGenerator &cg,
AnalysisResultPtr ar, int op) {
switch (op) {
case T_ISSET: cg_printf("isset("); break;
case T_EMPTY: cg_printf("empty("); break;
default: assert(false);
}
if (m_global) {
if (!m_globalName.empty()) {
VariableTablePtr variables = getScope()->getVariables();
string name = variables->getGlobalVariableName(ar, m_globalName);
cg_printf("g->%s", name.c_str());
} else {
cg_printf("((LVariableTable *)g)->get(");
m_offset->outputCPP(cg, ar);
cg_printf(")");
}
} else {
m_variable->outputCPP(cg, ar);
cg_printf(", ");
m_offset->outputCPP(cg, ar);
ScalarExpressionPtr sc =
dynamic_pointer_cast<ScalarExpression>(m_offset);
if (sc) {
if (sc->isLiteralString()) {
String s(sc->getLiteralString());
int64 n;
if (!s.get()->isStrictlyInteger(n)) {
cg_printf(", true"); // skip toKey() at run time
}
}
}
}
cg_printf(")");
}
void ArrayElementExpression::outputCPPUnset(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (isSuperGlobal()) {
Expression::outputCPPUnset(cg, ar);
} else {
TypePtr expected = m_variable->getExpectedType();
TypePtr implemented = m_variable->getImplementedType();
bool wrap = false;
if (TypePtr t = m_variable->getActualType()) {
if (t->is(Type::KindOfObject)) {
if (!m_variable->getImplementedType() ||
!m_variable->getImplementedType()->is(Type::KindOfVariant)) {
cg_printf("((Variant)(");
wrap = true;
}
m_variable->setImplementedType(TypePtr());
m_variable->setExpectedType(TypePtr());
}
}
m_variable->outputCPP(cg, ar);
if (wrap) cg_printf("))");
m_variable->setExpectedType(expected);
m_variable->setImplementedType(implemented);
cg_printf(".weakRemove(");
m_offset->outputCPP(cg, ar);
ScalarExpressionPtr sc =
dynamic_pointer_cast<ScalarExpression>(m_offset);
if (sc && sc->isLiteralString()) {
String s(sc->getLiteralString());
int64 n;
if (!s->isStrictlyInteger(n)) {
cg_printf(", true");
}
}
cg_printf(")");
}
}
@@ -56,11 +56,6 @@ public:
bool appendClass(ExpressionPtr cls,
AnalysisResultConstPtr ar, FileScopePtr file);
virtual void outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
int op);
virtual void outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
virtual bool canonCompare(ExpressionPtr e) const;
private:
@@ -126,13 +126,6 @@ bool ArrayPairExpression::canonCompare(ExpressionPtr e) const {
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void ArrayPairExpression::preOutputStash(CodeGenerator &cg,
AnalysisResultPtr ar,
int state) {
if (m_name) m_name->preOutputStash(cg, ar, state);
m_value->preOutputStash(cg, ar, state);
}
void ArrayPairExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_name) {
m_name->outputPHP(cg, ar);
@@ -141,40 +134,3 @@ void ArrayPairExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_ref) cg_printf("&");
m_value->outputPHP(cg, ar);
}
void ArrayPairExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
bool keyConverted = false;
if (m_name) {
keyConverted = outputCPPName(cg, ar);
cg_printf(", ");
}
m_value->outputCPP(cg, ar);
if (m_name && keyConverted && !m_collection) {
cg_printf(", true");
}
}
bool ArrayPairExpression::outputCPPName(CodeGenerator &cg,
AnalysisResultPtr ar) {
assert(m_name);
ScalarExpressionPtr sc = dynamic_pointer_cast<ScalarExpression>(m_name);
if (sc) {
if (sc->isLiteralString()) {
string s = sc->getLiteralString();
int64 res;
if (is_strictly_integer(s.c_str(), s.size(), res)) {
cg_printf("%sL", s.c_str());
} else {
m_name->outputCPP(cg, ar);
}
return true;
}
if (sc->isLiteralInteger()) {
m_name->outputCPP(cg, ar);
return true;
}
}
m_name->outputCPP(cg, ar);
return false;
}
@@ -40,9 +40,6 @@ public:
virtual int getLocalEffects() const { return NoEffect; }
bool isScalarArrayPair() const;
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool isRef() const { return m_ref; }
bool canonCompare(ExpressionPtr e) const;
@@ -51,8 +48,6 @@ private:
ExpressionPtr m_value;
bool m_ref;
bool m_collection;
bool outputCPPName(CodeGenerator &cg, AnalysisResultPtr ar);
};
///////////////////////////////////////////////////////////////////////////////
@@ -301,237 +301,3 @@ void AssignmentExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_ref) cg_printf("&");
m_value->outputPHP(cg, ar);
}
static void wrapValue(CodeGenerator &cg, AnalysisResultPtr ar,
ExpressionPtr exp, bool ref, bool array, bool varnr) {
bool close = false;
if (ref) {
cg_printf("ref(");
close = true;
} else if (array && !exp->hasCPPTemp() &&
!exp->isTemporary() && !exp->isScalar() &&
exp->getActualType() && !exp->getActualType()->isPrimitive() &&
exp->getActualType()->getKindOf() != Type::KindOfString) {
cg_printf("wrap_variant(");
close = true;
} else if (varnr && exp->getCPPType()->isExactType()) {
bool isScalar = exp->isScalar();
if (!isScalar || !Option::UseScalarVariant) {
cg_printf("VarNR(");
close = true;
} else if (isScalar) {
assert(!cg.hasScalarVariant());
cg.setScalarVariant();
}
}
exp->outputCPP(cg, ar);
cg.clearScalarVariant();
if (close) cg_printf(")");
}
void AssignmentExpression::preOutputStash(CodeGenerator &cg,
AnalysisResultPtr ar, int state) {
if (hasCPPTemp()) return;
if (m_value->hasCPPTemp() &&
(Type::SameType(getType(), m_value->getType()) ||
(Type::IsMappedToVariant(getType()) &&
Type::IsMappedToVariant(m_value->getType())))) {
setUnused(true);
outputCPP(cg, ar);
cg_printf(";\n");
setCPPTemp(m_value->cppTemp());
return;
}
TypePtr at(getActualType());
TypePtr et(getExpectedType());
TypePtr it(getImplementedType());
if (at && !Type::IsMappedToVariant(at) &&
!et && it && Type::IsMappedToVariant(it)) {
m_value->preOutputStash(cg, ar, state);
if (!m_value->hasCPPTemp()) {
// preOutputStash did no work, so we need to
// explicitly do a stash
TypePtr t(m_value->getType());
bool constRef = !t->isPrimitive() &&
(m_value->isTemporary() || !m_value->isLocalExprAltered());
const string &tmp = m_value->genCPPTemp(cg, ar);
if (constRef) cg_printf("const ");
t->outputCPPDecl(cg, ar, getScope());
const char *ref = constRef ? "&" : "";
cg_printf(" %s%s((", ref, tmp.c_str());
m_value->outputCPP(cg, ar);
cg_printf("));\n");
m_value->setCPPTemp(tmp);
}
assert(m_value->hasCPPTemp());
setUnused(true);
outputCPP(cg, ar);
cg_printf(";\n");
setCPPTemp(m_value->cppTemp());
return;
}
return Expression::preOutputStash(cg, ar, state);
}
bool AssignmentExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (hasContext(RefValue) && !m_ref) {
if (!cg.inExpression()) return true;
state |= FixOrder | ForceTemp;
}
if (m_variable->is(Expression::KindOfArrayElementExpression)) {
ExpressionPtr exp = m_value;
ExpressionPtr vv(
static_pointer_cast<ArrayElementExpression>(m_variable)->getVariable());
if ((vv->is(KindOfArrayElementExpression) ||
vv->is(KindOfObjectPropertyExpression)) &&
(vv->getContainedEffects() && (CreateEffect|AccessorEffect))) {
/*
We are in a case such as
$a->b['c'] = ...;
$a['b']['c'] = ...;
Where evaluating m_variable may modify $a. Unless we can prove that
the rhs is not referring to the same thing as $a, we must generate
a temporary for it (note that we could do better with the following
checks).
*/
if (!(m_ref && exp->isRefable()) &&
!exp->isTemporary() && !exp->isScalar() &&
exp->getActualType() && !exp->getActualType()->isPrimitive() &&
exp->getActualType()->getKindOf() != Type::KindOfString) {
state |= Expression::StashAll;
}
}
}
return Expression::preOutputCPP(cg, ar, state);
}
bool AssignmentExpression::SpecialAssignment(CodeGenerator &cg,
AnalysisResultPtr ar,
ExpressionPtr lval,
ExpressionPtr rval,
const char *rvalStr, bool ref) {
if (lval->is(KindOfArrayElementExpression)) {
ArrayElementExpressionPtr exp =
dynamic_pointer_cast<ArrayElementExpression>(lval);
if (!exp->isSuperGlobal() && !exp->isDynamicGlobal()) {
exp->getVariable()->outputCPP(cg, ar);
if (exp->getOffset()) {
cg_printf(".set(");
exp->getOffset()->outputCPP(cg, ar);
cg_printf(", (");
} else {
cg_printf(".append((");
}
if (rval) {
wrapValue(cg, ar, rval, ref,
(exp->getVariable()->is(KindOfArrayElementExpression) ||
exp->getVariable()->is(KindOfObjectPropertyExpression)) &&
(exp->getVariable()->getContainedEffects() &&
(CreateEffect|AccessorEffect)), true);
} else {
cg_printf(ref ? "ref(%s)" : "%s", rvalStr);
}
cg_printf(")");
ExpressionPtr off = exp->getOffset();
if (off) {
ScalarExpressionPtr sc =
dynamic_pointer_cast<ScalarExpression>(off);
if (sc) {
if (sc->isLiteralString()) {
String s(sc->getLiteralString());
int64 n;
if (!s.get()->isStrictlyInteger(n)) {
cg_printf(", true"); // skip toKey() at run time
}
}
}
}
cg_printf(")");
return true;
}
} else if (lval->is(KindOfObjectPropertyExpression)) {
ObjectPropertyExpressionPtr var(
dynamic_pointer_cast<ObjectPropertyExpression>(lval));
if (!var->isValid()) {
bool nonPrivate = var->isNonPrivate(ar);
var->outputCPPObject(cg, ar);
if (nonPrivate) {
cg_printf("o_setPublic(");
} else {
cg_printf("o_set(");
}
var->outputCPPProperty(cg, ar);
cg_printf(", %s", ref ? "ref(" : "");
if (rval) {
rval->outputCPP(cg, ar);
} else {
cg_printf(ref ? "ref(%s)" : "%s", rvalStr);
}
if (nonPrivate) {
cg_printf("%s)", ref ? ")" : "");
}
else {
cg_printf("%s%s)",
ref ? ")" : "",
lval->originalClassName(cg, true).c_str());
}
return true;
}
}
return false;
}
void AssignmentExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
bool ref = (m_ref && m_value->isRefable());
bool setNull = false;
if (SpecialAssignment(cg, ar, m_variable, m_value, nullptr, ref)) {
return;
}
if (m_value->isLiteralNull()) {
if (m_variable->is(Expression::KindOfSimpleVariable)) {
setNull = true;
} else {
TypePtr t = m_variable->getCPPType();
if (t && (t->is(Type::KindOfArray) ||
t->is(Type::KindOfObject) ||
t->is(Type::KindOfString))) {
setNull = true;
}
}
}
bool wrapped = true;
if (setNull) {
cg_printf("setNull(");
m_variable->outputCPP(cg, ar);
} else {
if (!m_variable->getCPPType()->isExactType() &&
!(m_value->hasCPPTemp() ?
m_value->getType() : m_value->getCPPType())->isExactType()) {
m_variable->outputCPP(cg, ar);
cg_printf(".assign%s(", ref ? "Ref" : "Val");
wrapped = true;
ref = false;
} else {
if (m_variable->getCPPType()->isExactType()) {
ref = false;
}
if ((wrapped = !isUnused())) {
cg_printf("(");
}
m_variable->outputCPP(cg, ar);
cg_printf(" = ");
}
wrapValue(cg, ar, m_value, ref, false, false);
}
if (wrapped) {
cg_printf(")");
}
}
@@ -48,13 +48,6 @@ public:
ExpressionPtr getValue() { return m_value;}
void setValue(ExpressionPtr v) { m_value = v; }
int getLocalEffects() const;
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar, int state);
static bool SpecialAssignment(CodeGenerator &cg,
AnalysisResultPtr ar,
ExpressionPtr lval,
ExpressionPtr rval,
const char *rvalStr, bool ref);
// $GLOBALS[<literal-string>] = <scalar>;
bool isSimpleGlobalAssign(StringData **name, TypedValue *tv) const;
+5 -572
Ver Arquivo
@@ -284,7 +284,7 @@ ExpressionPtr BinaryOpExpression::simplifyArithmetic(
Variant v2;
if (m_exp1->getScalarValue(v1)) {
if (v1.isInteger()) {
int64 ival1 = v1.toInt64();
int64_t ival1 = v1.toInt64();
// 1 * $a => $a, 0 + $a => $a
if ((ival1 == 1 && m_op == '*') || (ival1 == 0 && m_op == '+')) {
TypePtr actType2 = m_exp2->getActualType();
@@ -317,7 +317,7 @@ ExpressionPtr BinaryOpExpression::simplifyArithmetic(
}
if (m_exp2->getScalarValue(v2)) {
if (v2.isInteger()) {
int64 ival2 = v2.toInt64();
int64_t ival2 = v2.toInt64();
// $a * 1 => $a, $a + 0 => $a
if ((ival2 == 1 && m_op == '*') || (ival2 == 0 && m_op == '+')) {
TypePtr actType1 = m_exp1->getActualType();
@@ -484,8 +484,7 @@ ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
if (m_exp1->isScalar()) {
if (!m_exp1->getScalarValue(v1)) return ExpressionPtr();
try {
if (hhvm &&
Option::OutputHHBC &&
if (Option::OutputHHBC &&
(!Option::WholeProgram || !Option::ParseTimeOpts)) {
// In the VM, don't optimize __CLASS__ if within a trait, since
// __CLASS__ is not resolved yet.
@@ -524,11 +523,11 @@ ExpressionPtr BinaryOpExpression::foldConst(AnalysisResultConstPtr ar) {
case '<':
result = less(v1, v2); break;
case T_IS_SMALLER_OR_EQUAL:
result = not_more(v1, v2); break;
result = less_or_equal(v1, v2); break;
case '>':
result = more(v1, v2); break;
case T_IS_GREATER_OR_EQUAL:
result = not_less(v1, v2); break;
result = more_or_equal(v1, v2); break;
case '+':
result = plus(v1, v2); break;
case '-':
@@ -908,284 +907,6 @@ void BinaryOpExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_exp2->outputPHP(cg, ar);
}
static bool castIfNeeded(TypePtr top, TypePtr arg,
CodeGenerator &cg, AnalysisResultPtr ar,
BlockScopeRawPtr scope) {
if (top) {
if (top->isPrimitive()) {
if (!arg || !arg->isPrimitive()) {
top->outputCPPCast(cg, ar, scope);
cg_printf("(");
return true;
}
} else if (top->is(Type::KindOfArray)) {
if (arg && arg->isExactType() && !arg->is(Type::KindOfArray)) {
cg_printf("((Variant)");
return true;
}
} else if (top->mustBe(Type::KindOfNumeric)) {
if (arg && arg->is(Type::KindOfArray)) {
cg_printf("((Variant)");
return true;
}
}
}
return false;
}
void BinaryOpExpression::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (hasCPPTemp() || isScalar()) return;
if (m_op == '.' && (state & FixOrder)) {
if (m_exp1) {
if (!m_exp1->getActualType() && m_exp1->hasCPPTemp()) {
cg_printf("id(%s);\n", m_exp1->cppTemp().c_str());
}
m_exp1->preOutputStash(cg, ar, state|StashVars);
}
if (m_exp2) {
if (!m_exp2->getActualType() && m_exp2->hasCPPTemp()) {
cg_printf("id(%s);\n", m_exp2->cppTemp().c_str());
}
m_exp2->preOutputStash(cg, ar, state|StashVars);
}
} else {
Expression::preOutputStash(cg, ar, state);
}
}
static const char *stringBufferPrefix(CodeGenerator &cg, AnalysisResultPtr ar,
ExpressionPtr var) {
if (var->is(Expression::KindOfSimpleVariable)) {
if (LoopStatementPtr loop = cg.getLoopStatement()) {
SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(var);
if (loop->checkStringBuf(sv->getName())) {
return loop->getScope()->getVariables()->
getVariablePrefix(sv->getName());
}
}
}
return 0;
}
static std::string stringBufferName(const char *temp, const char *prefix,
const char *name)
{
return std::string(temp) + "_sbuf_" + prefix + name;
}
int BinaryOpExpression::getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp,
bool &hasVoid) {
if (!exp->hasCPPTemp()) {
if (exp->is(Expression::KindOfUnaryOpExpression)) {
UnaryOpExpressionPtr u = static_pointer_cast<UnaryOpExpression>(exp);
if (u->getOp() == '(') {
return getConcatList(ev, u->getExpression(), hasVoid);
}
} else if (exp->is(Expression::KindOfBinaryOpExpression)) {
BinaryOpExpressionPtr b = static_pointer_cast<BinaryOpExpression>(exp);
if (b->getOp() == '.') {
if (b->getExp1()->is(Expression::KindOfSimpleVariable) &&
b->getExp1()->isLocalExprAltered() &&
!b->getExp1()->hasCPPTemp() &&
b->getExp2()->hasEffect() &&
!b->getExp2()->hasCPPTemp()) {
/*
In this case, the simple variable must be evaluated
after b->getExp2(). But when we output a concat list we
explicitly order the expressions from left to right.
*/
} else {
return getConcatList(ev, b->getExp1(), hasVoid) +
getConcatList(ev, b->getExp2(), hasVoid);
}
}
} else if (exp->is(Expression::KindOfEncapsListExpression)) {
EncapsListExpressionPtr e =
static_pointer_cast<EncapsListExpression>(exp);
if (e->getType() != '`') {
ExpressionListPtr el = e->getExpressions();
int num = 0;
for (int i = 0, s = el->getCount(); i < s; i++) {
ExpressionPtr exp = (*el)[i];
num += getConcatList(ev, exp, hasVoid);
}
return num;
}
}
} else if (!exp->getActualType()) {
return 0;
}
ev.push_back(exp);
bool isVoid = !exp->getActualType();
hasVoid |= isVoid;
return isVoid ? 0 : 1;
}
static void outputStringExpr(CodeGenerator &cg, AnalysisResultPtr ar,
ExpressionPtr exp, bool asLitStr) {
if (asLitStr && exp->isLiteralString()) {
const std::string &s = exp->getLiteralString();
std::string enc = string_cplus_escape(s.c_str(), s.size());
cg_printf("\"%s\", %d", enc.c_str(), (int)s.size());
return;
}
TypePtr et(exp->getExpectedType());
exp->setExpectedType(Type::String);
exp->outputCPP(cg, ar);
exp->setExpectedType(et);
}
static void outputStringBufExprs(ExpressionPtrVec &ev,
CodeGenerator &cg, AnalysisResultPtr ar) {
for (size_t i = 0; i < ev.size(); i++) {
ExpressionPtr exp = ev[i];
cg_printf(".addWithTaint(");
outputStringExpr(cg, ar, exp, true);
cg_printf(")");
}
}
bool BinaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (isOpEqual() && (m_exp1->is(KindOfArrayElementExpression) ||
m_exp1->is(KindOfObjectPropertyExpression))) {
return Expression::preOutputCPP(cg, ar, state);
}
bool effect2 = m_exp2->hasEffect();
const char *prefix = 0;
if (effect2 || m_exp1->hasEffect()) {
ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this());
ExpressionPtrVec ev;
bool hasVoid = false;
int numConcat = 0;
bool ok = false;
if (m_op == '.') {
numConcat = getConcatList(ev, self, hasVoid);
ok = hasVoid || (numConcat > MAX_CONCAT_ARGS);
} else if (effect2 && m_op == T_CONCAT_EQUAL) {
prefix = stringBufferPrefix(cg, ar, m_exp1);
ok = prefix;
if (!ok) {
if (m_exp1->is(KindOfSimpleVariable)) {
ok = true;
ev.push_back(m_exp1);
numConcat++;
}
}
if (ok) {
numConcat += getConcatList(ev, m_exp2, hasVoid);
if (numConcat <= 2 && !prefix) {
return Expression::preOutputCPP(cg, ar, state);
}
}
}
if (ok) {
if (!cg.inExpression()) return true;
cg.wrapExpressionBegin();
std::string buf;
if (prefix) {
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(m_exp1));
buf = stringBufferName(Option::TempPrefix, prefix,
sv->getName().c_str());
m_cppTemp = "/**/";
} else if (numConcat) {
buf = m_cppTemp = genCPPTemp(cg, ar);
buf += "_buf";
if (numConcat > 1) {
cg_printf("StringBuffer %s;\n", buf.c_str());
}
} else {
m_cppTemp = "\"\"";
}
for (size_t i = 0; i < ev.size(); i++) {
ExpressionPtr exp = ev[i];
bool is_void = !exp->getActualType();
exp->preOutputCPP(cg, ar, 0);
if (!is_void) {
bool asLit = true;
if (numConcat > 1 || prefix) {
cg_printf("%s.appendWithTaint(", buf.c_str());
} else {
asLit = false;
cg_printf("CStrRef %s = (", m_cppTemp.c_str());
}
outputStringExpr(cg, ar, exp, asLit);
cg_printf(")");
} else {
exp->outputCPPUnneeded(cg, ar);
}
cg_printf(";\n");
}
if (numConcat > 1 && !prefix) {
cg_printf("CStrRef %s(%s.detachWithTaint());\n",
m_cppTemp.c_str(), buf.c_str());
if (m_op == T_CONCAT_EQUAL) {
m_exp1->outputCPP(cg, ar);
cg_printf(" = %s;\n", m_cppTemp.c_str());
}
}
return true;
}
}
if (!isShortCircuitOperator()) {
return Expression::preOutputCPP(cg, ar, state);
}
if (!effect2) {
bool ret = m_exp1->preOutputCPP(cg, ar, 0);
if (state & FixOrder) {
ret = true;
if (cg.inExpression()) {
preOutputStash(cg, ar, state);
}
}
return ret;
}
bool fix_e1 = m_exp1->preOutputCPP(cg, ar, 0);
if (!cg.inExpression()) {
return fix_e1 || m_exp2->preOutputCPP(cg, ar, 0);
}
cg.setInExpression(false);
bool fix_e2 = m_exp2->preOutputCPP(cg, ar, 0);
cg.setInExpression(true);
if (fix_e2) {
cg.wrapExpressionBegin();
std::string tmp = genCPPTemp(cg, ar);
cg_printf("bool %s = (", tmp.c_str());
m_exp1->outputCPP(cg, ar);
cg_printf(");\n");
cg_indentBegin("if (%s%s) {\n",
m_op == T_LOGICAL_OR || m_op == T_BOOLEAN_OR ? "!" : "",
tmp.c_str());
m_exp2->preOutputCPP(cg, ar, 0);
if (isUnused()) {
if (m_exp2->outputCPPUnneeded(cg, ar)) cg_printf(";\n");
} else {
cg_printf("%s = (", tmp.c_str());
m_exp2->outputCPP(cg, ar);
cg_printf(");\n");
}
cg_indentEnd("}\n");
m_cppTemp = tmp;
} else if (state & FixOrder) {
preOutputStash(cg, ar, state);
fix_e1 = true;
}
return fix_e1 || fix_e2;
}
bool BinaryOpExpression::isOpEqual() {
switch (m_op) {
case T_CONCAT_EQUAL:
@@ -1206,291 +927,3 @@ bool BinaryOpExpression::isOpEqual() {
return false;
}
bool BinaryOpExpression::outputCPPImplOpEqual(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (m_exp1->is(Expression::KindOfArrayElementExpression)) {
ArrayElementExpressionPtr exp =
dynamic_pointer_cast<ArrayElementExpression>(m_exp1);
if (exp->isSuperGlobal() || exp->isDynamicGlobal()) return false;
if (TypePtr t = exp->getVariable()->getActualType()) {
TypePtr it(exp->getVariable()->getImplementedType());
if (t->is(Type::KindOfArray) &&
(!it ||
it->is(Type::KindOfArray) ||
Type::IsMappedToVariant(it) /* fast cast will kick in */)) {
return false;
}
}
// turning $a['elem'] Op= $b into $a.setOpEqual('elem', $b);
exp->getVariable()->outputCPP(cg, ar);
if (exp->getOffset()) {
cg_printf(".setOpEqual(%d, ", m_op);
exp->getOffset()->outputCPP(cg, ar);
cg_printf(", (");
} else {
cg_printf(".appendOpEqual(%d, (", m_op);
}
m_exp2->outputCPP(cg, ar);
cg_printf(")");
ExpressionPtr off = exp->getOffset();
if (off) {
ScalarExpressionPtr sc = dynamic_pointer_cast<ScalarExpression>(off);
if (sc) {
if (sc->isLiteralString()) {
String s(sc->getLiteralString());
int64 n;
if (!s.get()->isStrictlyInteger(n)) {
cg_printf(", true"); // skip toKey() at run time
}
}
}
}
cg_printf(")");
return true;
}
if (m_exp1->is(Expression::KindOfObjectPropertyExpression)) {
ObjectPropertyExpressionPtr var(
dynamic_pointer_cast<ObjectPropertyExpression>(m_exp1));
if (var->isValid()) return false;
var->outputCPPObject(cg, ar);
cg_printf("o_assign_op<%s,%d>(",
isUnused() ? "void" : "Variant", m_op);
var->outputCPPProperty(cg, ar);
cg_printf(", ");
m_exp2->outputCPP(cg, ar);
cg_printf("%s)", originalClassName(cg, true).c_str());
return true;
}
return false;
}
void BinaryOpExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (isOpEqual() && outputCPPImplOpEqual(cg, ar)) return;
bool wrapped = true;
switch (m_op) {
case T_CONCAT_EQUAL:
if (const char *prefix = stringBufferPrefix(cg, ar, m_exp1)) {
SimpleVariablePtr sv = static_pointer_cast<SimpleVariable>(m_exp1);
if (m_exp2->hasCPPTemp()) {
cg_printf("%s.appendWithTaint(%s)",
stringBufferName(Option::TempPrefix, prefix,
sv->getName().c_str()).c_str(),
m_exp2->cppTemp().c_str());
return;
} else {
ExpressionPtrVec ev;
bool hasVoid = false;
getConcatList(ev, m_exp2, hasVoid);
if (!hasVoid) {
cg_printf("%s", stringBufferName(Option::TempPrefix, prefix,
sv->getName().c_str()).c_str());
outputStringBufExprs(ev, cg, ar);
return;
}
}
}
cg_printf("concat_assign");
break;
case '.':
{
ExpressionPtr self = static_pointer_cast<Expression>(shared_from_this());
ExpressionPtrVec ev;
bool hasVoid = false;
int num = getConcatList(ev, self, hasVoid);
if (num < 2) {
cg_printf("concat");
break;
}
always_assert(!hasVoid);
if (num <= MAX_CONCAT_ARGS) {
if (num == 2) {
cg_printf("concat(");
} else {
if (num > MAX_CONCAT_ARGS) ar->m_concatLengths.insert(num);
cg_printf("concat%d(", num);
}
for (size_t i = 0; i < ev.size(); i++) {
ExpressionPtr exp = ev[i];
if (i) cg_printf(", ");
outputStringExpr(cg, ar, exp, false);
}
cg_printf(")");
} else {
cg_printf("StringBuffer()");
outputStringBufExprs(ev, cg, ar);
cg_printf(".detachWithTaint()");
}
}
return;
case T_LOGICAL_XOR: cg_printf("logical_xor"); break;
case '|': cg_printf("bitwise_or"); break;
case '&': cg_printf("bitwise_and"); break;
case '^': cg_printf("bitwise_xor"); break;
case T_IS_IDENTICAL: cg_printf("same"); break;
case T_IS_NOT_IDENTICAL: cg_printf("!same"); break;
case T_IS_EQUAL: cg_printf("equal"); break;
case T_IS_NOT_EQUAL: cg_printf("!equal"); break;
case '<': cg_printf("less"); break;
case T_IS_SMALLER_OR_EQUAL: cg_printf("not_more"); break;
case '>': cg_printf("more"); break;
case T_IS_GREATER_OR_EQUAL: cg_printf("not_less"); break;
case '/': cg_printf("divide"); break;
case '%': cg_printf("modulo"); break;
case T_INSTANCEOF: cg_printf("instanceOf"); break;
case T_COLLECTION: cg_printf("Object"); break;
default:
wrapped = !isUnused();
break;
}
if (wrapped) cg_printf("(");
ExpressionPtr first = m_exp1;
ExpressionPtr second = m_exp2;
// we could implement these functions natively on String and Array classes
switch (m_op) {
case '+':
case '-':
case '*':
case '/':
if (!first->outputCPPArithArg(cg, ar, m_op == '+')) {
TypePtr argType = first->hasCPPTemp() ?
first->getType() : first->getActualType();
bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope());
first->outputCPP(cg, ar);
if (flag) {
cg_printf(")");
}
}
break;
case T_SL:
case T_SR:
assert(first->getType()->is(Type::KindOfInt64));
first->outputCPP(cg, ar);
break;
case T_COLLECTION:
/* do nothing */
break;
default:
first->outputCPP(cg, ar);
break;
}
switch (m_op) {
case T_PLUS_EQUAL: cg_printf(" += "); break;
case T_MINUS_EQUAL: cg_printf(" -= "); break;
case T_MUL_EQUAL: cg_printf(" *= "); break;
case T_DIV_EQUAL: cg_printf(" /= "); break;
case T_MOD_EQUAL: cg_printf(" %%= "); break;
case T_AND_EQUAL: cg_printf(" &= "); break;
case T_OR_EQUAL: cg_printf(" |= "); break;
case T_XOR_EQUAL: cg_printf(" ^= "); break;
case T_SL_EQUAL: cg_printf(" <<= "); break;
case T_SR_EQUAL: cg_printf(" >>= "); break;
case T_BOOLEAN_OR: cg_printf(" || "); break;
case T_BOOLEAN_AND: cg_printf(" && "); break;
case T_LOGICAL_OR: cg_printf(" || "); break;
case T_LOGICAL_AND: cg_printf(" && "); break;
case T_COLLECTION: /* print nothing */ break;
default:
switch (m_op) {
case '+': cg_printf(" + "); break;
case '-': cg_printf(" - "); break;
case '*': cg_printf(" * "); break;
case T_SL: cg_printf(" << "); break;
case T_SR: cg_printf(" >> "); break;
default:
cg_printf(", ");
break;
}
break;
}
switch (m_op) {
case '+':
case '-':
case '*':
case '/':
if (!second->outputCPPArithArg(cg, ar, m_op == '+')) {
TypePtr argType = second->hasCPPTemp() ?
second->getType() : second->getActualType();
bool flag = castIfNeeded(getActualType(), argType, cg, ar, getScope());
second->outputCPP(cg, ar);
if (flag) {
cg_printf(")");
}
}
break;
case T_INSTANCEOF:
{
if (second->isScalar()) {
ScalarExpressionPtr scalar =
dynamic_pointer_cast<ScalarExpression>(second);
bool notQuoted = scalar && !scalar->isQuoted();
std::string s = second->getLiteralString();
if (s == "static" && notQuoted) {
cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())");
} else if (s != "") {
if (s == "self" && notQuoted) {
ClassScopeRawPtr cls = getOriginalClass();
if (cls) {
s = cls->getOriginalName();
}
} else if (s == "parent" && notQuoted) {
ClassScopeRawPtr cls = getOriginalClass();
if (cls && !cls->getOriginalParent().empty()) {
s = cls->getOriginalParent();
}
}
cg_printString(s, ar, shared_from_this());
} else {
second->outputCPP(cg, ar);
}
} else {
second->outputCPP(cg, ar);
}
break;
}
case T_PLUS_EQUAL:
case T_MINUS_EQUAL:
case T_MUL_EQUAL:
{
TypePtr t1 = first->getCPPType();
TypePtr t2 = second->getType();
if (t1 && !t1->is(Type::KindOfArray) &&
t2 && Type::IsCastNeeded(ar, t2, t1)) {
t1->outputCPPCast(cg, ar, getScope());
cg_printf("(");
second->outputCPP(cg, ar);
cg_printf(")");
} else {
second->outputCPP(cg, ar);
}
break;
}
case T_BOOLEAN_OR:
case T_BOOLEAN_AND:
case T_LOGICAL_AND:
case T_LOGICAL_OR:
if (isUnused()) {
cg_printf("(");
if (second->outputCPPUnneeded(cg, ar)) {
cg_printf(",");
}
cg_printf("false)");
} else {
second->outputCPP(cg, ar);
}
break;
default:
second->outputCPP(cg, ar);
}
if (wrapped) cg_printf(")");
}
@@ -51,13 +51,6 @@ public:
virtual ExpressionPtr unneededHelper();
virtual bool canonCompare(ExpressionPtr e) const;
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool outputCPPImplOpEqual(CodeGenerator &cg, AnalysisResultPtr ar);
static int getConcatList(ExpressionPtrVec &ev, ExpressionPtr exp,
bool &hasVoid);
bool isAssignmentOp() const { return m_assign; }
@@ -199,7 +199,7 @@ TypePtr ClassConstantExpression::inferTypes(AnalysisResultPtr ar,
}
unsigned ClassConstantExpression::getCanonHash() const {
int64 val =
int64_t val =
hash_string(Util::toLower(m_varName).c_str(), m_varName.size()) -
hash_string(Util::toLower(m_className).c_str(), m_className.size());
return ~unsigned(val) ^ unsigned(val >> 32);
@@ -225,79 +225,3 @@ bool ClassConstantExpression::isDynamic() const {
if (!m_valid) return true;
return m_defScope->getConstants()->isDynamic(m_varName);
}
void ClassConstantExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (m_class) {
cg_printf("get_class_constant(");
if (m_class->is(KindOfScalarExpression)) {
assert(strcasecmp(dynamic_pointer_cast<ScalarExpression>(m_class)->
getString().c_str(), "static") == 0);
cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())");
} else {
cg_printf("get_static_class_name(");
m_class->outputCPP(cg, ar);
cg_printf(")");
}
cg_printf(", \"%s\")", m_varName.c_str());
return;
}
bool outsideClass = !isPresent();
if (m_valid) {
string trueClassName;
assert(m_defScope);
ClassScope *cls = dynamic_cast<ClassScope*>(m_defScope);
trueClassName = cls->getName();
assert(!trueClassName.empty());
if (outsideClass) {
cls->outputVolatileCheckBegin(cg, ar, getScope(), m_origClassName);
}
if (cls->getConstants()->isDynamic(m_varName)) {
cg_printf("%s%s->lazy_initializer(%s)->",
Option::ClassStaticsCallbackPrefix, cls->getId().c_str(),
cg.getGlobals(ar));
if (cg.isFileOrClassHeader()) {
if (getClassScope()) {
getClassScope()->addUsedClassFullHeader(ClassScopeRawPtr(cls));
} else {
getFileScope()->addUsedClassFullHeader(ClassScopeRawPtr(cls));
}
}
} else if (cg.isFileOrClassHeader()) {
if (getClassScope()) {
getClassScope()->addUsedClassConstHeader(ClassScopeRawPtr(cls),
m_varName);
} else {
getFileScope()->addUsedClassConstHeader(ClassScopeRawPtr(cls),
m_varName);
}
}
cg_printf("%s%s%s%s",
Option::ClassConstantPrefix, cls->getId().c_str(),
Option::IdPrefix.c_str(), m_varName.c_str());
if (outsideClass) {
cls->outputVolatileCheckEnd(cg);
}
} else if (isRedeclared()) {
if (outsideClass) {
ClassScope::OutputVolatileCheckBegin(cg, ar, getScope(), m_origClassName);
}
const string &clsName = CodeGenerator::FormatLabel(m_className);
cg_printf("%s->%s%s->os_constant(\"%s\")", cg.getGlobals(ar),
Option::ClassStaticsCallbackPrefix,
clsName.c_str(), m_varName.c_str());
if (outsideClass) {
ClassScope::OutputVolatileCheckEnd(cg);
}
} else if (m_defScope) { // !m_valid && m_defScope -> derives from redeclaring
cg_printf("%s%s->os_constant(\"%s\")",
Option::ClassStaticsCallbackPrefix, m_defScope->getId().c_str(),
m_varName.c_str());
} else {
cg_printf("throw_fatal(\"unknown class constant %s::%s\")",
CodeGenerator::EscapeLabel(m_className).c_str(),
m_varName.c_str());
}
}
+29 -75
Ver Arquivo
@@ -19,6 +19,7 @@
#include <compiler/expression/expression_list.h>
#include <compiler/expression/simple_variable.h>
#include <compiler/statement/function_statement.h>
#include <compiler/statement/static_statement.h>
#include <compiler/analysis/variable_table.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/analysis/file_scope.h>
@@ -151,9 +152,6 @@ void ClosureExpression::analyzeProgram(AnalysisResultPtr ar) {
return;
}
if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
if (m_func->getFileScope() != getFileScope()) {
getFileScope()->addUsedClosure(m_func->getFunctionScope());
}
// closure function's variable table (not containing function's)
VariableTablePtr variables = m_func->getFunctionScope()->getVariables();
for (int i = 0; i < m_vars->getCount(); i++) {
@@ -232,6 +230,34 @@ TypePtr ClosureExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
return s_ClosureType;
}
bool ClosureExpression::hasStaticLocals() {
ConstructPtr cons(m_func);
return hasStaticLocalsImpl(cons);
}
bool ClosureExpression::hasStaticLocalsImpl(ConstructPtr root) {
if (!root) {
return false;
}
if (root->getFunctionScope() != m_func->getFunctionScope()) {
// new scope, new statics
return false;
}
for (int i = 0; i < root->getKidCount(); i++) {
ConstructPtr cons = root->getNthKid(i);
if (StatementPtr s = dynamic_pointer_cast<Statement>(cons)) {
if (s->is(Statement::KindOfStaticStatement)) {
return true;
}
}
if (hasStaticLocalsImpl(cons)) {
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
@@ -244,75 +270,3 @@ void ClosureExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
m_func->outputPHPBody(cg, ar);
}
bool ClosureExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
FunctionScopeRawPtr cfunc(m_func->getFunctionScope());
bool output = false;
for (BlockScopePtr sc = cfunc->getOuterScope(); sc;
sc = sc->getOuterScope()) {
if (sc->is(BlockScope::ClassScope)) {
ClassScopePtr cls = boost::static_pointer_cast<ClassScope>(sc);
if (cls->isTrait()) {
output = true;
break;
}
}
}
if (!cg.inExpression()) {
return output || Expression::preOutputCPP(cg, ar, state);
}
if (output) {
cg.wrapExpressionBegin();
cfunc->outputCPPPreface(cg, ar);
}
return Expression::preOutputCPP(cg, ar, state) || output;
}
void ClosureExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
FunctionScopeRawPtr cfunc(m_func->getFunctionScope());
VariableTablePtr vt(cfunc->getVariables());
ParameterExpressionPtrIdxPairVec useVars;
bool needsAnonCls = cfunc->needsAnonClosureClass(useVars);
const string &origName = m_func->getOriginalName();
if (needsAnonCls) {
cg_printf("%sClosure$%s(NEWOBJ(%sClosure$%s)(&%s%s, \"%s\"",
Option::SmartPtrPrefix, origName.c_str(),
Option::ClassPrefix, origName.c_str(),
Option::CallInfoPrefix, origName.c_str(),
origName.c_str());
} else {
// no use vars, so can use the generic closure
cg_printf("%sClosure(NEWOBJ(%sClosure)(&%s%s, \"%s\"",
Option::SmartPtrPrefix, Option::ClassPrefix,
Option::CallInfoPrefix, origName.c_str(),
origName.c_str());
}
bool hasEmit = false;
if (needsAnonCls) {
if (!useVars.empty()) cg_printf(", ");
BOOST_FOREACH(ParameterExpressionPtrIdxPair paramPair, useVars) {
ParameterExpressionPtr param(paramPair.first);
ExpressionPtr value((*m_values)[paramPair.second]);
if (!hasEmit) hasEmit = true;
else cg_printf(", ");
bool ref = param->isRef() && value->isRefable();
if (ref) {
value->setContext(NoRefWrapper);
cg_printf("strongBind(");
}
value->outputCPP(cg, ar);
if (ref) cg_printf(")");
}
}
cg_printf("))");
}
+4 -1
Ver Arquivo
@@ -32,7 +32,6 @@ public:
FunctionStatementPtr func, ExpressionListPtr vars);
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
virtual bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
virtual ConstructPtr getNthKid(int n) const;
virtual void setNthKid(int n, ConstructPtr cp);
@@ -41,12 +40,16 @@ public:
FunctionStatementPtr getClosureFunction() { return m_func; }
ExpressionListPtr getClosureVariables() { return m_vars; }
ExpressionListPtr getClosureValues() { return m_values; }
bool hasStaticLocals();
private:
FunctionStatementPtr m_func;
ExpressionListPtr m_vars;
ExpressionListPtr m_values;
static TypePtr s_ClosureType;
bool hasStaticLocalsImpl(ConstructPtr root);
};
///////////////////////////////////////////////////////////////////////////////
+1 -55
Ver Arquivo
@@ -100,7 +100,7 @@ bool ConstantExpression::getScalarValue(Variant &value) {
}
unsigned ConstantExpression::getCanonHash() const {
int64 val = hash_string(Util::toLower(m_name).c_str(), m_name.size());
int64_t val = hash_string(Util::toLower(m_name).c_str(), m_name.size());
return ~unsigned(val) ^ unsigned(val >> 32);
}
@@ -285,57 +285,3 @@ TypePtr ConstantExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
void ConstantExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf("%s", m_name.c_str());
}
void ConstantExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
// special cases: STDIN, STDOUT, STDERR, INF, and NAN
if (m_name == "STDIN" || m_name == "STDOUT" || m_name == "STDERR") {
cg_printf("%s%s", Option::ConstantPrefix, m_name.c_str());
return;
}
if (m_name == "INF" || m_name == "NAN") {
if (cg.hasScalarVariant() && Option::UseScalarVariant) {
cg_printf("%s_varNR", m_name.c_str());
} else {
cg_printf("%s%s", Option::ConstantPrefix, m_name.c_str());
}
return;
}
string lower = Util::toLower(m_name);
bool requireFwDeclaration = false;
if (lower == "true" || lower == "false" || lower == "null") {
if (cg.hasScalarVariant()) {
cg_printf((Option::UseScalarVariant ? "%s_varNR" : "%s"), lower.c_str());
} else {
cg_printf("%s", lower.c_str());
}
} else if (m_valid) {
if (m_dynamic) {
cg_printf("getDynamicConstant(%s->%s%s, ",
cg.getGlobals(ar), Option::ConstantPrefix,
CodeGenerator::FormatLabel(m_name).c_str());
cg_printString(m_name, ar, shared_from_this());
cg_printf(")");
} else {
cg_printf("%s%s", Option::ConstantPrefix,
CodeGenerator::FormatLabel(m_name).c_str());
requireFwDeclaration = true;
}
} else {
cg_printf("getUndefinedConstant(");
cg_printString(CodeGenerator::FormatLabel(m_name).c_str(), ar,
shared_from_this());
cg_printf(")");
requireFwDeclaration = true;
}
if (requireFwDeclaration && cg.isFileOrClassHeader()) {
if (getClassScope()) {
getClassScope()->addUsedConstHeader(m_name);
} else {
getFileScope()->addUsedConstHeader(m_name);
}
}
}
@@ -53,6 +53,7 @@ public:
const std::string &getDocComment() const {
return m_docComment;
}
bool isNull() const;
bool isBoolean() const;
bool isDouble() const;
@@ -120,8 +120,6 @@ TypePtr DynamicFunctionCall::inferTypes(AnalysisResultPtr ar, TypePtr type,
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void DynamicFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
outputLineMap(cg, ar);
if (m_class || !m_className.empty()) {
StaticClassName::outputPHP(cg, ar);
cg_printf("::");
@@ -144,172 +142,3 @@ void DynamicFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_params) m_params->outputPHP(cg, ar);
cg_printf(")");
}
bool DynamicFunctionCall::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
bool nonStatic = !m_class && m_className.empty();
if (!nonStatic && !m_class && !m_classScope && !isRedeclared()) {
// call to an unknown class
// set m_noStatic to avoid pointlessly wrapping the call
// in STATIC_CLASS_NAME_CALL()
m_noStatic = true;
cg.pushCallInfo(-1);
bool ret = FunctionCall::preOutputCPP(cg, ar, state);
cg.popCallInfo();
return ret;
}
// Short circuit out if inExpression() returns false
if (!cg.inExpression()) return true;
cg.wrapExpressionBegin();
m_ciTemp = cg.createNewLocalId(shared_from_this());
if (!m_classScope && !m_className.empty() && m_cppTemp.empty() &&
!isSelf() && ! isParent() && !isStatic()) {
// Create a temporary to hold the class name, in case it is not a
// StaticString.
m_clsNameTemp = cg.createNewLocalId(shared_from_this());
cg_printf("CStrRef clsName%d(", m_clsNameTemp);
cg_printString(m_origClassName, ar, shared_from_this());
cg_printf(");\n");
}
if (m_class) {
int s = m_class->hasEffect() || m_nameExp->hasEffect() ?
FixOrder : 0;
m_class->preOutputCPP(cg, ar, s);
}
m_nameExp->preOutputCPP(cg, ar, 0);
if (nonStatic) {
cg_printf("const CallInfo *cit%d;\n", m_ciTemp);
cg_printf("void *vt%d;\n", m_ciTemp);
cg_printf("get_call_info_or_fail(cit%d, vt%d, ", m_ciTemp, m_ciTemp);
if (m_nameExp->is(Expression::KindOfSimpleVariable)) {
m_nameExp->outputCPP(cg, ar);
} else {
cg_printf("(");
m_nameExp->outputCPP(cg, ar);
cg_printf(")");
}
cg_printf(");\n");
} else {
cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
if (m_class) {
if (m_class->is(KindOfScalarExpression)) {
assert(strcasecmp(dynamic_pointer_cast<ScalarExpression>(m_class)->
getString().c_str(), "static") == 0);
cg_printf("CStrRef cls%d = "
"FrameInjection::GetStaticClassName(fi.getThreadInfo())",
m_ciTemp);
} else {
cg_printf("C%sRef cls%d = ",
m_class->getActualType() &&
m_class->getActualType()->is(Type::KindOfString) ?
"Str" : "Var", m_ciTemp);
m_class->outputCPP(cg, ar);
}
} else if (m_classScope) {
cg_printf("CStrRef cls%d = ", m_ciTemp);
cg_printString(m_classScope->getId(), ar, shared_from_this());
} else {
cg_printf("CStrRef cls%d = ", m_ciTemp);
cg_printString(m_className, ar, shared_from_this());
}
cg_printf(";\n");
cg_printf("CStrRef mth%d = ", m_ciTemp);
if (m_nameExp->is(Expression::KindOfSimpleVariable)) {
m_nameExp->outputCPP(cg, ar);
} else {
cg_printf("(");
m_nameExp->outputCPP(cg, ar);
cg_printf(")");
}
cg_printf(";\n");
bool dynamic = true;
if (!m_class) {
ClassScopeRawPtr origClass = getOriginalClass();
if (!origClass) {
dynamic = false;
} else {
FunctionScopeRawPtr origFunc = getOriginalFunction();
if (origFunc) {
if (origFunc->isStatic() ||
(m_classScope != origClass &&
(m_className.empty() || !origClass->derivesFrom(
ar, m_className, true, true)))) {
dynamic = false;
}
}
}
}
if (dynamic) {
if ((m_class && (!m_class->getActualType() ||
!m_class->getActualType()->is(Type::KindOfString))) ||
!getOriginalFunction() ||
!getOriginalClass() ||
getOriginalFunction()->isStatic()) {
cg_printf("mcp%d.dynamicNamedCall(cls%d, mth%d);\n",
m_ciTemp, m_ciTemp, m_ciTemp);
} else {
cg_printf("mcp%d.isObj = true;\n", m_ciTemp);
cg_printf("mcp%d.rootObj = this;\n", m_ciTemp);
cg_printf("mcp%d.name = &mth%d;\n", m_ciTemp, m_ciTemp);
cg_printf("o_get_call_info_ex(cls%d, mcp%d);\n", m_ciTemp, m_ciTemp);
}
} else {
cg_printf("mcp%d.staticMethodCall(cls%d, mth%d);\n",
m_ciTemp,
m_ciTemp, m_ciTemp);
if (m_classScope) {
cg_printf("%s%s.%sget_call_info(mcp%d);\n",
Option::ClassStaticsCallbackPrefix,
m_classScope->getId().c_str(),
Option::ObjectStaticPrefix, m_ciTemp);
} else if (isRedeclared()) {
cg_printf("g->%s%s->%sget_call_info(mcp%d);\n",
Option::ClassStaticsCallbackPrefix, m_className.c_str(),
Option::ObjectStaticPrefix, m_ciTemp);
} else {
not_reached();
}
}
cg_printf("const CallInfo *cit%d = mcp%d.ci;\n", m_ciTemp, m_ciTemp);
}
if (m_params && m_params->getCount() > 0) {
cg.pushCallInfo(m_ciTemp);
m_params->preOutputCPP(cg, ar, 0);
cg.popCallInfo();
}
if (state & FixOrder) {
cg.pushCallInfo(m_ciTemp);
preOutputStash(cg, ar, state);
cg.popCallInfo();
}
return true;
}
void DynamicFunctionCall::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
bool method = false;
if (m_class || !m_className.empty()) {
if (!m_class && !m_classScope && !isRedeclared()) {
const string &name = CodeGenerator::EscapeLabel(m_className);
cg_printf("throw_fatal(\"unknown class %s\")", name.c_str());
return;
}
method = true;
}
cg_printf("(cit%d->", m_ciTemp);
outputDynamicCall(cg, ar, method);
}
@@ -32,7 +32,6 @@ public:
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
ExpressionPtr preOptimize(AnalysisResultConstPtr ar);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
};
///////////////////////////////////////////////////////////////////////////////
@@ -95,9 +95,3 @@ void DynamicVariable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_exp->outputPHP(cg, ar);
cg_printf("}");
}
void DynamicVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf("variables->get(");
m_exp->outputCPP(cg, ar);
cg_printf(")");
}
@@ -136,55 +136,3 @@ void EncapsListExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_type == '`') cg_printf(")");
}
static void outputListElement(ExpressionPtr exp, CodeGenerator &cg,
AnalysisResultPtr ar) {
if (exp->is(Expression::KindOfScalarExpression)) {
TypePtr actType = exp->getActualType();
bool str = actType && actType->is(Type::KindOfString);
if (!str) cg_printf("toString(");
exp->outputCPP(cg, ar);
if (!str) cg_printf(")");
} else {
exp->outputCPP(cg, ar);
}
}
void EncapsListExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (m_type == '`') cg_printf("f_shell_exec(");
if (m_exps) {
int n = m_exps->getCount();
always_assert(n > 0);
if (n == 1) {
ExpressionPtr exp = (*m_exps)[0];
outputListElement(exp, cg, ar);
} else if (n <= MAX_CONCAT_ARGS) {
if (n == 2) {
cg_printf("concat(");
} else {
cg_printf("concat%d(", n);
}
for (int i = 0; i < n; i++) {
ExpressionPtr exp = (*m_exps)[i];
if (i > 0) cg_printf(", ");
outputListElement(exp, cg, ar);
}
cg_printf(")");
} else {
cg_printf("StringBuffer()");
for (int i = 0; i < n; i++) {
ExpressionPtr exp = (*m_exps)[i];
cg_printf(".addWithTaint(");
outputListElement(exp, cg, ar);
cg_printf(")");
}
cg_printf(".detachWithTaint()");
}
} else {
cg_printf("\"\"");
}
if (m_type == '`') cg_printf(")");
}
+2 -802
Ver Arquivo
@@ -308,22 +308,6 @@ FunctionScopeRawPtr Expression::getOriginalFunction() {
return scope ? scope->getContainingFunction() : FunctionScopeRawPtr();
}
string Expression::originalClassName(CodeGenerator &cg, bool withComma) {
ClassScopeRawPtr cls = getOriginalClass();
string ret = withComma ? ", " : "";
if (cls) {
if (cls == getClassScope()) {
return ret + "s_class_name";
}
return ret + Option::ClassPrefix + cls->getId() + "::s_class_name";
} else if (FunctionScopePtr funcScope = getOriginalFunction()) {
if (!funcScope->inPseudoMain()) {
return ret + "empty_string";
}
}
return withComma ? "" : "null_string";
}
void Expression::resetTypes() {
m_actualType .reset();
m_expectedType .reset();
@@ -547,11 +531,11 @@ void Expression::CheckPassByReference(AnalysisResultPtr ar,
}
unsigned Expression::getCanonHash() const {
int64 val = hash_int64(getKindOf());
int64_t val = hash_int64(getKindOf());
for (int i = getKidCount(); i--; ) {
ExpressionPtr k = getNthExpr(i);
if (k) {
val = hash_int64(val ^ (((int64)k->getKindOf()<<32)+k->getCanonID()));
val = hash_int64(val ^ (((int64_t)k->getKindOf()<<32)+k->getCanonID()));
}
}
@@ -726,487 +710,6 @@ ExpressionPtr Expression::MakeScalarExpression(AnalysisResultConstPtr ar,
///////////////////////////////////////////////////////////////////////////////
bool Expression::outputLineMap(CodeGenerator &cg, AnalysisResultPtr ar,
bool force /* = false */) {
switch (cg.getOutput()) {
case CodeGenerator::TrimmedPHP:
if (cg.getStream(CodeGenerator::MapFile) &&
cg.usingStream(CodeGenerator::PrimaryStream)) {
cg.useStream(CodeGenerator::MapFile);
cg_printf("%d => '%s:%d',", cg.getLineNo(CodeGenerator::PrimaryStream),
getLocation()->file, getLocation()->line1);
cg.useStream(CodeGenerator::PrimaryStream);
}
break;
case CodeGenerator::ClusterCPP:
{
if (!force &&
!(getLocalEffects() & (Construct::CanThrow|
Construct::AccessorEffect|
Construct::DiagnosticEffect))) {
return false;
}
int line = cg.getLineNo(CodeGenerator::PrimaryStream);
LocationPtr loc = getLocation();
if (loc) {
ar->recordSourceInfo(cg.getFileName(), line, loc);
if (cg.getPHPLineNo() != loc->line1) {
cg.setPHPLineNo(loc->line1);
cg_printf("LINE(%d,", loc->line1);
return true;
}
}
}
break;
default:
break;
}
return false;
}
bool Expression::outputCPPArithArg(CodeGenerator &cg, AnalysisResultPtr ar,
bool arrayOk) {
TypePtr at = getActualType();
if (at &&
(at->is(Type::KindOfString) ||
at->is(Type::KindOfObject) ||
(at->is(Type::KindOfArray) && !arrayOk)) &&
(!hasCPPTemp() || getCPPType()->isExactType())) {
if (!hasCPPTemp() && !getCPPType()->isExactType()) {
TypePtr et = getExpectedType();
setExpectedType(TypePtr());
setActualType(getCPPType());
outputCPP(cg, ar);
setActualType(at);
setExpectedType(et);
} else {
cg_printf("(Variant)(");
outputCPP(cg, ar);
cg_printf(")");
}
return true;
}
return false;
}
void Expression::outputCPPCast(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_expectedType) {
m_expectedType->outputCPPCast(cg, ar, getScope());
}
}
void Expression::outputCPPDecl(CodeGenerator &cg, AnalysisResultPtr ar) {
TypePtr type = m_actualType;
if (!type) type = Type::Variant;
type->outputCPPDecl(cg, ar, getScope());
}
std::string Expression::genCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar) {
std::ostringstream os;
os << Option::TempPrefix << cg.createNewLocalId(shared_from_this());
return os.str();
}
void Expression::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (hasCPPTemp() || isScalar()) return;
bool fastCast = needsFastCastTemp(ar);
if (!isLocalExprAltered() && !hasEffect() &&
!fastCast && !(state & StashAll)) {
return;
}
bool killCast = false;
TypePtr srcType, dstType, dstType0;
bool needsCast = getTypeCastPtrs(ar, srcType, dstType);
bool isLvalue = (m_context & LValue);
bool isTemp = isTemporary();
bool isReferenced = true;
if (fastCast) {
isTemp = true;
killCast = true;
dstType0 = dstType;
dstType = Type::Variant;
isReferenced = couldCppTypeBeReferenced();
} else if (needsCast) {
isTemp = true;
} else {
killCast = true;
dstType = srcType;
}
if (dstType) {
if (isUnused()) {
dstType.reset();
} else switch (dstType->getKindOf()) {
case Type::KindOfAny:
case Type::KindOfSome:
dstType = Type::Variant;
break;
default:
break;
}
}
bool eltOrPropArg = hasContext(InvokeArgument) &&
(is(KindOfArrayElementExpression) || is(KindOfObjectPropertyExpression));
bool constRef = dstType &&
((m_context & (RefValue|RefParameter)) ||
(isTemp && !dstType->isPrimitive()) || eltOrPropArg ||
(isLvalue && dynamic_cast<FunctionCall*>(this)));
cg.wrapExpressionBegin();
// make LINE macro separate to not interfere with persistance of expression.
// and because nested LINE macros dont work
if (outputLineMap(cg, ar)) cg_printf("0);\n");
if (constRef) {
cg_printf("const ");
}
if (dstType) {
bool inlinedRefReturn = hasAllContext(LValue|ReturnContext) &&
!hasAnyContext(InvokeArgument|RefValue);
bool refParam = hasContext(RefValue) &&
!hasAnyContext(InvokeArgument|AssignmentRHS|ReturnContext) &&
(is(KindOfObjectPropertyExpression) ||
is(KindOfArrayElementExpression));
if (inlinedRefReturn) {
cg_printf("Variant");
} else if (refParam) {
cg_printf("VRefParamValue");
} else {
dstType->outputCPPDecl(cg, ar, getScope());
}
std::string t = genCPPTemp(cg, ar);
const char *ref =
(!inlinedRefReturn &&
(isLvalue || constRef) &&
!(state & ForceTemp)) ? "&" : "";
/*
Note that double parens are necessary:
type_name1 tmp27(type_name2(foo));
type_name1 tmp28((type_name2(foo)));
tmp27 is a function returning a type_name1 taking a parameter of
type type_name2 (not what we want!)
tmp28 is an object of type type_name1, initialized by type_name2(foo)
*/
cg_printf(" %s%s((", ref, t.c_str());
/*
In c++ a temporary bound to a reference gets the lifetime of the
reference.
So "const Variant &tmp27 = foo()" generates a temporary, and binds it
to v, with the lifetime of v.
But "const Variant &tmp27 = ref(foo())", creates a temporary, binds it
to ref's parameter, returns a reference to that, and binds that to v;
but the temporary gets destroyed at the end of the statement.
So we clear the ref context here, and output the ref when we output the
use of the temporary (top of outputCPP, below), but in that case, we also
need to set the lval context, otherwise, rvalAt would be generated for
array elements and object properties.
*/
int save = m_context;
if (inlinedRefReturn) {
cg_printf("strongBind(");
} else if (refParam) {
m_context &= ~RefParameter;
} else if (hasContext(RefValue)) {
m_context &= ~RefValue;
if (is(KindOfObjectPropertyExpression) ||
(is(KindOfArrayElementExpression) &&
!(m_context & InvokeArgument))) {
m_context |= LValue;
m_context &= ~NoLValueWrapper;
}
}
TypePtr et = m_expectedType;
TypePtr at = m_actualType;
TypePtr it = m_implementedType;
if (killCast) {
m_actualType = dstType;
m_implementedType.reset();
m_expectedType.reset();
}
outputCPP(cg, ar);
if (killCast) {
m_actualType = at;
m_expectedType = et;
m_implementedType = it;
}
m_context = save;
if (inlinedRefReturn) cg_printf(")");
cg_printf("));\n");
if (!refParam && constRef &&
(isLvalue || hasContext(DeepReference) || hasContext(UnsetContext))) {
dstType->outputCPPDecl(cg, ar, getScope());
cg_printf(" &%s_lv = const_cast<", t.c_str());
dstType->outputCPPDecl(cg, ar, getScope());
cg_printf("&>(%s);\n", t.c_str());
t += "_lv";
}
if (fastCast) {
assert(dstType0);
assert(srcType == m_implementedType);
dstType = dstType0;
if (constRef && !dstType->isPrimitive()) {
cg_printf("const ");
}
dstType->outputCPPDecl(cg, ar, getScope());
cg_printf(" %s%s_vv = ",
dstType->isPrimitive() ? "" : "&",
t.c_str());
int closeParen = 0;
string method = Type::GetFastCastMethod(
m_actualType, isReferenced, constRef);
if (!Type::SameType(m_actualType, dstType)) {
dstType->outputCPPCast(cg, ar, getScope());
cg_printf("(");
closeParen++;
if (m_actualType->is(Type::KindOfObject)) {
method = "getObjectDataOrNull";
} else if (m_actualType->is(Type::KindOfString)) {
method = "getStringDataOrNull";
} else if (m_actualType->is(Type::KindOfArray)) {
method = "getArrayDataOrNull";
}
} else if (m_actualType->isSpecificObject()) {
cg_printf("(");
closeParen++;
m_actualType->outputCPPFastObjectCast(
cg, ar, getScope(), constRef);
cg_printf("(");
closeParen++;
}
cg_printf("%s.%s()", t.c_str(), method.c_str());
for (int i = 0; i < closeParen; i++) cg_printf(")");
cg_printf(";\n");
t += "_vv";
}
m_cppTemp = t;
} else {
if (outputCPPUnneeded(cg, ar)) {
cg_printf(";\n");
}
m_cppTemp = "null";
}
}
bool Expression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (isScalar()) {
return false;
}
bool paramList =
is(KindOfExpressionList) &&
static_cast<ExpressionList*>(this)->getListKind() ==
ExpressionList::ListKindParam;
bool stashAll = state & StashAll;
state &= ~StashAll;
bool doStash = (state & FixOrder) != 0 || needsFastCastTemp(ar);
bool ret = doStash;
int kidState = (state & ~(StashKidVars|StashVars|FixOrder|ForceTemp));
if (state & StashKidVars) kidState |= StashVars;
int lastEffect = -1, i;
int n = getKidCount();
if (hasEffect()) {
int j;
for (i = j = 0; i < n; i++) {
ExpressionPtr k = getNthExpr(i);
if (k && !k->isScalar()) {
if (k->hasEffect()) {
lastEffect = i;
if (!j && (n > 1 || paramList) && k->isTemporary() &&
(!k->hasContext(ExistContext) ||
(!k->is(KindOfObjectPropertyExpression) &&
!k->is(KindOfArrayElementExpression)))) {
j++;
}
}
j++;
}
}
if (lastEffect >= 0 && j > 1) {
kidState |= FixOrder;
if (stashAll) {
lastEffect = n - 1;
}
ret = true;
}
}
if (!ret || cg.inExpression()) {
if (paramList) kidState |= FixOrder;
bool skipLast = !stashAll;
int lastState = kidState | StashByRef;
if (stashAll) lastState |= StashVars;
for (i = 0; i <= lastEffect; i++) {
ExpressionPtr k = getNthExpr(i);
if (k && !k->isScalar()) {
int s = kidState;
if (i == n - 1 && skipLast) s = 0;
bool noEffect = false;
if (m_kindOf == KindOfExpressionList) {
ExpressionList *el = static_cast<ExpressionList*>(this);
if (i >= el->getOutputCount()) {
s = lastState = 0;
noEffect = true;
}
}
if (k->is(KindOfSimpleVariable)) {
skipLast = false;
}
if (k->preOutputCPP(cg, ar, i == lastEffect ? lastState : s)) {
ret = true;
if (!cg.inExpression()) break;
}
if (noEffect) {
k->outputCPPUnneeded(cg, ar);
k->setCPPTemp("0");
cg_printf(";\n");
}
}
}
}
if (doStash) {
if (cg.inExpression()) {
preOutputStash(cg, ar, state);
}
}
return ret;
}
static bool checkOffsetChain(CodeGenerator &cg, ExpressionPtr e,
bool &needsRefTemp) {
bool isArray = e->is(Expression::KindOfArrayElementExpression);
if (isArray || e->is(Expression::KindOfObjectPropertyExpression)) {
if (cg.hasReferenceTemp()) {
bool lval =
e->hasContext(Expression::LValue) ||
e->hasContext(Expression::RefValue) ||
e->hasContext(Expression::DeepReference) ||
e->hasContext(Expression::UnsetContext);
if (isArray) {
if (!lval && !e->hasContext(Expression::InvokeArgument) &&
!static_pointer_cast<ArrayElementExpression>(e)->isSuperGlobal()) {
TypePtr type = e->getNthExpr(0)->getActualType();
if (!type ||
(!type->is(Type::KindOfString) && !type->is(Type::KindOfArray))) {
needsRefTemp = true;
}
}
} else {
if (lval &&
!static_pointer_cast<ObjectPropertyExpression>(e)->isValid()) {
needsRefTemp = true;
}
}
}
if (ExpressionPtr e1 = e->getNthExpr(1)) {
if (e1->hasEffect()) return true;
}
return checkOffsetChain(cg, e->getNthExpr(0), needsRefTemp);
}
return e->hasEffect();
}
bool Expression::preOutputOffsetLHS(CodeGenerator &cg,
AnalysisResultPtr ar,
int state) {
bool ret = (state & FixOrder);
bool needRefTemp = false;
if (!hasContext(AccessContext)) {
if (!ret) {
ret = checkOffsetChain(cg, getNthExpr(0), needRefTemp);
if (!ret &&
(m_context & (LValue | OprLValue |
RefValue | DeepReference | RefParameter))) {
if (ExpressionPtr e1 = getNthExpr(1)) {
if (e1->hasEffect()) {
ret = true;
}
}
}
}
}
// check to see if this elem has a CSE substitution
// or is a chain root. in this case, we need to force a temp
// since we will be taking a reference out, if we need to
// fix our order
bool forceTemp = false;
bool hasCse = false;
ExpressionPtr p(getCanonCsePtr());
if (p && p->hasCPPCseTemp()) {
assert(p->isChainRoot() && !isChainRoot());
if (!isLocalExprAltered()) return false;
hasCse = forceTemp = true;
} else if (hasCPPCseTemp() && isChainRoot()) {
forceTemp = isLocalExprAltered();
}
if (!ret) {
if (hasCse) return false;
if (needRefTemp && cg.inExpression()) {
cg.wrapExpressionBegin();
}
return Expression::preOutputCPP(cg, ar, state) || needRefTemp;
}
if (forceTemp) {
// if a cast was needed, then no need to force temp
TypePtr srcType, dstType;
if (getTypeCastPtrs(ar, srcType, dstType)) {
forceTemp = false;
}
}
if (cg.inExpression()) {
cg.wrapExpressionBegin();
state |= FixOrder;
if (!hasCse) {
if (ExpressionPtr e0 = getNthExpr(0)) {
e0->preOutputCPP(cg, ar, state & ~(StashVars));
}
if (ExpressionPtr e1 = getNthExpr(1)) {
e1->preOutputCPP(cg, ar, state & ~(StashVars));
}
}
if (!hasContext(AccessContext)) {
if (!(m_context & (AssignmentLHS | OprLValue |
ExistContext | UnsetContext))) {
if (forceTemp) state |= ForceTemp;
Expression::preOutputStash(cg, ar, state);
}
}
}
return true;
}
void Expression::collectCPPTemps(ExpressionPtrVec &collection) {
if (isChainRoot()) {
collection.push_back(static_pointer_cast<Expression>(shared_from_this()));
@@ -1340,59 +843,6 @@ ExpressionPtr Expression::getCanonCsePtr() const {
return ExpressionPtr();
}
bool Expression::preOutputCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar,
bool emitTemps) {
ExpressionPtrVec temps;
collectCPPTemps(temps);
if (temps.empty()) return false;
if (emitTemps) {
for (ExpressionPtrVec::iterator it(temps.begin());
it != temps.end();
++it) {
ExpressionPtr p(*it);
if (p->hasCPPCseTemp()) continue;
p->m_cppCseTemp = genCPPTemp(cg, ar);
TypePtr t;
bool needsStorage = Expression::GetCseTempInfo(ar, p, t);
bool useConst = !p->hasContext(Expression::LValue);
bool isString = t && t->is(Type::KindOfString);
const char *s = isString ? "String" : "Variant";
if (!isString) {
cg_printf("%s%s *%s%s;\n",
useConst ? "const " : "",
s,
Option::CseTempVariablePrefix,
p->m_cppCseTemp.c_str());
if (needsStorage) {
cg_printf("%s %s%s;\n",
s,
Option::CseTempStoragePrefix,
p->m_cppCseTemp.c_str());
}
} else {
cg_printf("%s %s%s;\n",
s,
Option::CseTempVariablePrefix,
p->m_cppCseTemp.c_str());
}
}
}
return true;
}
bool Expression::outputCPPBegin(CodeGenerator &cg, AnalysisResultPtr ar) {
preOutputCPPTemp(cg, ar, !cg.inExpression());
cg.setInExpression(true);
return preOutputCPP(cg, ar, 0);
}
bool Expression::outputCPPEnd(CodeGenerator &cg, AnalysisResultPtr ar) {
bool ret = cg.wrapExpressionEnd();
cg.setInExpression(false);
return ret;
}
bool Expression::getTypeCastPtrs(
AnalysisResultPtr ar, TypePtr &srcType, TypePtr &dstType) {
srcType = m_actualType;
@@ -1464,253 +914,3 @@ bool Expression::canUseFastCast(AnalysisResultPtr ar) {
}
return false;
}
bool Expression::outputCPPGuardedObjectPtr(CodeGenerator &cg) {
if (is(KindOfSimpleVariable) &&
static_cast<SimpleVariable*>(this)->isGuarded()) {
TypePtr at = getActualType();
if (at && at->is(Type::KindOfObject)) {
TypePtr it = getImplementedType();
if (it && !it->is(Type::KindOfObject)) {
TypePtr et = getExpectedType();
if (!et || !et->is(Type::KindOfObject)) {
cg_printf(".getObjectData()");
return true;
}
}
cg_printf(".get()");
return true;
}
}
return false;
}
void Expression::outputCPPInternal(CodeGenerator &cg, AnalysisResultPtr ar) {
if (hasError(Expression::BadPassByRef)) {
cg_printf("throw_fatal(\"bad pass by reference\")");
return;
}
int closeParen = 0;
TypePtr srcType, dstType;
bool needsCast = getTypeCastPtrs(ar, srcType, dstType);
bool useFastCast = false;
bool isReferenced = true;
bool isLval = (m_context & LValue);
if (canUseFastCast(ar)) {
useFastCast = true;
isReferenced = couldCppTypeBeReferenced();
}
if (needsCast) {
assert(dstType);
bool isSpecObj = m_actualType && m_actualType->isSpecificObject();
if (!useFastCast ||
!Type::SameType(m_actualType, dstType) ||
isSpecObj) {
if (useFastCast && isSpecObj) {
if (!Type::SameType(m_actualType, dstType)) {
dstType->outputCPPCast(cg, ar, getScope());
cg_printf("(");
closeParen++;
} else {
// specific object is special, since we do not have
// a fast cast method into a specific object on Variant,
// we must emit an additional (but also fast) cast.
// In the end, the cast will look like (for example):
//
// (const X&)(v_var.asCObjRef())
cg_printf("(");
closeParen++;
m_actualType->outputCPPFastObjectCast(cg, ar, getScope(), !isLval);
cg_printf("(");
closeParen++;
}
} else {
dstType->outputCPPCast(cg, ar, getScope());
cg_printf("(");
closeParen++;
}
}
} else {
if (hasContext(RefValue) && !hasContext(NoRefWrapper) &&
isRefable()) {
if (hasContext(RefParameter)) {
cg_printf("strongBind(");
} else {
cg_printf("ref(");
}
useFastCast = false; // cannot ref() or strongBind() a non-variant
closeParen++;
}
if (is(Expression::KindOfArrayElementExpression)) {
if (((m_context & LValue) || ((m_context & RefValue) &&
!(m_context & InvokeArgument))) &&
!(m_context & NoLValueWrapper)) {
isLval = true;
cg_printf("lval(");
closeParen++;
}
}
}
bool needsDeref = false;
if (hasCPPCseTemp()) {
TypePtr t;
GetCseTempInfo(
ar,
static_pointer_cast<Expression>(shared_from_this()),
t);
if (!t || !t->is(Type::KindOfString)) needsDeref = true;
if (isChainRoot()) {
if (!needsDeref) {
cg_printf("(%s%s = (",
Option::CseTempVariablePrefix, m_cppCseTemp.c_str());
closeParen += 2;
} else {
cg_printf("(*(%s%s = &(",
Option::CseTempVariablePrefix, m_cppCseTemp.c_str());
closeParen += 3;
}
}
}
if (hasCPPCseTemp() && !isChainRoot()) {
if (needsDeref) cg_printf("(*");
cg_printf("%s%s",
Option::CseTempVariablePrefix, m_cppCseTemp.c_str());
if (needsDeref) cg_printf(")");
} else {
outputCPPImpl(cg, ar);
}
if (useFastCast) {
assert(srcType == m_implementedType);
string method;
if (!Type::SameType(m_actualType, dstType)) {
if (m_actualType->is(Type::KindOfObject)) {
method = "getObjectDataOrNull";
} else if (m_actualType->is(Type::KindOfString)) {
method = "getStringDataOrNull";
} else if (m_actualType->is(Type::KindOfArray)) {
method = "getArrayDataOrNull";
}
}
if (method.empty()) {
method = Type::GetFastCastMethod(
m_actualType, isReferenced,
!isLval && !(m_context & UnsetContext));
}
cg_printf(".%s()", method.c_str());
}
for (int i = 0; i < closeParen; i++) {
cg_printf(")");
}
string comment;
if (is(Expression::KindOfScalarExpression)) {
ScalarExpressionPtr exp =
dynamic_pointer_cast<ScalarExpression>(shared_from_this());
comment = exp->getComment();
} else if (is(Expression::KindOfConstantExpression)) {
ConstantExpressionPtr exp =
dynamic_pointer_cast<ConstantExpression>(shared_from_this());
comment = exp->getComment();
}
if (!comment.empty()) {
if (cg.inComments()) {
cg_printf(" (%s)", comment.c_str());
} else {
cg_printf(" /* %s */", comment.c_str());
}
}
}
bool Expression::outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar) {
if (hasEffect() && m_cppTemp.empty()) {
setUnused(true);
outputCPP(cg, ar);
return true;
}
return false;
}
void Expression::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
bool inExpression = cg.inExpression();
bool wrapped = false;
TypePtr et = m_expectedType;
TypePtr at = m_actualType;
TypePtr it = m_implementedType;
if (isUnused()) {
if (et) {
m_expectedType.reset();
}
if (it) {
m_implementedType.reset();
m_actualType = it;
}
}
if (!inExpression) {
wrapped = outputCPPBegin(cg, ar);
}
ExpressionPtr p(getCanonCsePtr());
if (p && p->hasCPPCseTemp() && !hasCPPCseTemp()) {
assert(p->isChainRoot() && !isChainRoot());
m_cppCseTemp = p->m_cppCseTemp;
}
if (!m_cppTemp.empty()) {
bool ref = hasContext(RefValue) &&
!hasContext(NoRefWrapper) &&
(hasAnyContext(ReturnContext|AssignmentRHS|RefParameter) ||
!(is(KindOfObjectPropertyExpression) ||
is(KindOfArrayElementExpression))) &&
isRefable();
if (ref) {
if (m_context & RefParameter) {
cg_printf("strongBind(");
} else {
cg_printf("ref(");
}
}
cg_printf("%s", m_cppTemp.c_str());
if (ref) cg_printf(")");
} else {
bool linemap = outputLineMap(cg, ar);
if (linemap) cg_printf("(");
outputCPPInternal(cg, ar);
if (linemap) cg_printf("))");
}
m_implementedType = it;
m_actualType = at;
m_expectedType = et;
if (!inExpression) {
if (wrapped) cg_printf(";");
cg.wrapExpressionEnd();
cg.setInExpression(inExpression);
}
}
void Expression::outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
int op) {
switch (op) {
case T_ISSET: cg_printf("isset("); break;
case T_EMPTY: cg_printf("empty("); break;
default: assert(false);
}
outputCPP(cg, ar);
cg_printf(")");
}
void Expression::outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf("unset(");
outputCPP(cg, ar);
cg_printf(")");
}
+1 -29
Ver Arquivo
@@ -36,8 +36,7 @@
virtual ExpressionPtr clone(); \
virtual TypePtr inferTypes(AnalysisResultPtr ar, TypePtr type, \
bool coerce); \
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar); \
virtual void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar)
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
#define DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS \
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS; \
virtual ConstructPtr getNthKid(int n) const; \
@@ -186,28 +185,9 @@ public:
/**
* Implementing Construct.
*/
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
void outputCPPCast(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void outputCPPDecl(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
int op);
virtual void outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar);
virtual void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
virtual bool outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar);
bool outputCPPBegin(CodeGenerator &cg, AnalysisResultPtr ar);
bool outputCPPEnd(CodeGenerator &cg, AnalysisResultPtr ar);
void collectCPPTemps(ExpressionPtrVec &collection);
void disableCSE();
bool hasChainRoots();
bool preOutputCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar,
bool emitTemps);
virtual bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool preOutputOffsetLHS(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool hasCPPTemp() const { return !m_cppTemp.empty(); }
const std::string &cppTemp() const { return m_cppTemp; }
std::string genCPPTemp(CodeGenerator &cg, AnalysisResultPtr ar);
@@ -216,7 +196,6 @@ public:
void setOriginalScope(BlockScopeRawPtr scope);
ClassScopeRawPtr getOriginalClass();
FunctionScopeRawPtr getOriginalFunction();
std::string originalClassName(CodeGenerator &cg, bool withComma);
/**
* For generic walks
@@ -390,7 +369,6 @@ public:
static bool GetCseTempInfo(
AnalysisResultPtr ar, ExpressionPtr p, TypePtr &t);
bool outputCPPArithArg(CodeGenerator &cg, AnalysisResultPtr ar, bool arrayOk);
bool isUnused() const { return m_unused; }
void setUnused(bool u) { m_unused = u; }
ExpressionPtr fetchReplacement();
@@ -400,8 +378,6 @@ public:
* Correctly compute the local expression altered bit
*/
void computeLocalExprAltered();
bool outputCPPGuardedObjectPtr(CodeGenerator &cg);
protected:
static bool IsIdentifier(const std::string &value);
@@ -432,13 +408,9 @@ protected:
TypePtr expectedType);
void setDynamicByIdentifier(AnalysisResultPtr ar,
const std::string &value);
bool outputLineMap(CodeGenerator &cg, AnalysisResultPtr ar,
bool force = false);
void resetTypes();
private:
static ExprClass Classes[];
void outputCPPInternal(CodeGenerator &cg, AnalysisResultPtr ar);
/**
* Returns true if a type cast is needed, and sets src/dst type
-370
Ver Arquivo
@@ -494,144 +494,6 @@ void ExpressionList::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
}
void ExpressionList::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (hasCPPTemp() || m_kind == ListKindParam || m_arrayElements) {
return;
}
int n = m_exps.size();
int i = m_kind == ListKindLeft ? 0 : n - 1;
if (m_exps[i]->hasCPPTemp() &&
Type::SameType(getType(), m_exps[i]->getType())) {
setUnused(true);
outputCPP(cg, ar);
cg_printf(";\n");
m_cppTemp = m_exps[i]->cppTemp();
}
return Expression::preOutputStash(cg, ar, state);
}
bool ExpressionList::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (m_kind == ListKindParam && !m_arrayElements) {
return Expression::preOutputCPP(cg, ar, state|StashKidVars);
}
unsigned n = m_exps.size();
bool inExpression = cg.inExpression();
if (!inExpression && (state & FixOrder)) {
return true;
}
cg.setInExpression(false);
bool ret = false;
if (m_arrayElements) {
/*
* would like to do:
* ret = Expression::preOutputCPP(cg, ar, state);
* but icc has problems with the generated code.
*/
ret = hasEffect();
} else if (n > 1 && m_kind == ListKindLeft) {
ret = true;
} else {
for (unsigned int i = 0; i < n; i++) {
if (m_exps[i]->preOutputCPP(cg, ar, 0)) {
ret = true;
break;
}
}
if (!ret) {
ExpressionPtr e = m_exps[n - 1];
if (hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) &&
!(e->hasContext(LValue) &&
!e->hasAnyContext(RefValue|InvokeArgument))) {
ret = true;
} else if (hasContext(RefValue) &&
!e->hasAllContext(LValue|ReturnContext) &&
!e->hasContext(RefValue)) {
ret = true;
}
}
}
if (!inExpression) return ret;
cg.setInExpression(true);
if (!ret) {
if (state & FixOrder) {
preOutputStash(cg, ar, state);
return true;
}
return false;
}
cg.wrapExpressionBegin();
if (m_arrayElements) {
setCPPTemp(genCPPTemp(cg, ar));
outputCPPInternal(cg, ar, true, true);
} else {
unsigned ix = isUnused() ? (unsigned)-1 :
m_kind == ListKindLeft ? 0 : n - 1;
for (unsigned int i = 0; i < n; i++) {
ExpressionPtr e = m_exps[i];
if (i != ix) e->setUnused(true);
e->preOutputCPP(cg, ar, i == ix ? state : 0);
if (i != ix) {
if (e->outputCPPUnneeded(cg, ar)) {
cg_printf(";\n");
}
e->setCPPTemp("/**/");
continue;
}
/*
We inlined a by-value function into the rhs of a by-ref assignment.
*/
bool noRef = hasContext(RefValue) &&
!e->hasAllContext(LValue|ReturnContext) &&
!e->hasContext(RefValue) &&
!e->isTemporary() &&
Type::IsMappedToVariant(e->getActualType());
/*
If we need a non-const reference, but the expression is
going to generate a const reference, fix it
*/
bool lvSwitch =
hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) &&
!(e->hasContext(LValue) &&
!e->hasAnyContext(RefValue|InvokeArgument));
if (e->hasAllContext(LValue|ReturnContext) && i + 1 == n) {
e->clearContext(ReturnContext);
}
if (noRef || lvSwitch || (!i && n > 1)) {
e->Expression::preOutputStash(cg, ar, state | FixOrder | StashAll);
if (!(state & FixOrder)) {
cg_printf("id(%s);\n", e->cppTemp().c_str());
}
}
if (e->hasCPPTemp() &&
Type::SameType(e->getGenType(), getGenType())) {
string t = e->cppTemp();
if (noRef) {
cg_printf("CVarRef %s_nr = wrap_variant(%s);\n",
t.c_str(), t.c_str());
t += "_nr";
}
if (lvSwitch) {
cg_printf("Variant &%s_lv = const_cast<Variant&>(%s);\n",
t.c_str(), t.c_str());
t += "_lv";
}
setCPPTemp(t);
}
}
}
return true;
}
unsigned int ExpressionList::checkLitstrKeys() const {
assert(m_arrayElements && !m_collectionType);
std::set<string> keys;
@@ -652,235 +514,3 @@ unsigned int ExpressionList::checkLitstrKeys() const {
return keys.size();
}
bool ExpressionList::hasNonArrayCreateValue(
bool arrayElements /* = true */, unsigned int start /* = 0 */) const {
for (unsigned int i = start; i < m_exps.size(); i++) {
ExpressionPtr value = m_exps[i];
if (arrayElements) {
ArrayPairExpressionPtr ap =
dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
value = ap->getValue();
}
assert(value);
if (value->hasContext(RefValue)) {
return true;
}
}
return false;
}
void ExpressionList::outputCPPUniqLitKeyArrayInit(
CodeGenerator &cg, AnalysisResultPtr ar, bool litstrKeys, int64 num,
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(%" PRId64 ", ", litstrKeys ? 's' : 'i', num);
always_assert(n - start == num);
for (unsigned int i = start; i < n; i++) {
ExpressionPtr exp = m_exps[i];
always_assert(exp);
ExpressionPtr name;
ExpressionPtr value = exp;
if (arrayElements) {
ArrayPairExpressionPtr ap =
dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
name = ap->getName();
value = ap->getValue();
}
if (name) {
always_assert(litstrKeys);
cg_printf("toSPOD(");
name->outputCPP(cg, ar);
cg_printf("), ");
}
cg_printf("toVPOD(");
if (value->isScalar()) {
always_assert(!cg.hasScalarVariant());
cg.setScalarVariant();
if (!Option::UseScalarVariant) cg_printf("VarNR(");
value->outputCPP(cg, ar);
if (!Option::UseScalarVariant) cg_printf(")");
cg.clearScalarVariant();
} else {
bool wrap = Expression::CheckVarNR(value, Type::Variant);
if (wrap) cg_printf("VarNR(");
value->outputCPP(cg, ar);
if (wrap) cg_printf(")");
}
cg_printf(")");
if (i < n-1) {
cg_printf(", ");
} else {
cg_printf(")");
}
}
}
bool ExpressionList::outputCPPArrayCreate(CodeGenerator &cg,
AnalysisResultPtr ar,
bool isVector,
bool pre) {
assert(pre == !m_cppTemp.empty());
if (!Option::GenArrayCreate || cg.getOutput() == CodeGenerator::SystemCPP) {
return false;
}
if (hasNonArrayCreateValue()) return false;
unsigned int n = isVector ? m_exps.size() : 0;
bool uniqLitstrKeys = false;
if (isVector) {
n = m_exps.size();
} else {
n = checkLitstrKeys();
if (n > 0 && n == m_exps.size()) uniqLitstrKeys = true;
}
if (isVector) {
if (ar->m_arrayIntegerKeyMaxSize < (int)n) ar->m_arrayIntegerKeyMaxSize = n;
} else if (uniqLitstrKeys) {
if (ar->m_arrayLitstrKeyMaxSize < (int)n) ar->m_arrayLitstrKeyMaxSize = n;
} else {
return false;
}
if (pre) {
Expression::preOutputCPP(cg, ar, StashKidVars);
cg_printf("ArrayInit %s(", m_cppTemp.c_str());
outputCPPUniqLitKeyArrayInit(cg, ar, uniqLitstrKeys, n);
cg_printf(");\n");
} else {
outputCPPUniqLitKeyArrayInit(cg, ar, uniqLitstrKeys, n);
}
return true;
}
bool ExpressionList::outputCPPInternal(CodeGenerator &cg,
AnalysisResultPtr ar,
bool needed, bool pre) {
bool needsComma = false;
bool anyOutput = false;
if (m_arrayElements) {
if (!m_collectionType) {
bool isVector = true;
for (unsigned int i = 0; i < m_exps.size(); i++) {
ArrayPairExpressionPtr ap =
dynamic_pointer_cast<ArrayPairExpression>(m_exps[i]);
if (ap->getName()) {
isVector = false;
break;
}
}
if (outputCPPArrayCreate(cg, ar, isVector, pre)) return true;
cg_printf("ArrayInit");
if (pre) {
cg_printf(" %s", m_cppTemp.c_str());
}
cg_printf("(%d)", (int)m_exps.size());
if (pre) cg_printf(";\n");
needsComma = true;
anyOutput = true;
} else {
cg_printf("CollectionInit");
if (pre) {
cg_printf(" %s", m_cppTemp.c_str());
}
cg_printf("(%d, %luLL)", m_collectionType, m_exps.size());
if (pre) cg_printf(";\n");
needsComma = true;
anyOutput = true;
}
}
bool trailingComma = false;
unsigned i = 0, s = m_exps.size();
unsigned ix = m_kind == ListKindLeft ? 0 : s - 1;
bool uniqueStringKeys =
m_arrayElements && !m_collectionType &&
(checkLitstrKeys() == s); // TODO integer keys as well
for ( ; i < s; i++) {
if (ExpressionPtr exp = m_exps[i]) {
if (pre) {
exp->preOutputCPP(cg, ar, 0);
cg_printf("%s", m_cppTemp.c_str());
}
if (needsComma) {
cg_printf(m_arrayElements ? "." : ", ");
trailingComma = true;
}
if (m_arrayElements) {
ArrayPairExpressionPtr ap =
dynamic_pointer_cast<ArrayPairExpression>(exp);
if (ap->isRef()) {
cg_printf("setRef(");
// The value itself shouldn't be wrapped with ref() any more.
ap->getValue()->setContext(NoRefWrapper);
} else {
cg_printf(uniqueStringKeys ? "add(" : "set(");
}
exp->outputCPP(cg, ar);
cg_printf(")");
if (pre) {
cg_printf(";\n");
}
needsComma = true;
} else if (m_kind != ListKindParam && (i != ix || !needed)) {
needsComma = exp->outputCPPUnneeded(cg, ar);
} else {
bool wrap =
exp->hasCPPTemp() &&
hasContext(LValue) && !hasAnyContext(RefValue|InvokeArgument) &&
!(exp->hasContext(LValue) &&
!exp->hasAnyContext(RefValue|InvokeArgument));
if (wrap) cg_printf("const_cast<Variant&>(");
bool noRef = !exp->hasCPPTemp() &&
hasContext(RefValue) &&
!exp->hasAllContext(LValue|ReturnContext) &&
!exp->hasContext(RefValue) &&
!exp->isTemporary() &&
Type::IsMappedToVariant(exp->getActualType());
if (noRef) cg_printf("wrap_variant(");
exp->outputCPP(cg, ar);
if (noRef) cg_printf(")");
if (wrap) cg_printf(")");
needsComma = true;
}
if (needsComma) {
trailingComma = false;
anyOutput = true;
}
}
}
if (trailingComma) {
cg_printf("id(0)");
}
if (m_arrayElements && !pre) {
cg_printf(".create()");
anyOutput = true;
}
return anyOutput;
}
void ExpressionList::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
bool wrapped = m_kind == ListKindWrapped ||
(m_kind == ListKindComma && getCount() > 1);
if (wrapped) cg_printf("(");
outputCPPInternal(cg, ar, true, false);
if (wrapped) cg_printf(")");
}
bool ExpressionList::outputCPPUnneeded(CodeGenerator &cg,
AnalysisResultPtr ar) {
bool inExpression = cg.inExpression();
bool wrapped = false;
if (!inExpression) {
cg.setInExpression(true);
wrapped = preOutputCPP(cg, ar, 0);
}
bool ret = outputCPPInternal(cg, ar, false, false);
if (!inExpression) {
if (wrapped) cg_printf(";\n");
cg.wrapExpressionEnd();
cg.setInExpression(inExpression);
}
return ret || wrapped;
}
-17
Ver Arquivo
@@ -85,19 +85,6 @@ public:
virtual bool canonCompare(ExpressionPtr e) const;
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar);
bool hasNonArrayCreateValue(bool arrayElements = true,
unsigned int start = 0) const;
void outputCPPUniqLitKeyArrayInit(CodeGenerator &cg,
AnalysisResultPtr ar,
bool litstrKeys,
int64 max,
bool arrayElements = true,
unsigned int start = 0);
/**
* Checks whether the expression list contains only literal strings and
* (recursive) arrays of literal strings. Also returns the list of strings
@@ -108,10 +95,6 @@ public:
private:
void optimize(AnalysisResultConstPtr ar);
unsigned int checkLitstrKeys() const;
bool outputCPPArrayCreate(CodeGenerator &cg, AnalysisResultPtr ar,
bool isVector, bool pre);
bool outputCPPInternal(CodeGenerator &cg,
AnalysisResultPtr ar, bool needed, bool pre);
ExpressionPtrVec m_exps;
int m_outputCount;
-180
Ver Arquivo
@@ -584,183 +584,3 @@ TypePtr FunctionCall::checkParamsAndReturn(AnalysisResultPtr ar,
return type;
}
bool FunctionCall::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
optimizeArgArray(ar);
bool noLSB = m_noStatic || (!m_class && m_className.empty()) ||
isSelf() || isParent();
if (!noLSB) {
if (m_funcScope && !m_funcScope->usesLSB()) {
noLSB = true;
}
}
if (noLSB || isUnused()) {
return Expression::preOutputCPP(cg, ar, state);
}
if (!cg.inExpression()) {
return true;
}
Expression::preOutputCPP(cg, ar, state & ~FixOrder);
cg.wrapExpressionBegin();
if (m_classScope) {
string className = m_classScope->getId();
cg_printf("fi.setStaticClassName(%s%s::s_class_name);\n",
Option::ClassPrefix, className.c_str());
} else {
m_clsNameTemp = cg.createNewLocalId(shared_from_this());
cg_printf("CStrRef clsName%d(", m_clsNameTemp);
cg_printString(m_origClassName, ar, shared_from_this());
cg_printf(");\n");
cg_printf("fi.setStaticClassName(clsName%d);\n", m_clsNameTemp);
}
m_noStatic = true;
preOutputStash(cg, ar, FixOrder);
m_noStatic = false;
cg_printf("fi.resetStaticClassName();\n");
if (!(state & FixOrder)) {
cg_printf("id(%s);\n", cppTemp().c_str());
}
return true;
}
void FunctionCall::outputDynamicCall(CodeGenerator &cg,
AnalysisResultPtr ar, bool method) {
const char *kind = method ? "Meth" : "Func";
const char *var = method ? "mcp" : "vt";
int pcount = m_params ? m_params->getCount() : 0;
if (canInvokeFewArgs()) {
if (Option::InvokeWithSpecificArgs) {
cg_printf("get%s%dArgs())(%s%d, ", kind, pcount, var, m_ciTemp);
} else {
cg_printf("get%sFewArgs())(%s%d, ", kind, var, m_ciTemp);
}
if (pcount) {
for (int i = 0; i < pcount; i++) {
(*m_params)[i]->setContext(NoRefWrapper);
}
cg_printf("%d, ", pcount);
cg.pushCallInfo(m_ciTemp);
FunctionScope::OutputCPPArguments(m_params, FunctionScopePtr(),
cg, ar, 0, false);
cg.popCallInfo();
} else {
cg_printf("0");
}
if (!Option::InvokeWithSpecificArgs) {
for (int i = pcount; i < Option::InvokeFewArgsCount; i++) {
cg_printf(", null_variant");
}
}
} else {
cg_printf("get%s())(%s%d, ", kind, var, m_ciTemp);
if (pcount) {
cg.pushCallInfo(m_ciTemp);
FunctionScope::OutputCPPArguments(m_params, FunctionScopePtr(),
cg, ar, -1, false);
cg.popCallInfo();
} else {
cg_printf("Array()");
}
}
cg_printf(")");
}
void FunctionCall::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) {
optimizeArgArray(ar);
bool staticClassName = false;
bool noLSB = !m_cppTemp.empty() || m_noStatic ||
(!m_class && m_className.empty()) ||
isSelf() || isParent() || isStatic();
if (!noLSB) {
if (m_funcScope && !m_funcScope->usesLSB()) {
noLSB = true;
}
}
if (!noLSB) {
if (!m_className.empty()) {
cg_printf("STATIC_CLASS_NAME_CALL(");
if (m_classScope) {
string className = m_classScope->getId();
cg_printf("%s%s::s_class_name, ",
Option::ClassPrefix, className.c_str());
} else {
assert(m_clsNameTemp >= 0);
cg_printf("clsName%d, ", m_clsNameTemp);
}
} else {
cg_printf("STATIC_CLASS_INVOKE_CALL(mcp%d.getClassName(), ",
m_ciTemp);
}
if (m_voidReturn) m_voidWrapper = true;
staticClassName = true;
}
if (m_voidReturn) clearContext(RefValue);
TypePtr eType = getExpectedType();
bool wrap = m_voidWrapper && m_cppTemp.empty() && !isUnused();
if (wrap) {
cg_printf("(");
setExpectedType(TypePtr());
}
Expression::outputCPP(cg, ar);
if (wrap) {
setExpectedType(eType);
if (eType && !Type::IsMappedToVariant(eType)) {
if (eType->is(Type::KindOfBoolean)) {
cg_printf(", false)");
} else if (eType->isInteger()) {
cg_printf(", 0)");
} else if (eType->is(Type::KindOfDouble)) {
cg_printf(", 0.0)");
} else if (eType->is(Type::KindOfString)) {
cg_printf(", empty_string)");
} else {
cg_printf(", ");
eType->outputCPPCast(cg, ar, getScope());
cg_printf("(null))");
}
} else {
cg_printf(", null)");
}
}
if (staticClassName) {
cg_printf(")");
}
}
void FunctionCall::optimizeArgArray(AnalysisResultPtr ar) {
if (m_extraArg <= 0 || m_argArrayId >= 0) return;
int paramCount = m_params->getOutputCount();
int iMax = paramCount - m_extraArg;
bool isScalar = true;
for (int i = iMax; i < paramCount; i++) {
ExpressionPtr param = (*m_params)[i];
if (!param->isScalar()) {
isScalar = false;
break;
}
}
if (isScalar) {
ExpressionPtr argArrayPairs =
ExpressionListPtr(new ExpressionList(getScope(), getLocation()));
for (int i = iMax; i < paramCount; i++) {
ExpressionPtr param = (*m_params)[i];
argArrayPairs->addElement(
ArrayPairExpressionPtr(new ArrayPairExpression(
getScope(), param->getLocation(),
ExpressionPtr(), param, false)));
}
string text;
m_argArrayId =
ar->registerScalarArray(false, getFileScope(), argArrayPairs,
m_argArrayHash, m_argArrayIndex, text);
}
}
-6
Ver Arquivo
@@ -35,8 +35,6 @@ protected:
public:
void analyzeProgram(AnalysisResultPtr ar);
// overriding Expression::outputCPP to implement void wrapper
virtual void outputCPP(CodeGenerator &cg, AnalysisResultPtr ar);
virtual bool isRefable(bool checkError = false) const { return true;}
virtual bool isTemporary() const;
@@ -52,8 +50,6 @@ public:
ExpressionPtr getNameExp() const { return m_nameExp; }
const ExpressionListPtr& getParams() const { return m_params; }
void setNoInline() { m_noInline = true; }
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
void deepCopy(FunctionCallPtr exp);
FunctionScopeRawPtr getFuncScope() const { return m_funcScope; }
@@ -62,8 +58,6 @@ public:
bool isValid() const { return m_valid; }
protected:
void outputDynamicCall(CodeGenerator &cg,
AnalysisResultPtr ar, bool method);
ExpressionPtr m_nameExp;
std::string m_name;
std::string m_origName;
+1 -51
Ver Arquivo
@@ -286,7 +286,7 @@ ExpressionPtr IncludeExpression::postOptimize(AnalysisResultConstPtr ar) {
return replaceValue(rep->clone());
}
}
if (!hhvm || !Option::OutputHHBC) {
if (!Option::OutputHHBC) {
m_exp.reset();
}
} else {
@@ -307,53 +307,3 @@ TypePtr IncludeExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
void IncludeExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
UnaryOpExpression::outputPHP(cg, ar);
}
void IncludeExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
// Includes aren't really supported in system mode
if (cg.getOutput() == CodeGenerator::SystemCPP) {
cg_printf("true");
return;
}
const char *vars = m_privateScope ?
"lvar_ptr(LVariableTable())" : "variables";
bool require = (m_op == T_REQUIRE || m_op == T_REQUIRE_ONCE);
bool once = (m_op == T_INCLUDE_ONCE || m_op == T_REQUIRE_ONCE);
if (!m_include.empty()) {
FileScopePtr fs = ar->findFileScope(m_include);
if (fs) {
if (!fs->canUseDummyPseudoMain(ar)) {
if (!fs->needPseudoMainVariables()) {
vars = "NULL";
}
cg_printf("%s%s(%s, %s, %s)", Option::PseudoMainPrefix,
fs->pseudoMainName().c_str(),
once ? "true" : "false",
vars, cg.getGlobals(ar));
} else {
cg_printf("true");
}
return;
}
}
// include() and require() need containing file's directory
string currentDir = "\"\"";
if (m_loc && m_loc->file && *m_loc->file) {
string file = m_loc->file;
size_t pos = file.rfind('/');
if (pos != string::npos) {
currentDir = '"';
currentDir += file.substr(0, pos + 1);
currentDir += '"';
}
}
// fallback to dynamic include
cg_printf("%s(", require ? "require" : "include");
m_exp->outputCPP(cg, ar);
cg_printf(", %s, %s, %s)",
once ? "true" : "false",
vars,
currentDir.c_str());
}
-151
Ver Arquivo
@@ -263,154 +263,3 @@ void ListAssignment::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf(")");
}
}
static string getArrRef(const string &arrTmp, int index) {
if (arrTmp == "null_variant") return arrTmp;
return arrTmp + "[" + lexical_cast<string>(index) + "]";
}
bool ListAssignment::outputCPPAssignment(CodeGenerator &cg,
AnalysisResultPtr ar,
const string &arrTmp, bool subRef) {
if (!m_variables) return false;
bool ret = false;
for (int i = m_variables->getCount() - 1; i >= 0; --i) {
ExpressionPtr exp = (*m_variables)[i];
if (exp) {
if (exp->is(Expression::KindOfListAssignment)) {
ListAssignmentPtr sublist = dynamic_pointer_cast<ListAssignment>(exp);
string subTmp;
if (arrTmp == "null_variant") {
subTmp = arrTmp;
} else {
subTmp = genCPPTemp(cg, ar);
cg_printf("Variant %s((%s(%s[%d])));\n",
subTmp.c_str(), subRef ? "strongBind" : "",
arrTmp.c_str(), i);
}
if (sublist->outputCPPAssignment(cg, ar, subTmp, subRef)) ret = true;
} else {
ret = true;
bool done = false;
if (exp->is(Expression::KindOfArrayElementExpression)) {
ArrayElementExpressionPtr arrExp =
dynamic_pointer_cast<ArrayElementExpression>(exp);
if (!arrExp->isSuperGlobal() && !arrExp->isDynamicGlobal()) {
arrExp->getVariable()->outputCPP(cg, ar);
if (arrExp->getOffset()) {
cg_printf(".set(");
arrExp->getOffset()->outputCPP(cg, ar);
cg_printf(", ");
} else {
cg_printf(".append(");
}
cg_printf("%s);\n", getArrRef(arrTmp, i).c_str());
done = true;
}
} else if (exp->is(Expression::KindOfObjectPropertyExpression)) {
ObjectPropertyExpressionPtr var(
dynamic_pointer_cast<ObjectPropertyExpression>(exp));
if (!var->isValid()) {
var->outputCPPObject(cg, ar);
cg_printf("o_set(");
var->outputCPPProperty(cg, ar);
cg_printf(", %s, %s);\n",
getArrRef(arrTmp, i).c_str(),
getClassScope() ? "s_class_name" : "empty_string");
done = true;
}
}
if (!done) {
exp->outputCPP(cg, ar);
cg_printf(" = %s;\n", getArrRef(arrTmp, i).c_str());
}
}
}
}
return ret;
}
void ListAssignment::preOutputVariables(CodeGenerator &cg,
AnalysisResultPtr ar,
int state) {
for (int i = 0, c = m_variables->getCount(); i < c; ) {
if (ExpressionPtr exp = (*m_variables)[i++]) {
if (i == c) {
state = 0;
}
if (exp->is(Expression::KindOfListAssignment)) {
static_pointer_cast<ListAssignment>(exp)->
preOutputVariables(cg, ar, state);
} else {
exp->preOutputCPP(cg, ar, state);
}
}
}
}
bool ListAssignment::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
assert(m_array);
if (!cg.inExpression()) return true;
if (m_variables) {
preOutputVariables(cg, ar, m_variables->hasEffect() ||
m_array->hasEffect() ? FixOrder : 0);
}
m_array->preOutputCPP(cg, ar, 0);
bool isArray = false, notArray = false;
bool simpleVar = m_array->is(KindOfSimpleVariable) &&
!static_pointer_cast<SimpleVariable>(m_array)->getAlwaysStash();
bool needsUse = false;
if (TypePtr type = m_array->getActualType()) {
isArray = type->is(Type::KindOfArray);
notArray = !isArray &&
(type->isPrimitive() ||
m_rhsKind == Null ||
(m_rhsKind == Checked && (type->is(Type::KindOfString) ||
type->is(Type::KindOfObject))));
}
cg.wrapExpressionBegin();
if (outputLineMap(cg, ar)) cg_printf("0);\n");
if (notArray && isUnused()) {
if (m_array->outputCPPUnneeded(cg, ar)) cg_printf(";\n");
m_cppTemp = "null";
} else {
m_cppTemp = genCPPTemp(cg, ar);
needsUse = simpleVar || m_array->isTemporary();
const char *decl;
if (isArray && m_array->getCPPType()->is(Type::KindOfArray)) {
decl = needsUse ? "CArrRef" : "Array";
} else {
decl = needsUse ? "CVarRef" : "Variant";
}
cg_printf("%s %s((", decl, m_cppTemp.c_str());
m_array->outputCPP(cg, ar);
cg_printf("));\n");
}
std::string tmp;
if (notArray) {
tmp = "null_variant";
if (needsUse) cg_printf("id(%s);\n", m_cppTemp.c_str());
needsUse = false;
} else if (m_rhsKind != Checked || isArray) {
tmp = m_cppTemp;
} else {
tmp = genCPPTemp(cg, ar);
cg_printf("CVarRef %s(f_is_array(%s)?%s:null_variant);\n",
tmp.c_str(), m_cppTemp.c_str(), m_cppTemp.c_str());
needsUse = true;
}
if (!outputCPPAssignment(cg, ar, tmp, simpleVar) && needsUse) {
cg_printf("id(%s);\n", tmp.c_str());
}
return true;
}
void ListAssignment::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
not_reached();
}
-5
Ver Arquivo
@@ -49,11 +49,6 @@ private:
RHSKind m_rhsKind;
void setLValue();
bool outputCPPAssignment(CodeGenerator &cg, AnalysisResultPtr ar,
const std::string &arrTmp, bool subRef);
void preOutputVariables(CodeGenerator &cg, AnalysisResultPtr ar, int state);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
};
///////////////////////////////////////////////////////////////////////////////
@@ -134,20 +134,3 @@ void ModifierExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
}
}
void ModifierExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
/**
* Not sure if we can bar access coding errors...
if (isPublic()) {
cg_printf("public: ");
} else if (isProtected()) {
cg_printf("protected: ");
} else {
cg_printf("private: ");
}
*/
cg_printf("public: ");
if (isStatic()) cg_printf("static ");
}
@@ -157,231 +157,9 @@ TypePtr NewObjectExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
// code generation functions
void NewObjectExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
outputLineMap(cg, ar);
cg_printf("new ");
m_nameExp->outputPHP(cg, ar);
cg_printf("(");
if (m_params) m_params->outputPHP(cg, ar);
cg_printf(")");
}
void NewObjectExpression::preOutputStash(CodeGenerator &cg,
AnalysisResultPtr ar, int state) {
if (hasCPPTemp()) return;
if (!m_receiverTemp.empty()) {
TypePtr e = getExpectedType();
if (!e || !Type::IsCastNeeded(ar, getActualType(), e)) {
bool unused = isUnused();
setUnused(true);
outputCPPImpl(cg, ar);
setUnused(unused);
setCPPTemp(m_receiverTemp);
cg_printf(";\n");
return;
}
}
optimizeArgArray(ar);
FunctionCall::preOutputStash(cg, ar, state);
}
void NewObjectExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
string &cname = isSelf() || isParent() ? m_name : m_origName;
bool outsideClass = !isPresent();
if (m_classScope &&
(m_classScope->isAbstract() ||
m_classScope->isTrait() ||
m_classScope->isInterface())) {
cg_printf("throw_fatal(\"Cannot instantiate %s %s\").toObject()",
m_classScope->isTrait() ? "trait" :
m_classScope->isInterface() ? "interface" : "abstract class",
CodeGenerator::EscapeLabel(
m_classScope->getOriginalName()).c_str());
return;
}
if (!m_name.empty() && m_classScope && !m_dynamic) {
ClassScopePtr cls = m_classScope;
const string& lClassName = cls->getId();
bool skipCreate = cls->canSkipCreateMethod(ar);
if (skipCreate && m_params && m_params->getCount()) {
cg_printf("(");
for (int i = 0; i < m_params->getCount(); i++) {
ExpressionPtr e = (*m_params)[i];
if (!e->isScalar() && !e->hasCPPTemp()) {
cg_printf("id(");
e->outputCPP(cg, ar);
cg_printf("), ");
}
}
}
if (m_receiverTemp.empty()) {
if (outsideClass) {
cls->outputVolatileCheckBegin(cg, ar, getScope(), cname);
}
cg_printf("%s%s(((%s%s*)%s%s())",
Option::SmartPtrPrefix, lClassName.c_str(),
Option::ClassPrefix, lClassName.c_str(),
Option::CreateObjectOnlyPrefix, lClassName.c_str());
} else {
cg_printf("((%s%s*)%s.get()",
Option::ClassPrefix, lClassName.c_str(),
m_receiverTemp.c_str());
}
if (skipCreate) {
assert(!m_params || m_params->getOutputCount() == 0);
} else {
cg_printf("->create(");
FunctionScope::OutputCPPArguments(m_params, m_funcScope, cg, ar,
m_extraArg, m_variableArgument,
m_argArrayId, m_argArrayHash,
m_argArrayIndex);
cg_printf(")");
}
if (cls->needsEnableDestructor(ar)) {
cg_printf("->clearNoDestruct()");
}
if (m_receiverTemp.empty()) {
cg_printf(")");
if (outsideClass) {
cls->outputVolatileCheckEnd(cg);
}
} else {
if (!isUnused()) {
cg_printf(", %s", m_receiverTemp.c_str());
}
cg_printf(")");
}
if (skipCreate && m_params && m_params->getCount()) {
cg_printf(")");
}
} else {
bool wrap = false;
wrap = m_actualType && m_actualType->is(Type::KindOfVariant) &&
!m_expectedType && !m_implementedType;
if (wrap) {
cg_printf("((Variant)");
}
cg_printf("id(obj%d)", m_objectTemp);
if (wrap) {
cg_printf(")");
}
}
}
bool NewObjectExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (m_classScope &&
(m_classScope->isAbstract() ||
m_classScope->isInterface() ||
m_classScope->isTrait())) {
return false;
}
string &cname = isSelf() || isParent() ? m_name : m_origName;
if (m_name.empty() || !m_classScope || m_dynamic) {
// Short circuit out if inExpression() returns false
if (!cg.inExpression()) return true;
if (m_nameExp) m_nameExp->preOutputCPP(cg, ar, 0);
cg.wrapExpressionBegin();
m_ciTemp = cg.createNewLocalId(shared_from_this());
m_objectTemp = cg.createNewLocalId(shared_from_this());
cg_printf("Object obj%d(", m_objectTemp);
if (isRedeclared()) {
bool outsideClass = !isPresent();
if (outsideClass) {
ClassScope::OutputVolatileCheckBegin(cg, ar, getScope(), cname);
}
cg_printf("g->%s%s->createOnly()", Option::ClassStaticsCallbackPrefix,
m_name.c_str());
if (outsideClass) {
ClassScope::OutputVolatileCheckEnd(cg);
}
} else {
cg_printf("create_object_only(");
if (isStatic()) {
cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())");
} else if (!cname.empty()) {
cg_printString(cname, ar, getScope(), true);
} else if (m_nameExp->is(Expression::KindOfSimpleVariable)) {
m_nameExp->outputCPP(cg, ar);
} else {
cg_printf("(");
m_nameExp->outputCPP(cg, ar);
cg_printf(")");
}
cg_printf(")");
}
cg_printf(");\n");
cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
cg_printf("mcp%d.construct(obj%d);\n", m_ciTemp, m_objectTemp);
cg_printf("const CallInfo *cit%d = mcp%d.ci;\n", m_ciTemp, m_ciTemp);
int pcount = m_params ? m_params->getCount() : 0;
if (pcount > 0) {
cg.pushCallInfo(m_ciTemp);
m_params->preOutputCPP(cg, ar, 0);
cg.popCallInfo();
}
cg_printf("(cit%d->", m_ciTemp);
outputDynamicCall(cg, ar, true);
cg_printf(";\n");
if (!m_classScope ||
m_classScope->derivesFromRedeclaring() ||
m_classScope->hasAttribute(ClassScope::HasDestructor, ar)) {
cg_printf("obj%d.get()->clearNoDestruct();\n", m_objectTemp);
}
if (state & FixOrder) {
cg.pushCallInfo(m_ciTemp);
preOutputStash(cg, ar, state);
cg.popCallInfo();
}
return true;
} else {
bool tempRcvr = true;
bool paramEffect = false;
if (m_params && m_params->getCount() > 0) {
for (int i = m_params->getCount(); i--; ) {
if (!(*m_params)[i]->isScalar()) {
paramEffect = true;
break;
}
}
}
if (!paramEffect) {
tempRcvr = false;
}
if (tempRcvr && cg.inExpression()) {
bool outsideClass = !isPresent();
cg.wrapExpressionBegin();
m_receiverTemp = genCPPTemp(cg, ar);
cg_printf("%s%s %s = ",
Option::SmartPtrPrefix, m_classScope->getId().c_str(),
m_receiverTemp.c_str());
if (outsideClass) {
m_classScope->outputVolatileCheckBegin(cg, ar, getScope(), cname);
}
cg_printf("%s%s()",
Option::CreateObjectOnlyPrefix,
m_classScope->getId().c_str());
if (outsideClass) {
m_classScope->outputVolatileCheckEnd(cg);
}
cg_printf(";\n");
}
return FunctionCall::preOutputCPP(cg, ar, state) || tempRcvr || isUnused();
}
}
@@ -31,9 +31,7 @@ public:
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
virtual bool isRefable(bool checkError = false) const { return checkError; }
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar, int state);
bool isTemporary() const { return true; }
private:
bool m_dynamic;
@@ -73,7 +73,7 @@ void ObjectMethodExpression::analyzeProgram(AnalysisResultPtr ar) {
if (func &&
!cls->isInterface() &&
!(func->isVirtual() &&
(ar->isSystem() || func->isAbstract() ||
(func->isAbstract() ||
(func->hasOverride() &&
cls->getAttribute(ClassScope::NotFinal))) &&
!func->isPerfectVirtual())) {
@@ -156,7 +156,7 @@ ExpressionPtr ObjectMethodExpression::preOptimize(AnalysisResultConstPtr ar) {
if (m_classScope && m_funcScope &&
(!m_funcScope->isVirtual() ||
(!ar->isSystem() && !m_funcScope->hasOverride()))) {
(Option::WholeProgram && !m_funcScope->hasOverride()))) {
if (Option::DynamicInvokeFunctions.size()) {
if (Option::DynamicInvokeFunctions.find(
@@ -257,7 +257,7 @@ TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar,
// invoke() will return Variant
if (cls->isInterface() ||
(func->isVirtual() &&
(ar->isSystem() || func->isAbstract() ||
(!Option::WholeProgram || func->isAbstract() ||
(func->hasOverride() && cls->getAttribute(ClassScope::NotFinal))) &&
!func->isPerfectVirtual())) {
valid = false;
@@ -283,8 +283,6 @@ TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar,
void ObjectMethodExpression::outputPHP(CodeGenerator &cg,
AnalysisResultPtr ar) {
outputLineMap(cg, ar);
m_object->outputPHP(cg, ar);
cg_printf("->");
if (m_nameExp->getKindOf() == Expression::KindOfScalarExpression) {
@@ -298,193 +296,3 @@ void ObjectMethodExpression::outputPHP(CodeGenerator &cg,
m_params->outputPHP(cg, ar);
cg_printf(")");
}
void ObjectMethodExpression::outputCPPObject(CodeGenerator &cg,
AnalysisResultPtr ar) {
bool isThis = m_object->isThis();
if (isThis) {
TypePtr thisImplType(m_object->getImplementedType());
TypePtr thisActType (m_object->getActualType());
bool close = false;
bool checkedThis = getFunctionScope()->isStatic();
if (thisImplType) {
assert(thisActType);
assert(!Type::SameType(thisActType, thisImplType));
ClassScopePtr implCls(thisImplType->getClass(ar, getScope()));
if (implCls &&
!implCls->derivesFrom(ar, thisActType->getName(), true, false)) {
// This happens in this case:
// if ($this instanceof Y) {
// ... $this->meth() ...
// }
ClassScopePtr cls(thisActType->getClass(ar, getScope()));
assert(cls && !cls->derivedByDynamic()); // since we don't do type
// assertions for these
if (!cls->derivesFrom(ar, thisImplType->getName(), true, false)) {
assert(cls->derivesFromRedeclaring() &&
implCls->derivedByDynamic());
checkedThis = true;
}
cg_printf("static_cast<%s%s*>(",
Option::ClassPrefix,
cls->getId().c_str());
close = true;
}
}
if (checkedThis) {
if (close) {
cg_printf("GET_THIS_VALID()");
} else {
cg_printf("GET_THIS_ARROW()");
}
} else {
if (close) cg_printf("this");
}
if (close) {
cg_printf(")->");
}
} else {
TypePtr t = m_object->getType();
bool ok = !t || t->is(Type::KindOfObject) || t->is(Type::KindOfVariant);
if (!ok) cg_printf("Variant(");
m_object->outputCPP(cg, ar);
if (!ok) cg_printf(")");
}
}
void ObjectMethodExpression::outputCPPObjectCall(CodeGenerator &cg,
AnalysisResultPtr ar) {
outputCPPObject(cg, ar);
bool isThis = m_object->isThis();
if (!isThis) {
m_object->outputCPPGuardedObjectPtr(cg);
cg_printf("->");
}
if (m_bindClass && m_classScope) {
cg_printf("bindThis(fi.getThreadInfo()), %s%s::",
Option::ClassPrefix, m_classScope->getId().c_str());
}
}
bool ObjectMethodExpression::preOutputCPP(CodeGenerator &cg,
AnalysisResultPtr ar, int state) {
if (!m_name.empty() && m_valid && m_object->getType()->isSpecificObject()) {
if (m_object->hasEffect()) {
if (cg.inExpression()) {
m_object->preOutputCPP(cg, ar, FixOrder);
if (m_params) m_params->preOutputCPP(cg, ar, 0);
if (state & FixOrder) {
preOutputStash(cg, ar, state);
}
}
return true;
}
return FunctionCall::preOutputCPP(cg, ar, state);
}
// Short circuit out if inExpression() returns false
if (!cg.inExpression()) return true;
cg.wrapExpressionBegin();
m_ciTemp = cg.createNewLocalId(shared_from_this());
if (outputLineMap(cg, ar)) cg_printf("0);\n");
bool isThis = m_object->isThis();
if (!isThis) {
int s = 0;
if (m_name.empty() &&
m_nameExp->hasEffect() && !m_object->isScalar()) {
s = FixOrder;
}
m_object->preOutputCPP(cg, ar, s);
}
if (m_name.empty()) {
m_nameExp->preOutputCPP(cg, ar, 0);
}
cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
if (!isThis) {
TypePtr t = m_object->getType();
if (t && t->is(Type::KindOfObject)) {
cg_printf("CObjRef obj%d = ", m_ciTemp);
} else {
cg_printf("CVarRef obj%d = ", m_ciTemp);
}
outputCPPObject(cg, ar);
cg_printf(";\n");
}
if (m_name.empty()) {
cg_printf("CStrRef mth%d = ", m_ciTemp);
m_nameExp->outputCPP(cg, ar);
cg_printf(";\n");
}
cg_printf("mcp%d.methodCall((", m_ciTemp);
if (isThis) {
if (!getClassScope() || getClassScope()->derivedByDynamic() ||
!static_pointer_cast<SimpleVariable>(m_object)->isGuarded()) {
cg_printf("GET_THIS_VALID()");
} else {
cg_printf("this");
}
} else {
cg_printf("obj%d", m_ciTemp);
m_object->outputCPPGuardedObjectPtr(cg);
}
cg_printf("), ");
if (!m_name.empty()) {
strhash_t hash = hash_string_i(m_name.c_str());
cg_printString(m_origName, ar, shared_from_this());
cg_printf(", " STRHASH_FMT ");\n", hash);
} else {
cg_printf("mth%d, -1);\n", m_ciTemp);
}
cg_printf("const CallInfo *cit%d ATTRIBUTE_UNUSED = mcp%d.ci;\n",
m_ciTemp, m_ciTemp);
if (m_params && m_params->getCount() > 0) {
cg.pushCallInfo(m_ciTemp);
m_params->preOutputCPP(cg, ar, 0);
cg.popCallInfo();
}
if (state & FixOrder) {
cg.pushCallInfo(m_ciTemp);
preOutputStash(cg, ar, state);
cg.popCallInfo();
}
return true;
}
void ObjectMethodExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (!m_name.empty() && m_valid && m_object->getType()->isSpecificObject()) {
// Direct method call
ClassScopePtr cls(m_object->getType()->getClass(ar, getScope()));
if (cls) getFileScope()->addUsedClassFullHeader(cls);
if (m_bindClass && m_classScope) cg_printf("(");
outputCPPObjectCall(cg, ar);
cg_printf("%s%s(", m_funcScope ?
m_funcScope->getPrefix(ar, m_params) : Option::MethodPrefix,
m_name.c_str());
FunctionScope::OutputCPPArguments(m_params, m_funcScope, cg, ar,
m_extraArg, m_variableArgument,
m_argArrayId, m_argArrayHash,
m_argArrayIndex);
cg_printf(")");
if (m_bindClass && m_classScope) cg_printf(")");
} else {
bool maybeStatic = true;
if (Option::WholeProgram && !ar->isSystem() && !m_name.empty()) {
FunctionScope::FunctionInfoPtr info =
FunctionScope::GetFunctionInfo(m_name);
if (info && !info->getMaybeStatic()) maybeStatic = false;
}
cg_printf("(mcp%d.%s->",
m_ciTemp, maybeStatic ? "bindClass(fi)" : "ci" );
outputDynamicCall(cg, ar, true);
}
}
@@ -38,9 +38,6 @@ public:
virtual TypePtr inferAndCheck(AnalysisResultPtr ar, TypePtr type,
bool coerce);
virtual bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
ExpressionPtr getObject() const { return m_object; }
private:
ExpressionPtr m_object;
@@ -50,9 +47,6 @@ private:
// for avoiding code generate toObject(Variant)
bool directVariantProxy(AnalysisResultPtr ar);
bool m_bindClass;
void outputCPPObject(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPObjectCall(CodeGenerator &cg, AnalysisResultPtr ar);
};
///////////////////////////////////////////////////////////////////////////////
@@ -357,301 +357,3 @@ void ObjectPropertyExpression::outputPHP(CodeGenerator &cg,
cg_printf("}");
}
}
bool ObjectPropertyExpression::preOutputCPP(CodeGenerator &cg,
AnalysisResultPtr ar, int state) {
return preOutputOffsetLHS(cg, ar, state);
}
void ObjectPropertyExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
outputCPPObjProperty(cg, ar, false);
}
static string nullName(AnalysisResultPtr ar, TypePtr type) {
if (!type || Type::IsMappedToVariant(type)) {
return "null_variant";
}
if (type->is(Type::KindOfArray)) {
return "null_array";
}
if (type->is(Type::KindOfObject)) {
return "null_object";
}
if (type->is(Type::KindOfString)) {
return "null_string";
}
return type->getCPPDecl(ar, BlockScopeRawPtr()) + "()";
}
void ObjectPropertyExpression::outputCPPObjProperty(CodeGenerator &cg,
AnalysisResultPtr ar,
int doExist) {
if (m_valid) {
TypePtr type = m_object->getActualType();
if (type->isSpecificObject()) {
ClassScopePtr cls(type->getClass(ar, getScope()));
if (cls) getFileScope()->addUsedClassFullHeader(cls);
}
}
string func = Option::ObjectPrefix;
const char *error = ", true";
std::string context = "";
bool doUnset = m_context & LValue && m_context & UnsetContext;
bool needTemp = false;
if (cg.getOutput() != CodeGenerator::SystemCPP) {
context = originalClassName(cg, true);
}
if (doUnset) {
func = "o_unset";
error = "";
} else if (doExist) {
func = doExist > 0 ? "o_isset" : "o_empty";
error = "";
} else {
if (m_context & ExistContext) {
error = ", false";
}
if (m_context & InvokeArgument) {
if (cg.callInfoTop() != -1) {
func += "argval";
} else {
func += "get";
}
} else if (m_context & (LValue | RefValue | DeepReference | UnsetContext)) {
if (m_context & UnsetContext) {
always_assert(!(m_context & LValue)); // handled by doUnset
func += "unsetLval";
} else {
func += "lval";
}
error = "";
needTemp = true;
} else {
func += "get";
if (isNonPrivate(ar)) {
func += "Public";
context = "";
}
}
}
if (m_valid && !m_object->isThis() &&
(!m_object->is(KindOfSimpleVariable) ||
!static_pointer_cast<SimpleVariable>(m_object)->isGuarded())) {
cg_printf("(obj_tmp = ");
outputCPPValidObject(cg, ar, false);
bool write_context = hasAnyContext(LValue | RefValue | DeepReference |
UnsetContext | OprLValue |
DeepOprLValue | DeepAssignmentLHS |
AssignmentLHS) && !doUnset;
cg_printf(", LIKELY(obj_tmp != 0) %s ", write_context ? "||" : "?");
always_assert(m_property->is(KindOfScalarExpression));
ScalarExpressionPtr name =
static_pointer_cast<ScalarExpression>(m_property);
if (doExist || doUnset) {
cg_printf(doUnset ? "unset" : doExist > 0 ? "isset" : "empty");
}
ClassScopePtr cls =
ar->findExactClass(shared_from_this(),
m_object->getActualType()->getName());
if (write_context) {
cg_printf("(throw_null_object_prop(),false),");
}
cg_printf("(((%s%s*)obj_tmp)->%s%s)",
Option::ClassPrefix, cls->getId().c_str(),
Option::PropertyPrefix, name->getLiteralString().c_str());
if (!write_context) {
cg_printf(" : (raise_null_object_prop(),%s)",
doUnset ? "null_variant" :
doExist ? doExist > 0 ? "false" : "true" :
nullName(ar, getCPPType()).c_str());
}
cg_printf(")");
return;
}
if (m_valid && (doExist || doUnset)) {
cg_printf(doUnset ? "unset(" : doExist > 0 ? "isset(" : "empty(");
}
bool flag = outputCPPObject(cg, ar, !m_valid && (doUnset || doExist));
if (flag) {
cg_printf("id(");
outputCPPProperty(cg, ar);
cg_printf(")");
if (doExist) cg_printf(", %s", doExist > 0 ? "false" : "true");
cg_printf(")");
} else if (m_valid) {
always_assert(m_object->getActualType() &&
m_object->getActualType()->isSpecificObject());
ScalarExpressionPtr name =
dynamic_pointer_cast<ScalarExpression>(m_property);
cg_printf("%s%s", Option::PropertyPrefix,
name->getLiteralString().c_str());
if (doExist || doUnset) cg_printf(")");
} else {
cg_printf("%s(", func.c_str());
if (hasContext(InvokeArgument) && cg.callInfoTop() != -1) {
cg_printf("cit%d->isRef(%d), ", cg.callInfoTop(), m_argNum);
}
outputCPPProperty(cg, ar);
if (needTemp) {
const string &tmp = cg.getReferenceTemp();
context = ", " + (tmp.empty() ? "Variant()" : tmp) + context;
}
cg_printf("%s%s)", error, context.c_str());
}
}
void ObjectPropertyExpression::outputCPPValidObject(CodeGenerator &cg,
AnalysisResultPtr ar,
bool guarded) {
TypePtr act;
bool close = false;
if (!m_object->hasCPPTemp() && m_object->getImplementedType() &&
!Type::SameType(m_object->getImplementedType(),
m_object->getActualType())) {
act = m_object->getActualType();
m_object->setActualType(m_object->getImplementedType());
if (guarded) {
ClassScopePtr cls = ar->findExactClass(shared_from_this(),
act->getName());
cg_printf("((%s%s*)", Option::ClassPrefix, cls->getId().c_str());
close = true;
}
}
m_object->outputCPP(cg, ar);
if (act) {
if (m_object->getImplementedType()->is(Type::KindOfObject)) {
cg_printf(".get()");
} else {
cg_printf(".getObjectData%s()", guarded ? "" : "OrNull");
}
if (close) cg_printf(")");
m_object->setActualType(act);
} else {
cg_printf(".get()");
}
}
bool ObjectPropertyExpression::outputCPPObject(CodeGenerator &cg,
AnalysisResultPtr ar,
bool noEvalOnError) {
if (m_object->isThis()) {
TypePtr thisImplType(m_object->getImplementedType());
TypePtr thisActType (m_object->getActualType());
bool close = false;
if (m_valid && thisImplType) {
assert(thisActType);
assert(!Type::SameType(thisActType, thisImplType));
ClassScopePtr implCls(thisImplType->getClass(ar, getScope()));
if (implCls &&
!implCls->derivesFrom(ar, thisActType->getName(), true, false)) {
// This happens in this case:
// if ($this instanceof Y) {
// ... $this->prop ...
// }
ClassScopePtr cls(thisActType->getClass(ar, getScope()));
assert(cls && cls->derivesFrom(ar, thisImplType->getName(),
true, false));
cg_printf("static_cast<%s%s*>(",
Option::ClassPrefix,
cls->getId().c_str());
close = true;
}
}
if (m_valid) {
if (!m_object->getOriginalClass()) {
m_valid = false;
} else {
FunctionScopeRawPtr fs = m_object->getOriginalFunction();
if (!fs || fs->isStatic()) {
m_valid = false;
} else if (m_object->getOriginalClass() != getClassScope()) {
if (m_object->getOriginalClass()->isRedeclaring()) {
m_valid = false;
} else {
m_objectClass = getClassScope();
}
}
}
}
if (m_valid) {
if (close) cg_printf("this");
} else {
if (!getClassScope() || getClassScope()->derivedByDynamic() ||
(getFunctionScope() && getFunctionScope()->isStatic()) ||
!static_pointer_cast<SimpleVariable>(m_object)->isGuarded()) {
if (close) {
cg_printf("GET_THIS_VALID()");
} else {
cg_printf("GET_THIS_ARROW()");
}
}
}
if (close) {
cg_printf(")->");
}
} else if (m_valid) {
assert(m_object->is(KindOfSimpleVariable) &&
static_pointer_cast<SimpleVariable>(m_object)->isGuarded());
outputCPPValidObject(cg, ar, true);
cg_printf("->");
} else {
TypePtr t = m_object->getType();
bool ok = t && (t->is(Type::KindOfObject) || t->is(Type::KindOfVariant));
if (noEvalOnError && !ok) {
if (!t || !t->is(Type::KindOfArray)) {
cg_printf("(");
if (m_object->outputCPPUnneeded(cg, ar)) cg_printf(", ");
return true;
}
}
ok = ok || !t;
if (!ok) cg_printf("Variant(");
m_object->outputCPP(cg, ar);
if (!ok) cg_printf(")");
if (ok && m_object->outputCPPGuardedObjectPtr(cg)) {
cg_printf("->");
} else {
cg_printf(".");
}
}
if (m_valid && m_propSym->isPrivate() &&
m_objectClass != getOriginalClass()) {
cg_printf("%s%s::",
Option::ClassPrefix, getOriginalClass()->getId().c_str());
}
return false;
}
void ObjectPropertyExpression::outputCPPProperty(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (m_property->getKindOf() == Expression::KindOfScalarExpression) {
ScalarExpressionPtr name =
dynamic_pointer_cast<ScalarExpression>(m_property);
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,
AnalysisResultPtr ar,
int op) {
outputCPPObjProperty(cg, ar, op == T_ISSET ? 1 : -1);
}
void ObjectPropertyExpression::outputCPPUnset(CodeGenerator &cg,
AnalysisResultPtr ar) {
outputCPPObjProperty(cg, ar, 0);
}
@@ -45,18 +45,9 @@ public:
ExpressionPtr getObject() { return m_object;}
ExpressionPtr getProperty() { return m_property;}
virtual void outputCPPExistTest(CodeGenerator &cg, AnalysisResultPtr ar,
int op);
virtual void outputCPPUnset(CodeGenerator &cg, AnalysisResultPtr ar);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
bool isTemporary() const;
bool isNonPrivate(AnalysisResultPtr ar);
bool isValid() const { return m_valid; }
void outputCPPProperty(CodeGenerator &cg, AnalysisResultPtr ar);
bool outputCPPObject(CodeGenerator &cg, AnalysisResultPtr ar,
bool noEvalOnError = false);
void outputCPPValidObject(CodeGenerator &cg, AnalysisResultPtr ar,
bool guarded);
private:
ExpressionPtr m_object;
ExpressionPtr m_property;
@@ -70,8 +61,6 @@ private:
// for avoiding code generate toObject(Variant)
bool directVariantProxy(AnalysisResultPtr ar);
void outputCPPObjProperty(CodeGenerator &cg, AnalysisResultPtr ar,
int doExist);
};
///////////////////////////////////////////////////////////////////////////////
+1 -100
Ver Arquivo
@@ -34,7 +34,7 @@ ParameterExpression::ParameterExpression
const std::string &type, const std::string &name, bool ref,
ExpressionPtr defaultValue, ExpressionPtr attributeList)
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ParameterExpression)),
m_originalType(type), m_name(name), m_ref(ref), m_hasRTTI(false),
m_originalType(type), m_name(name), m_ref(ref),
m_defaultValue(defaultValue), m_attributeList(attributeList) {
m_type = Util::toLower(type);
if (m_defaultValue) {
@@ -285,102 +285,3 @@ void ParameterExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_defaultValue->outputPHP(cg, ar);
}
}
void ParameterExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
FunctionScopePtr func = getFunctionScope();
VariableTablePtr variables = func->getVariables();
Symbol *sym = variables->getSymbol(m_name);
always_assert(sym && sym->isParameter());
bool inHeader = cg.isFileOrClassHeader();
cg.setFileOrClassHeader(true);
CodeGenerator::Context context = cg.getContext();
bool typedWrapper = (context == CodeGenerator::CppTypedParamsWrapperImpl ||
context == CodeGenerator::CppTypedParamsWrapperDecl);
TypePtr paramType =
typedWrapper && func->getParamTypeSpec(sym->getParameterIndex()) ?
Type::Variant : func->getParamType(sym->getParameterIndex());
bool wrapper = typedWrapper ||
context == CodeGenerator::CppFunctionWrapperImpl ||
context == CodeGenerator::CppFunctionWrapperDecl;
bool isCVarRef = false;
const char *prefix = "";
if (m_ref) {
cg_printf("VRefParam");
if (!wrapper) {
prefix = "r";
}
} else if (wrapper ||
(!variables->isLvalParam(m_name) &&
!variables->getAttribute(VariableTable::ContainsDynamicVariable) &&
!variables->getAttribute(VariableTable::ContainsExtract))) {
if (paramType->is(Type::KindOfVariant) ||
paramType->is(Type::KindOfSome)) {
cg_printf("CVarRef");
isCVarRef = true;
}
else if (paramType->is(Type::KindOfArray)) cg_printf("CArrRef");
else if (paramType->is(Type::KindOfString)) cg_printf("CStrRef");
else paramType->outputCPPDecl(cg, ar, getScope());
} else {
paramType->outputCPPDecl(cg, ar, getScope());
}
cg_printf(" %s%s%s",
prefix, Option::VariablePrefix,
CodeGenerator::FormatLabel(m_name).c_str());
if (m_defaultValue && sym->getParameterIndex() >= func->getMinParamCount()) {
bool comment = context == CodeGenerator::CppTypedParamsWrapperImpl ||
context == CodeGenerator::CppFunctionWrapperImpl ||
context == CodeGenerator::CppImplementation ||
(context == CodeGenerator::CppDeclaration && func->isInlined());
if (comment) {
cg_printf(" // ");
}
cg_printf(" = ");
ConstantExpressionPtr con =
dynamic_pointer_cast<ConstantExpression>(m_defaultValue);
bool done = false;
if (con && con->isNull()) {
done = true;
if (isCVarRef) {
cg_printf("null_variant");
} else if (paramType->is(Type::KindOfVariant) ||
paramType->is(Type::KindOfSome)) {
cg_printf("null");
} else if (paramType->is(Type::KindOfObject)) {
cg_printf("Object()");
} else if (paramType->is(Type::KindOfArray)) {
cg_printf("Array()");
} else if (paramType->is(Type::KindOfString)) {
cg_printf("String()");
} else {
done = false;
}
}
if (!done) {
if (comment) {
cg.setContext(CodeGenerator::CppParameterDefaultValueImpl);
} else {
cg.setContext(CodeGenerator::CppParameterDefaultValueDecl);
}
bool isScalar = m_defaultValue->isScalar();
if (isCVarRef && isScalar) {
assert(!cg.hasScalarVariant());
cg.setScalarVariant();
}
m_defaultValue->outputCPP(cg, ar);
if (isCVarRef && isScalar) cg.clearScalarVariant();
assert(!cg.hasScalarVariant());
cg.setContext(context);
}
if (comment) {
cg_printf("\n");
}
}
cg.setFileOrClassHeader(inHeader);
}
@@ -38,8 +38,6 @@ public:
bool isRef() const { return m_ref;}
bool isOptional() const { return m_defaultValue;}
bool hasRTTI() const { return m_hasRTTI;}
void setHasRTTI() { m_hasRTTI = true;}
const std::string &getName() const { return m_name; }
int getLocalEffects() const { return NoEffect; }
void rename(const std::string &name) { m_name = name;}
@@ -65,7 +63,6 @@ private:
std::string m_originalType;
std::string m_name;
bool m_ref;
bool m_hasRTTI;
ExpressionPtr m_defaultValue;
ExpressionPtr m_attributeList;
};
-148
Ver Arquivo
@@ -176,151 +176,3 @@ void QOpExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
m_expNo->outputPHP(cg, ar);
}
void QOpExpression::wrapBoolean(CodeGenerator &cg,
AnalysisResultPtr ar,
ExpressionPtr exp) {
TypePtr t(exp->getType());
assert(t);
bool wrap = false;
if (!t->is(Type::KindOfBoolean)) {
wrap = true;
cg_printf("toBoolean(");
}
exp->outputCPP(cg, ar);
if (wrap) cg_printf(")");
}
bool QOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (!hasEffect()) {
return Expression::preOutputCPP(cg, ar, state);
}
bool fix_condition = m_condition->preOutputCPP(cg, ar, 0);
if (!cg.inExpression()) {
return fix_condition || (state & FixOrder) ||
(!m_expYes || m_expYes->preOutputCPP(cg, ar, 0)) ||
m_expNo->preOutputCPP(cg, ar, 0);
}
cg.setInExpression(false);
bool fix_yes = (!m_expYes || m_expYes->preOutputCPP(cg, ar, 0));
bool fix_no = m_expNo->preOutputCPP(cg, ar, 0);
cg.setInExpression(true);
if (fix_yes || fix_no) {
cg.wrapExpressionBegin();
if (isUnused()) {
cg_printf("if (");
wrapBoolean(cg, ar, m_condition);
cg_indentBegin(") {\n");
if (m_expYes) {
m_expYes->preOutputCPP(cg, ar, 0);
if (m_expYes->outputCPPUnneeded(cg, ar)) cg_printf(";\n");
}
cg_indentEnd("\n");
cg_indentBegin("} else {\n");
m_expNo->preOutputCPP(cg, ar, 0);
if (m_expNo->outputCPPUnneeded(cg, ar)) cg_printf(";\n");
cg_indentEnd("}\n");
m_cppValue = "null_variant";
} else {
std::string tmp = genCPPTemp(cg, ar);
if (m_expYes) {
TypePtr typeYes = m_expYes->getActualType();
TypePtr typeNo = m_expNo->getActualType();
TypePtr type =
typeYes && typeNo && Type::SameType(typeYes, typeNo) &&
!typeYes->is(Type::KindOfVariant) &&
m_expYes->isLiteralString() == m_expNo->isLiteralString() ?
typeYes : Type::Variant;
type->outputCPPDecl(cg, ar, getScope());
cg_printf(" %s;\n", tmp.c_str());
cg_printf("if (");
wrapBoolean(cg, ar, m_condition);
cg_indentBegin(") {\n");
m_expYes->preOutputCPP(cg, ar, 0);
cg_printf("%s = (", tmp.c_str());
m_expYes->outputCPP(cg, ar);
cg_indentEnd(");\n");
} else {
TypePtr typeYes = m_condition->getActualType();
TypePtr typeNo = m_expNo->getActualType();
TypePtr type =
typeYes && typeNo && Type::SameType(typeYes, typeNo) &&
!typeYes->is(Type::KindOfVariant) &&
m_condition->isLiteralString() == m_expNo->isLiteralString() ?
typeYes : Type::Variant;
type->outputCPPDecl(cg, ar, getScope());
cg_printf(" %s = ", tmp.c_str());
m_condition->outputCPP(cg, ar);
cg_printf(";\n");
cg_printf("if (toBoolean(%s)) {\n", tmp.c_str());
}
cg_indentBegin("} else {\n");
m_expNo->preOutputCPP(cg, ar, 0);
cg_printf("%s = (", tmp.c_str());
m_expNo->outputCPP(cg, ar);
cg_printf(");\n");
cg_indentEnd("}\n");
m_cppValue = tmp;
}
} else if (state & FixOrder) {
preOutputStash(cg, ar, state);
return true;
}
return false;
}
bool QOpExpression::outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar) {
return m_cppValue.empty() && Expression::outputCPPUnneeded(cg, ar);
}
static void outputUnneededExpr(CodeGenerator &cg, AnalysisResultPtr ar,
ExpressionPtr exp) {
cg_printf("(");
if (exp->outputCPPUnneeded(cg, ar)) {
cg_printf(",");
}
cg_printf("false)");
}
void QOpExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
if (!m_cppValue.empty()) {
cg_printf("%s", m_cppValue.c_str());
} else {
ExpressionPtr expYes = m_expYes ? m_expYes : m_condition;
bool wrapped = !isUnused();
if (wrapped) {
cg_printf("(");
}
wrapBoolean(cg, ar, m_condition);
if (isUnused()) {
cg_printf(" ? ");
outputUnneededExpr(cg, ar, expYes);
cg_printf(" : ");
outputUnneededExpr(cg, ar, m_expNo);
} else {
TypePtr typeYes = expYes->getActualType();
TypePtr typeNo = m_expNo->getActualType();
const char *castType =
typeYes && typeNo && Type::SameType(typeYes, typeNo) &&
!typeYes->is(Type::KindOfVariant) &&
expYes->isLiteralString() == m_expNo->isLiteralString()
? "" : "(Variant)";
cg_printf(" ? (%s(", castType);
expYes->outputCPP(cg, ar);
cg_printf(")) : (%s(", castType);
m_expNo->outputCPP(cg, ar);
cg_printf("))");
}
if (wrapped) {
cg_printf(")");
}
}
}
-7
Ver Arquivo
@@ -36,17 +36,10 @@ public:
virtual int getLocalEffects() const { return NoEffect; }
virtual ExpressionPtr unneededHelper();
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool outputCPPUnneeded(CodeGenerator &cg, AnalysisResultPtr ar);
ExpressionPtr getCondition() const { return m_condition; }
ExpressionPtr getYes() const { return m_expYes; }
ExpressionPtr getNo() const { return m_expNo; }
private:
void wrapBoolean(CodeGenerator &cg,
AnalysisResultPtr ar,
ExpressionPtr exp);
ExpressionPtr m_condition;
ExpressionPtr m_expYes;
ExpressionPtr m_expNo;
+6 -221
Ver Arquivo
@@ -164,7 +164,7 @@ void ScalarExpression::analyzeProgram(AnalysisResultPtr ar) {
}
unsigned ScalarExpression::getCanonHash() const {
int64 val = getHash();
int64_t val = getHash();
if (val == -1) {
val = hash_string(m_value.c_str(), m_value.size());
}
@@ -288,7 +288,7 @@ bool ScalarExpression::isLiteralInteger() const {
return false;
}
int64 ScalarExpression::getLiteralInteger() const {
int64_t ScalarExpression::getLiteralInteger() const {
assert(isLiteralInteger());
return strtoll(m_value.c_str(), nullptr, 0);
}
@@ -405,228 +405,13 @@ void ScalarExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
}
std::string ScalarExpression::getCPPLiteralString(bool *binary /* = NULL */) {
string output;
switch (m_type) {
case T_CONSTANT_ENCAPSED_STRING:
case T_ENCAPSED_AND_WHITESPACE:
case T_STRING: {
output = "\"";
output += CodeGenerator::EscapeLabel(m_value, binary);
output += "\"";
break;
}
case T_TRAIT_C:
case T_CLASS_C:
case T_NS_C:
case T_METHOD_C:
case T_FUNC_C:
output = "\"";
output += m_translated;
output += "\"";
break;
default:
assert(false);
}
return output;
}
void ScalarExpression::OutputCPPString(
const string &str, CodeGenerator &cg, AnalysisResultPtr ar,
BlockScopeRawPtr scope, bool constant) {
if (!cg.hasScalarVariant() || !Option::UseScalarVariant) {
cg_printString(str, ar, scope, constant);
return;
}
bool isBinary = false;
string escaped = CodeGenerator::EscapeLabel(str, &isBinary);
string fullName = cg.printNamedString(str, escaped, ar, scope, false);
assert(!fullName.empty());
string prefix(Option::ScalarPrefix);
if (Option::SystemGen) prefix += Option::SysPrefix;
assert(fullName.find(prefix) == 0);
string name =
fullName.substr(prefix.size() + strlen(Option::StaticStringPrefix));
cg.printf("NAMVAR(%s%s%s, \"%s\")",
prefix.c_str(), Option::StaticVarStrPrefix,
name.c_str(), escaped.c_str());
ar->addNamedLiteralVarString(fullName);
}
void ScalarExpression::outputCPPString(CodeGenerator &cg,
AnalysisResultPtr ar) {
switch (m_type) {
case T_CONSTANT_ENCAPSED_STRING:
case T_ENCAPSED_AND_WHITESPACE:
assert(m_quoted); // fall through
case T_STRING: {
if (m_quoted) {
string output = getLiteralString();
bool constant =
(cg.getContext() == CodeGenerator::CppConstantsDecl) ||
(cg.getContext() == CodeGenerator::CppClassConstantsImpl);
OutputCPPString(output, cg, ar, getScope(), constant);
} else {
not_reached();
}
break;
}
case T_TRAIT_C:
case T_CLASS_C:
case T_NS_C:
case T_METHOD_C:
case T_FUNC_C:
OutputCPPString(m_translated, cg, ar, getScope(), false);
break;
case T_NUM_STRING: {
bool constant =
(cg.getContext() == CodeGenerator::CppConstantsDecl) ||
(cg.getContext() == CodeGenerator::CppClassConstantsImpl);
always_assert(!constant);
OutputCPPString(m_value, cg, ar, getScope(), false);
break;
}
default:
assert(false);
}
}
void ScalarExpression::outputCPPNamedInteger(CodeGenerator &cg,
AnalysisResultPtr ar) {
Variant v = getVariant();
assert(v.isInteger());
int index = -1;
int64 val = v.toInt64();
int intId = ar->checkScalarVarInteger(val, index);
always_assert(index != -1);
string name = ar->getScalarVarIntegerName(intId, index);
cg_printf("NAMVAR(%s, int64_t(%" PRId64 "))", name.c_str(), val);
getUsedScalarScope(cg)->addUsedScalarVarInteger(val);
if (cg.isFileOrClassHeader()) {
if (getClassScope()) {
getClassScope()->addUsedScalarVarIntegerHeader(val);
} else {
getFileScope()->addUsedScalarVarIntegerHeader(val);
}
}
}
void ScalarExpression::outputCPPInteger(CodeGenerator &cg,
AnalysisResultPtr ar) {
Variant v = getVariant();
assert(v.isInteger());
if (v.toInt64() == std::numeric_limits<int64_t>::min()) {
cg_printf("int64_t(0x8000000000000000LL)");
} else {
cg_printf("%" PRId64 "L", v.toInt64());
}
}
void ScalarExpression::outputCPPNamedDouble(CodeGenerator &cg,
AnalysisResultPtr ar) {
double dval = getVariant().getDouble();
if (finite(dval)) {
int index = -1;
int dblId = ar->checkScalarVarDouble(dval, index);
always_assert(index != -1);
string name = ar->getScalarVarDoubleName(dblId, index);
cg_printf("NAMVAR(%s, ", name.c_str());
ar->outputCPPFiniteDouble(cg, dval);
cg_printf(")");
getUsedScalarScope(cg)->addUsedScalarVarDouble(dval);
if (cg.isFileOrClassHeader()) {
if (getClassScope()) {
getClassScope()->addUsedScalarVarDoubleHeader(dval);
} else {
getFileScope()->addUsedScalarVarDoubleHeader(dval);
}
}
} else if (std::isnan(dval)) {
cg_printf("NAN_varNR");
} else if (dval > 0) {
cg_printf("INF_varNR");
} else {
cg_printf("NEGINF_varNR");
}
}
void ScalarExpression::outputCPPDouble(CodeGenerator &cg,
AnalysisResultPtr ar) {
double dval = getVariant().getDouble();
if (finite(dval)) {
ar->outputCPPFiniteDouble(cg, dval);
} else if (std::isnan(dval)) {
cg_printf("%sNAN", Option::ConstantPrefix);
} else if (dval > 0) {
cg_printf("%sINF", Option::ConstantPrefix);
} else {
cg_printf("-%sINF", Option::ConstantPrefix);
}
}
void ScalarExpression::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
switch (m_type) {
case T_CONSTANT_ENCAPSED_STRING:
case T_ENCAPSED_AND_WHITESPACE:
case T_STRING:
case T_TRAIT_C:
case T_CLASS_C:
case T_NS_C:
case T_METHOD_C:
case T_FUNC_C: {
outputCPPString(cg, ar);
break;
}
case T_LINE:
ar->addInteger(getVariant().toInt64());
if (cg.hasScalarVariant() && Option::UseScalarVariant) {
outputCPPNamedInteger(cg, ar);
} else {
cg_printf("%s", m_translated.c_str());
}
break;
case T_NUM_STRING: {
always_assert(!cg.hasScalarVariant());
const char *s = m_value.c_str();
if ((*s == '0' && m_value.size() == 1) || ('1' <= *s && *s <= '9')) {
// Offset could be treated as a long
cg_printf("%sL", m_value.c_str());
} else {
// Offset must be treated as a string
outputCPPString(cg, ar);
}
break;
}
case T_LNUMBER:
ar->addInteger(getVariant().toInt64());
if (cg.hasScalarVariant() && Option::UseScalarVariant) {
outputCPPNamedInteger(cg, ar);
} else {
outputCPPInteger(cg, ar);
}
break;
case T_DNUMBER:
if (cg.hasScalarVariant() && Option::UseScalarVariant) {
outputCPPNamedDouble(cg, ar);
} else {
outputCPPDouble(cg, ar);
}
break;
default:
assert(false);
}
}
int64 ScalarExpression::getHash() const {
int64 hash = -1;
int64_t ScalarExpression::getHash() const {
int64_t hash = -1;
if (isLiteralInteger()) {
hash = hash_int64(getLiteralInteger());
} else if (isLiteralString()) {
string scs = getLiteralString();
int64 res;
int64_t res;
if (is_strictly_integer(scs.c_str(), scs.size(), res)) {
hash = hash_int64(res);
} else {
@@ -690,7 +475,7 @@ bool ScalarExpression::getString(const std::string *&s) const {
}
}
bool ScalarExpression::getInt(int64 &i) const {
bool ScalarExpression::getInt(int64_t &i) const {
if (m_type == T_LNUMBER) {
i = strtoll(m_value.c_str(), nullptr, 0);
return true;
+3 -13
Ver Arquivo
@@ -63,26 +63,18 @@ public:
void appendEncapString(const std::string &value);
bool isLiteralInteger() const;
int64 getLiteralInteger() const;
int64_t getLiteralInteger() const;
std::string getIdentifier() const;
Variant getVariant() const;
int64 getHash() const;
int64_t getHash() const;
void setComment(const std::string &comment) { m_comment = comment;}
const std::string getComment() { return m_comment;}
void outputCPPString(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPInteger(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPDouble(CodeGenerator &cg, AnalysisResultPtr ar);
std::string getCPPLiteralString(bool *binary = nullptr);
bool getString(const std::string *&s) const;
bool getInt(int64 &i) const;
bool getInt(int64_t &i) const;
bool getDouble(double &d) const;
static void OutputCPPString(const std::string &str, CodeGenerator &cg,
AnalysisResultPtr ar, BlockScopeRawPtr scope,
bool constant);
private:
int m_type;
std::string m_serializedValue;
@@ -92,8 +84,6 @@ private:
std::string m_translated;
bool m_quoted;
std::string m_comment; // for inlined constant name
void outputCPPNamedInteger(CodeGenerator &cg, AnalysisResultPtr ar);
void outputCPPNamedDouble(CodeGenerator &cg, AnalysisResultPtr ar);
};
///////////////////////////////////////////////////////////////////////////////
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
@@ -67,7 +67,6 @@ public:
static SimpleFunctionCallPtr GetFunctionCallForCallUserFunc(
AnalysisResultConstPtr ar, SimpleFunctionCallPtr call, int testOnly,
int firstParam, bool &error);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar, int state);
void setupScopes(AnalysisResultConstPtr ar);
bool readsLocals() const;
bool writesLocals() const;
@@ -113,7 +112,6 @@ protected:
ExpressionPtr m_safeDef;
std::string m_lambda;
void outputCPPParamOrderControlled(CodeGenerator &cg, AnalysisResultPtr ar);
ExpressionPtr optimize(AnalysisResultConstPtr ar);
private:
int checkObjCall(AnalysisResultPtr ar);
+3 -162
Ver Arquivo
@@ -142,8 +142,8 @@ void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) {
m_globals = true;
} else {
m_sym = variables->addDeclaredSymbol(
m_name, hhvm && Option::OutputHHBC ?
shared_from_this() : ConstructPtr());
m_name,
Option::OutputHHBC ? shared_from_this() : ConstructPtr());
}
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
@@ -172,7 +172,7 @@ void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) {
}
}
} else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
if (m_sym) {
if (m_sym && !m_this) {
if (!m_sym->isSystem() &&
!(getContext() &
(LValue|RefValue|RefParameter|UnsetContext|ExistContext)) &&
@@ -324,162 +324,3 @@ TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
void SimpleVariable::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf("$%s", m_name.c_str());
}
void SimpleVariable::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state)
{
if (hasCPPTemp()) return;
VariableTablePtr vt(getScope()->getVariables());
if (hasContext(InvokeArgument) && !hasContext(AccessContext) &&
(isLocalExprAltered() || (m_sym && m_sym->isReseated())) &&
!m_globals /* $GLOBALS always has reference semantics */ &&
hasAssignableCPPVariable()) {
const string &cppName = getAssignableCPPVariable(ar);
assert(!cppName.empty());
if (m_sym && m_sym->isReseated()) {
const string &arg_temp = genCPPTemp(cg, ar);
cg.wrapExpressionBegin();
cg_printf("const Variant %s = cit%d->isRef(%d) ? "
"Variant(strongBind(%s)) : %s;\n",
arg_temp.c_str(),
cg.callInfoTop(),
m_argNum,
cppName.c_str(),
cppName.c_str());
setCPPTemp(arg_temp);
} else {
Expression::preOutputStash(cg, ar, state);
const string &ref_temp = cppTemp();
assert(!ref_temp.empty());
const string &copy_temp = genCPPTemp(cg, ar);
const string &arg_temp = genCPPTemp(cg, ar);
cg_printf("const Variant %s = %s;\n",
copy_temp.c_str(),
cppName.c_str());
cg_printf("const Variant &%s = cit%d->isRef(%d) ? %s : %s;\n",
arg_temp.c_str(),
cg.callInfoTop(),
m_argNum,
ref_temp.c_str(),
copy_temp.c_str());
setCPPTemp(arg_temp);
}
return;
}
if (hasAnyContext(RefValue|RefParameter)) {
if (!hasAnyContext(InvokeArgument|AccessContext|
AssignmentRHS|ReturnContext) &&
!m_globals && (!m_sym || m_sym->isReseated()) &&
hasAssignableCPPVariable()) {
cg.wrapExpressionBegin();
const string &cppName = getAssignableCPPVariable(ar);
assert(!cppName.empty());
const string &tmp = genCPPTemp(cg, ar);
cg_printf("VRefParamValue %s((ref(%s)));\n",
tmp.c_str(), cppName.c_str());
setCPPTemp(tmp);
setContext(NoRefWrapper);
}
return;
} else if (hasContext(LValue)) {
return;
}
if (!m_alwaysStash && !(state & StashVars)) return;
Expression::preOutputStash(cg, ar, state);
}
bool SimpleVariable::hasAssignableCPPVariable() const {
if (!m_this) return true;
if (hasAnyContext(OprLValue | AssignmentLHS)) return false;
VariableTablePtr variables = getScope()->getVariables();
return variables->getAttribute(VariableTable::ContainsLDynamicVariable);
}
std::string SimpleVariable::getAssignableCPPVariable(AnalysisResultPtr ar)
const {
VariableTablePtr variables = getScope()->getVariables();
if (m_this) {
if (!hasAnyContext(OprLValue | AssignmentLHS) &&
variables->getAttribute(VariableTable::ContainsLDynamicVariable)) {
assert(m_sym);
const string &namePrefix = getNamePrefix();
return namePrefix + variables->getVariablePrefix(m_sym) + "this";
}
return "";
} else if (m_superGlobal) {
const string &name = variables->getGlobalVariableName(ar, m_name);
return string("g->") + name.c_str();
} else if (m_globals) {
return "get_global_array_wrapper()";
} else {
assert(m_sym);
const string &prefix0 = getNamePrefix();
const char *prefix1 =
getScope()->getVariables()->getVariablePrefix(m_sym);
return prefix0 + prefix1 +
CodeGenerator::FormatLabel(m_name);
}
}
void SimpleVariable::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
VariableTablePtr variables = getScope()->getVariables();
if (m_this) {
assert((getContext() & ObjectContext) == 0);
if (hasContext(OprLValue) || hasContext(AssignmentLHS)) {
cg_printf("throw_assign_this()");
return;
}
if (variables->getAttribute(VariableTable::ContainsLDynamicVariable)) {
assert(m_sym);
const string &namePrefix = getNamePrefix();
cg_printf("%s%sthis",
namePrefix.c_str(),
variables->getVariablePrefix(m_sym));
} else if (hasContext(DeepOprLValue) ||
hasContext(DeepAssignmentLHS) ||
hasContext(LValue)) {
// $this[] op= ...; or $this[] = ...
cg_printf("Variant(GET_THIS())");
} else {
ClassScopePtr cls = getOriginalClass();
if (!cls || cls->derivedByDynamic()) {
cg_printf("Object(GET_THIS())");
} else {
cg_printf("GET_THIS_TYPED(%s)", cls->getId().c_str());
}
}
} else if (m_superGlobal) {
const string &name = variables->getGlobalVariableName(ar, m_name);
cg_printf("g->%s", name.c_str());
} else if (m_globals) {
cg_printf("get_global_array_wrapper()");
} else {
assert(m_sym);
bool sw = false;
if (m_sym->isShrinkWrapped() &&
m_context == Declaration) {
assert(!getFunctionScope()->isGenerator());
TypePtr type = m_sym->getFinalType();
type->outputCPPDecl(cg, ar, getScope());
sw = true;
cg_printf(" ");
}
const string &prefix0 = getNamePrefix();
const char *prefix1 = variables->getVariablePrefix(m_sym);
cg_printf("%s%s%s",
prefix0.c_str(),
prefix1,
CodeGenerator::FormatLabel(m_name).c_str());
if (m_originalSym) {
cg.printf(" /* %s */", m_originalSym->getName().c_str());
}
if (sw) {
TypePtr type = m_sym->getFinalType();
const char *initializer = type->getCPPInitializer();
if (initializer) {
cg_printf(" = %s", initializer);
}
}
}
}
-6
Ver Arquivo
@@ -53,17 +53,11 @@ public:
bool couldBeAliased() const;
bool canKill(bool unset) const;
bool isHidden() const;
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool checkUnused() const;
bool getAlwaysStash() const { return m_alwaysStash; }
void setAlwaysStash() { m_alwaysStash = true; }
void updateSymbol(SimpleVariablePtr src);
void coalesce(SimpleVariablePtr other);
bool hasAssignableCPPVariable() const;
std::string getAssignableCPPVariable(AnalysisResultPtr ar) const;
private:
std::string getNamePrefix() const;
+1 -5
Ver Arquivo
@@ -97,11 +97,7 @@ ClassScopePtr StaticClassName::resolveClass() {
m_origClassName = self->getOriginalParent();
m_present = true;
}
} else if (!hhvm) {
// When generating hhvm bytecodes, the following statement
// causes EmitterVisitor::emitFuncCall to not generate a Parent
// byte code. It's unclear whether removing it would break hphpc
// so this code is left here under a hhvm flag check for now.
} else {
m_parent = false;
}
}
@@ -319,7 +319,7 @@ TypePtr StaticMemberExpression::inferTypes(AnalysisResultPtr ar,
}
unsigned StaticMemberExpression::getCanonHash() const {
int64 val = Expression::getCanonHash() +
int64_t val = Expression::getCanonHash() +
hash_string(Util::toLower(m_className).c_str(), m_className.size());
return ~unsigned(val) ^ unsigned(val >> 32);
}
@@ -360,119 +360,3 @@ void StaticMemberExpression::outputPHP(CodeGenerator &cg,
cg_printf("}");
}
}
void StaticMemberExpression::preOutputStash(CodeGenerator &cg,
AnalysisResultPtr ar,
int state)
{
if (getContext() & (LValue|RefValue|RefParameter)) return;
Expression::preOutputStash(cg, ar, state);
}
void StaticMemberExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (m_class) {
const char *func_suffix = "";
if (m_context & (LValue | RefValue | UnsetContext)) {
func_suffix = "_lval";
}
if (!hasContext(UnsetContext) || !hasContext(LValue)) {
cg_printf("get_static_property%s(", func_suffix);
} else {
cg_printf("throw_fatal_unset_static_property(");
}
if (m_class->is(KindOfScalarExpression)) {
assert(strcasecmp(dynamic_pointer_cast<ScalarExpression>(m_class)->
getString().c_str(), "static") == 0);
cg_printf("FrameInjection::GetStaticClassName(fi.getThreadInfo())");
} else {
cg_printf("get_static_class_name(");
m_class->outputCPP(cg, ar);
cg_printf(")");
}
cg_printf(", toString(");
m_exp->outputCPP(cg, ar);
cg_printf(").data())");
return;
}
if (hasContext(UnsetContext) && hasContext(LValue)) {
const string &name = CodeGenerator::EscapeLabel(m_origClassName);
cg_printf("throw_fatal_unset_static_property(\"%s\"", name.c_str());
cg_printf(", toString(");
m_exp->outputCPP(cg, ar);
cg_printf(").data())");
return;
}
if (!m_valid) {
if (!m_resolvedClass && !isRedeclared()) {
const string &name = CodeGenerator::EscapeLabel(m_origClassName);
cg_printf("throw_fatal(\"unknown class %s\")", name.c_str());
} else {
cg_printf("throw_fatal(\"Access to undeclared static property: ");
outputPHP(cg, ar);
cg_printf("\")");
}
return;
}
bool volatileCheck = false;
if (!isPresent() &&
((m_resolvedClass && m_resolvedClass->isVolatile()) ||
isRedeclared())) {
volatileCheck = true;
ClassScope::OutputVolatileCheckBegin(cg, ar, getScope(),
m_origClassName);
}
if (m_exp->is(Expression::KindOfScalarExpression) && !isRedeclared() &&
!m_dynamicClass) {
assert(m_resolvedClass);
ScalarExpressionPtr var = dynamic_pointer_cast<ScalarExpression>(m_exp);
string clsId = m_resolvedClass->getId();
TypePtr type = getCPPType();
bool close = type->isSpecificObject();
if (close) {
cg_printf("((%s&)", type->getCPPDecl(ar, getScope()).c_str());
}
if (m_resolvedClass->needLazyStaticInitializer()) {
cg_printf("%s%s->lazy_initializer(g)->%s%s%s%s",
Option::ClassStaticsCallbackPrefix, clsId.c_str(),
Option::StaticPropertyPrefix, clsId.c_str(),
Option::IdPrefix.c_str(),
CodeGenerator::FormatLabel(var->getString()).c_str());
} else {
cg_printf("g->%s%s%s%s", Option::StaticPropertyPrefix, clsId.c_str(),
Option::IdPrefix.c_str(),
CodeGenerator::FormatLabel(var->getString()).c_str());
}
if (close) cg_printf(")");
} else {
if (m_context & (LValue | RefValue | UnsetContext)) {
if (isRedeclared()) cg_printf("g->");
cg_printf("%s%s->%slval(", Option::ClassStaticsCallbackPrefix,
isRedeclared() ?
CodeGenerator::FormatLabel(m_className).c_str() :
m_resolvedClass->getId().c_str(),
Option::ObjectStaticPrefix);
} else {
if (isRedeclared()) cg_printf("g->");
cg_printf("%s%s->%sget(", Option::ClassStaticsCallbackPrefix,
isRedeclared() ?
CodeGenerator::FormatLabel(m_className).c_str() :
m_resolvedClass->getId().c_str(),
Option::ObjectStaticPrefix);
}
m_exp->outputCPP(cg, ar);
cg_printf(")");
}
if (volatileCheck) {
ClassScope::OutputVolatileCheckEnd(cg);
}
}
@@ -37,8 +37,6 @@ public:
virtual unsigned getCanonHash() const;
virtual bool canonCompare(ExpressionPtr e) const;
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
ExpressionPtr getExp() { return m_exp; }
@@ -617,351 +617,3 @@ void UnaryOpExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
}
}
void UnaryOpExpression::preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (hasCPPTemp() || m_op == T_FILE || m_op == T_DIR) return;
if (m_op == T_CLASS || m_op == T_FUNCTION) {
m_definedScope->outputCPPDef(cg);
setCPPTemp("id(0)");
return;
}
if (m_exp && !getLocalEffects() &&
m_op != '@' && m_op != T_ISSET && m_op != T_EMPTY &&
!m_exp->is(KindOfExpressionList)) {
m_exp->preOutputStash(cg, ar, state);
} else {
Expression::preOutputStash(cg, ar, state);
}
}
bool UnaryOpExpression::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state) {
if (m_op == T_ISSET && m_exp && m_exp->is(Expression::KindOfExpressionList)) {
ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
int count = exps->getCount();
if (count > 1) {
bool fix_e1 = (*exps)[0]->preOutputCPP(cg, ar, 0);
bool inExpression = cg.inExpression();
cg.setInExpression(false);
bool fix_en = false;
for (int i = 1; i < count; i++) {
if ((*exps)[i]->preOutputCPP(cg, ar, 0)) {
fix_en = true;
break;
}
}
cg.setInExpression(inExpression);
if (inExpression && fix_en) {
cg.wrapExpressionBegin();
std::string tmp = genCPPTemp(cg, ar);
cg_printf("bool %s = (", tmp.c_str());
(*exps)[0]->outputCPPExistTest(cg, ar, m_op);
cg_printf(");\n");
for (int i = 1; i < count; i++) {
cg_indentBegin("if (%s) {\n", tmp.c_str());
ExpressionPtr e = (*exps)[i];
e->preOutputCPP(cg, ar, 0);
cg_printf("%s = (", tmp.c_str());
e->outputCPPExistTest(cg, ar, m_op);
cg_printf(");\n");
}
for (int i = 1; i < count; i++) {
cg_indentEnd("}\n");
}
m_cppTemp = tmp;
} else if (state & FixOrder) {
preOutputStash(cg, ar, state);
fix_e1 = true;
}
return fix_e1 || fix_en;
}
}
if (m_op == '@') {
if (isUnused()) m_exp->setUnused(true);
bool doit = (state & FixOrder) || m_exp->hasEffect();
if (doit && cg.inExpression()) {
cg.wrapExpressionBegin();
std::string tmp = genCPPTemp(cg, ar);
cg_printf("Silencer %s(true);\n", tmp.c_str());
m_exp->preOutputCPP(cg, ar, 0);
this->preOutputStash(cg, ar, state | FixOrder | StashAll);
cg_printf("%s.disable();\n", tmp.c_str());
}
return doit;
} else if (m_op == T_PRINT && m_exp && !m_exp->hasEffect()) {
ExpressionPtrVec ev;
bool hasVoid = false;
if (BinaryOpExpression::getConcatList(ev, m_exp, hasVoid) > 1 ||
hasVoid ) {
if (!cg.inExpression()) return true;
cg.wrapExpressionBegin();
for (int i = 0, s = ev.size(); i < s; i++) {
ExpressionPtr e = ev[i];
e->preOutputCPP(cg, ar, 0);
cg_printf("print(");
e->outputCPP(cg, ar);
cg_printf(");\n");
}
m_cppTemp = "id(1)";
return true;
}
}
if (m_op == T_CLASS || m_op == T_FUNCTION) {
if (cg.inExpression()) {
cg.wrapExpressionBegin();
m_definedScope->outputCPPDef(cg);
setCPPTemp("id(0)");
}
return true;
}
return Expression::preOutputCPP(cg, ar, state);
}
bool UnaryOpExpression::outputCPPImplOpEqual(CodeGenerator &cg,
AnalysisResultPtr ar) {
if (m_exp->is(Expression::KindOfObjectPropertyExpression)) {
ObjectPropertyExpressionPtr var(
dynamic_pointer_cast<ObjectPropertyExpression>(m_exp));
if (var->isValid()) return false;
var->outputCPPObject(cg, ar);
cg_printf("o_assign_op<%s,%d>(",
isUnused() ? "void" : "Variant", m_op);
var->outputCPPProperty(cg, ar);
cg_printf(", %s%s)",
isUnused() || m_front ? "null_variant" : "Variant(0)",
originalClassName(cg, true).c_str());
return true;
}
return false;
}
void UnaryOpExpression::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
if ((m_op == T_INC || m_op == T_DEC) && outputCPPImplOpEqual(cg, ar)) {
return;
}
if (m_op == T_ARRAY &&
(getContext() & (RefValue|LValue)) == 0 &&
!cg.getInsideScalarArray()) {
int id = -1;
int hash = -1;
int index = -1;
string text;
if (m_exp) {
ExpressionListPtr pairs = dynamic_pointer_cast<ExpressionList>(m_exp);
Variant v;
if (pairs && pairs->isScalarArrayPairs() && pairs->getScalarValue(v)) {
id = ar->registerScalarArray(cg.getInsideScalarArray(), getFileScope(),
m_exp, hash, index, text);
}
} else {
id = ar->registerScalarArray(cg.getInsideScalarArray(), getFileScope(),
m_exp, hash, index, text); // empty array
}
if (id != -1) {
bool scalarVariant =
Option::UseScalarVariant && cg.hasScalarVariant();
if (scalarVariant) {
ar->addNamedScalarVarArray(text);
getUsedScalarScope(cg)->addUsedScalarVarArray(text);
}
if (Option::UseNamedScalarArray && cg.isFileOrClassHeader()) {
if (getClassScope()) {
getClassScope()->addUsedDefaultValueScalarArray(text);
if (scalarVariant) {
getClassScope()->addUsedDefaultValueScalarVarArray(text);
}
} else {
getFileScope()->addUsedDefaultValueScalarArray(text);
if (scalarVariant) {
getFileScope()->addUsedDefaultValueScalarVarArray(text);
}
}
}
ar->outputCPPScalarArrayId(cg, id, hash, index, scalarVariant);
return;
}
}
if ((m_op == T_ISSET || m_op == T_EMPTY || m_op == T_UNSET) && m_exp) {
if (m_exp->is(Expression::KindOfExpressionList)) {
ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
if (exps->getListKind() == ExpressionList::ListKindParam) {
int count = exps->getCount();
if (count > 1) {
cg_printf("(");
}
for (int i = 0; i < count; i++) {
if (m_op == T_UNSET) {
if (i > 0) cg_printf(", ");
(*exps)[i]->outputCPPUnset(cg, ar);
} else {
if (i > 0) cg_printf(" && ");
(*exps)[i]->outputCPPExistTest(cg, ar, m_op);
}
}
if (exps->getCount() > 1) {
cg_printf(")");
}
return;
}
}
if (m_op == T_UNSET) {
m_exp->outputCPPUnset(cg, ar);
} else {
m_exp->outputCPPExistTest(cg, ar, m_op);
}
return;
}
assert(m_op != T_CLASS && m_op != T_FUNCTION);
const char *cstr = 0;
if (m_front) {
switch (m_op) {
case T_CLONE: cg_printf("f_clone("); break;
case T_INC: cg_printf("++"); break;
case T_DEC: cg_printf("--"); break;
case '+': cg_printf("+"); break;
case '-': cg_printf("negate("); break;
case '!': cg_printf("!("); break;
case '~': cg_printf("~"); break;
case T_INT_CAST: cg_printf("("); break;
case T_DOUBLE_CAST: cg_printf("("); break;
case T_STRING_CAST: cstr = "String"; goto null_cast;
case T_ARRAY_CAST: cstr = "Array"; goto null_cast;
case T_OBJECT_CAST: cstr = "Object"; goto null_cast;
null_cast: {
TypePtr at = m_exp->getActualType();
TypePtr et = m_exp->getType();
TypePtr it = m_exp->getCPPType();
if (at && Type::SameType(at, et) && Type::SameType(it, at)) {
cg_printf("to%s(", cstr);
} else {
cg_printf("(");
}
break;
}
case T_BOOL_CAST: cg_printf("("); break;
case T_UNSET_CAST:
if (m_exp->isScalar()) {
cg_printf("(null)");
return;
}
if (m_exp->hasCPPTemp()) {
cg_printf("(id(");
} else {
cg_printf("(");
}
break;
case T_EXIT: cg_printf("f_exit("); break;
case T_ARRAY:
cg_printf("Array(");
break;
case T_PRINT: cg_printf("print("); break;
case T_EVAL:
if (Option::EnableEval > Option::NoEval) {
bool instance;
if (getClassScope()) {
FunctionScopePtr fs = getFunctionScope();
instance = fs && !fs->isStatic();
} else {
instance = false;
}
cg_printf("eval(%s, Object(%s), ",
getScope()->inPseudoMain() ?
"get_variable_table()" : "variables",
instance ? "this" : "");
} else {
cg_printf("f_eval(");
}
break;
case '@':
break;
case T_FILE:
cg_printf("get_source_filename(\"%s\")", getLocation()->file);
break;
case T_DIR:
cg_printf("get_source_filename(\"%s\", true)", getLocation()->file);
break;
default:
assert(false);
}
}
if (m_exp) {
switch (m_op) {
case '+':
case '-':
if (!m_exp->outputCPPArithArg(cg, ar, false)) {
m_exp->outputCPP(cg, ar);
}
break;
case '@':
if (isUnused()) {
m_exp->outputCPPUnneeded(cg, ar);
} else {
m_exp->outputCPP(cg, ar);
}
break;
default:
m_exp->outputCPP(cg, ar);
break;
}
}
if (m_front) {
switch (m_op) {
case T_ARRAY:
{
ExpressionListPtr exps = dynamic_pointer_cast<ExpressionList>(m_exp);
if (!exps) {
cg_printf("ArrayData::Create()");
}
cg_printf(")");
}
break;
case T_UNSET_CAST:
if (m_exp->hasCPPTemp()) {
cg_printf("),null");
} else {
cg_printf(",null");
}
case T_CLONE:
case '!':
case '-':
case T_INT_CAST:
case T_DOUBLE_CAST:
case T_STRING_CAST:
case T_ARRAY_CAST:
case T_OBJECT_CAST:
case T_BOOL_CAST:
case T_EXIT:
case T_PRINT:
case T_EVAL:
case T_INCLUDE:
case T_INCLUDE_ONCE:
case T_REQUIRE:
case T_REQUIRE_ONCE:
cg_printf(")");
break;
case '@':
break;
default:
break;
}
} else {
switch (m_op) {
case T_INC: cg_printf("++"); break;
case T_DEC: cg_printf("--"); break;
default:
assert(false);
}
}
}
@@ -58,10 +58,6 @@ public:
virtual bool canonCompare(ExpressionPtr e) const;
virtual ExpressionPtr unneededHelper();
void preOutputStash(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
bool preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
int state);
void setDefinedScope(BlockScopeRawPtr scope);
protected:
ExpressionPtr m_exp;
@@ -72,8 +68,6 @@ protected:
private:
bool preCompute(CVarRef value, Variant &result);
void setExistContext();
bool outputCPPImplOpEqual(CodeGenerator &cg, AnalysisResultPtr ar);
static void SetExpTypeForExistsContext(AnalysisResultPtr ar,
ExpressionPtr e, bool allowPrimitives);
};
@@ -65,8 +65,4 @@ void UserAttribute::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
}
void UserAttribute::outputCPPImpl(CodeGenerator &cg,
AnalysisResultPtr ar) {
}
}
-179
Ver Arquivo
@@ -59,7 +59,6 @@ map<string, int> Option::DynamicFunctionCalls;
bool Option::GeneratePickledPHP = false;
bool Option::GenerateInlinedPHP = false;
bool Option::GenerateTrimmedPHP = false;
bool Option::GenerateInlineComments = true;
bool Option::GenerateInferredTypes = false;
bool Option::ConvertSuperGlobals = false;
bool Option::ConvertQOpExpressions = false;
@@ -91,119 +90,25 @@ string Option::LabelEscape = "$";
string Option::LambdaPrefix = "df_";
string Option::Tab = " ";
/**
* They all have to be something different. Otherwise, there is always a chance
* of name collision or incorrect code transformation.
*/
const char *Option::FunctionPrefix = "f_";
const char *Option::TypedFunctionPrefix = "ft_";
const char *Option::BuiltinFunctionPrefix = "x_";
const char *Option::InvokePrefix = "i_";
const char *Option::InvokeFewArgsPrefix = "ifa_";
const char *Option::InvokeWrapperPrefix = "iw_";
const char *Option::InvokeWrapperFewArgsPrefix = "iwfa_";
const char *Option::InvokeSinglePrefix = "is_";
const char *Option::CreateObjectOnlyPrefix = "coo_";
const char *Option::PseudoMainPrefix = "pm_";
const char *Option::VariablePrefix = "v_";
const char *Option::LabelPrefix = "l_";
const char *Option::HiddenVariablePrefix = "h_";
const char *Option::GlobalVariablePrefix = "gv_";
const char *Option::StaticVariablePrefix = "sv_";
const char *Option::ClassPropTablePrefix = "cpt_";
const char *Option::ScalarArrayName = "sa_";
const char *Option::SystemScalarArrayName = "ssa_";
const char *Option::ClassPrefix = "c_";
const char *Option::ClassStaticsCallbackPrefix = "cw_";
const char *Option::ClassStaticsCallbackNullPrefix = "cwn_";
const char *Option::ClassStaticInitializerFlagPrefix = "csf_";
const char *Option::ObjectPrefix = "o_";
const char *Option::ObjectStaticPrefix = "os_";
const char *Option::SmartPtrPrefix = "p_";
const char *Option::MethodPrefix = "t_";
const char *Option::TypedMethodPrefix = "tt_";
const char *Option::MethodWrapperPrefix = "mf_";
const char *Option::MethodImplPrefix = "ti_";
const char *Option::TypedMethodImplPrefix = "tti_";
const char *Option::PropertyPrefix = "m_";
const char *Option::StaticPropertyPrefix = "s_";
const char *Option::ConstantPrefix = "k_";
const char *Option::ClassConstantPrefix = "q_";
const char *Option::ExceptionPrefix = "e_";
const char *Option::TempVariablePrefix = "r_";
const char *Option::CseTempVariablePrefix = "cse_";
const char *Option::CseTempStoragePrefix = "cses_";
const char *Option::EvalOrderTempPrefix = "eo_";
const char *Option::CallInfoPrefix = "ci_";
const char *Option::CallInfoWrapperPrefix = "ciw_";
const char *Option::SilencerPrefix = "sil_";
const char *Option::ScalarPrefix = "s_";
const char *Option::SysPrefix = "sys_";
const char *Option::StaticStringPrefix = "ss";
const char *Option::StaticStringProxyPrefix = "ssp";
const char *Option::StaticArrayPrefix = "sa";
const char *Option::StaticVarIntPrefix = "svi";
const char *Option::StaticVarDblPrefix = "svd";
const char *Option::StaticVarStrPrefix = "svs";
const char *Option::StaticVarStrProxyPrefix = "svsp";
const char *Option::StaticVarArrPrefix = "sva";
const char *Option::FFIFnPrefix = "ffi_";
const char *Option::TempPrefix = "tmp";
const char *Option::MapPrefix = "map";
const char *Option::IterPrefix = "iter";
const char *Option::InitPrefix = "inited_";
const char *Option::SwitchPrefix = "switch";
const char *Option::SystemFilePrefix = "sys/";
const char *Option::UserFilePrefix = "php/";
const char *Option::ClassHeaderPrefix = "cls/";
const char *Option::ClusterPrefix = "cpp/";
const char *Option::FFIFilePrefix = "ffi/";
bool Option::PreOptimization = false;
bool Option::PostOptimization = false;
bool Option::ScalarArrayOptimization = true;
bool Option::ScalarArrayCompression = true;
int Option::ScalarArrayFileCount = 1;
int Option::ScalarArrayOverflowLimit = 2000;
bool Option::SeparateCompilation = false;
bool Option::SeparateCompLib = false;
bool Option::UseNamedScalarArray = true;
int Option::LiteralStringFileCount = 2;
bool Option::AnalyzePerfectVirtuals = true;
bool Option::HardTypeHints = true;
std::string Option::RTTIOutputFile;
std::string Option::RTTIDirectory;
bool Option::GenRTTIProfileData = false;
bool Option::UseRTTIProfileData = false;
bool Option::GenerateCPPMacros = true;
bool Option::GenerateCPPMain = false;
bool Option::GenerateCPPComments = true;
bool Option::GenerateCPPMetaInfo = true;
bool Option::GenerateCPPNameSpace = true;
bool Option::GenArrayCreate = true;
bool Option::UseScalarVariant = true;
bool Option::UseStaticStringProxy = true;
bool Option::UseCallUserFuncFewArgs = true;
bool Option::GenGlobalState = false;
bool Option::KeepStatementsWithNoEffect = false;
bool Option::GenerateDummyPseudoMain = true;
int Option::ConditionalIncludeExpandLevel = 1;
int Option::DependencyMaxProgram = 1;
int Option::CodeErrorMaxProgram = 1;
bool Option::GenerateFFI = false;
Option::EvalLevel Option::EnableEval = NoEval;
std::string Option::JavaFFIRootPackage;
std::string Option::ProgramName;
std::string Option::PreprocessedPartitionConfig;
@@ -216,7 +121,6 @@ bool Option::EnableShortTags = true;
bool Option::EnableAspTags = false;
bool Option::EnableXHP = true;
bool Option::EnableFinallyStatement = false;
bool Option::NativeXHP = true;
int Option::ScannerType = Scanner::AllowShortTags;
int Option::ParserThreadCount = 0;
@@ -248,10 +152,6 @@ bool Option::GenerateSourceInfo = false;
bool Option::GenerateDocComments = true;
bool Option::FlAnnotate = false;
bool Option::SystemGen = false;
bool Option::PregenerateCPP = false;
bool Option::GenerateFFIStaticBinding = true;
int Option::GCCOptimization[] = {0, 0, 0};
void (*Option::m_hookHandler)(Hdf &config);
bool (*Option::PersistenceHook)(BlockScopeRawPtr scope, FileScopeRawPtr file);
@@ -320,46 +220,6 @@ void Option::Load(Hdf &config) {
READ_CG_OPTION(IdPrefix);
READ_CG_OPTION(LabelEscape);
READ_CG_OPTION(LambdaPrefix);
READ_CG_OPTION(FunctionPrefix);
READ_CG_OPTION(BuiltinFunctionPrefix);
READ_CG_OPTION(InvokePrefix);
READ_CG_OPTION(PseudoMainPrefix);
READ_CG_OPTION(VariablePrefix);
READ_CG_OPTION(LabelPrefix);
READ_CG_OPTION(HiddenVariablePrefix);
READ_CG_OPTION(GlobalVariablePrefix);
READ_CG_OPTION(StaticVariablePrefix);
READ_CG_OPTION(ScalarArrayName);
READ_CG_OPTION(SystemScalarArrayName);
READ_CG_OPTION(ClassPrefix);
READ_CG_OPTION(ClassStaticsCallbackPrefix);
READ_CG_OPTION(ClassStaticsCallbackNullPrefix);
READ_CG_OPTION(ClassStaticInitializerFlagPrefix);
READ_CG_OPTION(ObjectPrefix);
READ_CG_OPTION(ObjectStaticPrefix);
READ_CG_OPTION(SmartPtrPrefix);
READ_CG_OPTION(MethodPrefix);
READ_CG_OPTION(MethodWrapperPrefix);
READ_CG_OPTION(MethodImplPrefix);
READ_CG_OPTION(PropertyPrefix);
READ_CG_OPTION(StaticPropertyPrefix);
READ_CG_OPTION(ConstantPrefix);
READ_CG_OPTION(ClassConstantPrefix);
READ_CG_OPTION(ExceptionPrefix);
READ_CG_OPTION(TempVariablePrefix);
READ_CG_OPTION(EvalOrderTempPrefix);
READ_CG_OPTION(SilencerPrefix);
READ_CG_OPTION(TempPrefix);
READ_CG_OPTION(MapPrefix);
READ_CG_OPTION(IterPrefix);
READ_CG_OPTION(InitPrefix);
READ_CG_OPTION(SwitchPrefix);
READ_CG_OPTION(FFIFnPrefix);
READ_CG_OPTION(SystemFilePrefix);
READ_CG_OPTION(UserFilePrefix);
READ_CG_OPTION(ClassHeaderPrefix);
READ_CG_OPTION(ClusterPrefix);
READ_CG_OPTION(FFIFilePrefix);
}
int count = 0;
@@ -411,18 +271,7 @@ void Option::Load(Hdf &config) {
AutoloadRoot = autoloadMap["root"].getString();
}
ScalarArrayFileCount = config["ScalarArrayFileCount"].getByte(1);
if (ScalarArrayFileCount <= 0) ScalarArrayFileCount = 1;
LiteralStringFileCount = config["LiteralStringFileCount"].getInt32(2);
if (LiteralStringFileCount <= 0) LiteralStringFileCount = 2;
UseStaticStringProxy = config["UseStaticStringProxy"].getBool(true);
HardTypeHints = config["HardTypeHints"].getBool(true);
ScalarArrayOverflowLimit = config["ScalarArrayOverflowLimit"].getInt32(2000);
if (ScalarArrayOverflowLimit <= 0) ScalarArrayOverflowLimit = 2000;
if (UseNamedScalarArray) {
ScalarArrayOptimization = true;
ScalarArrayCompression = true;
}
EnableHipHopSyntax = config["EnableHipHopSyntax"].getBool();
JitEnableRenameFunction = config["JitEnableRenameFunction"].getBool();
@@ -437,9 +286,6 @@ void Option::Load(Hdf &config) {
else ScannerType &= ~Scanner::AllowAspTags;
EnableXHP = config["EnableXHP"].getBool(true);
NativeXHP = config["NativeXHP"].getBool(true);
if (EnableXHP && !NativeXHP) ScannerType |= Scanner::PreprocessXHP;
else ScannerType &= ~Scanner::PreprocessXHP;
ParserThreadCount = config["ParserThreadCount"].getInt32(0);
if (ParserThreadCount <= 0) {
@@ -448,7 +294,6 @@ void Option::Load(Hdf &config) {
EnableFinallyStatement = config["EnableFinallyStatement"].getBool();
RTTIOutputFile = config["RTTIOutputFile"].getString();
EnableEval = (EvalLevel)config["EnableEval"].getByte(0);
AllDynamic = config["AllDynamic"].getBool(true);
AllVolatile = config["AllVolatile"].getBool();
@@ -467,30 +312,12 @@ void Option::Load(Hdf &config) {
ArrayAccessIdempotent = config["ArrayAccessIdempotent"].getBool(false);
DumpAst = config["DumpAst"].getBool(false);
WholeProgram = config["WholeProgram"].getBool(true);
PregenerateCPP = config["PregenerateCPP"].getBool(false);
GenerateFFIStaticBinding = config["GenerateFFIStaticBinding"].getBool(true);
{
Hdf gccOptimization = config["GCCOptimization"];
GCCOptimization[0] = gccOptimization["O0"].getInt32(0);
GCCOptimization[1] = gccOptimization["O1"].getInt32(GCCOptimization[0]);
GCCOptimization[2] = gccOptimization["O2"].getInt32(GCCOptimization[1]);
}
if (m_hookHandler) m_hookHandler(config);
OnLoad();
}
int Option::GetOptimizationLevel(int length) {
if (length <= 0) return 3;
for (int i = 2; i >= 0; --i) {
int min = GCCOptimization[i];
if (length < min || min == 0) return i + 1;
}
return 0;
}
void Option::Load() {
OnLoad();
}
@@ -558,12 +385,6 @@ std::string Option::MangleFilename(const std::string &name, bool id) {
return ret;
}
std::string Option::FormatClusterFile(int index) {
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s%03d", ClusterPrefix, index);
return buf;
}
bool Option::IsFileExcluded(const std::string &file,
const std::set<std::string> &patterns) {
String sfile(file.c_str(), file.size(), AttachLiteral);
-121
Ver Arquivo
@@ -117,46 +117,14 @@ public:
*/
static bool PreOptimization;
static bool PostOptimization;
static bool ScalarArrayOptimization;
static bool ScalarArrayCompression;
static int ScalarArrayFileCount;
static int ScalarArrayOverflowLimit;
static int LiteralStringFileCount;
static bool AnalyzePerfectVirtuals;
static bool HardTypeHints;
/**
* RTTI profiling metadata output file
*/
static std::string RTTIOutputFile;
/**
* Directory of RTTI profiling data, used for second pass compilation
*/
static std::string RTTIDirectory;
static bool GenRTTIProfileData;
static bool UseRTTIProfileData;
/**
* Generate array_createN service routines
*/
static bool GenArrayCreate;
static bool UseScalarVariant;
static bool UseStaticStringProxy;
static bool UseCallUserFuncFewArgs;
static bool GenGlobalState;
/**
* Separate compilation
*/
static bool SeparateCompilation;
static bool SeparateCompLib;
static bool UseNamedScalarArray;
/**
* CodeGenerator options for PHP.
@@ -164,7 +132,6 @@ public:
static bool GeneratePickledPHP;
static bool GenerateInlinedPHP;
static bool GenerateTrimmedPHP;
static bool GenerateInlineComments; // comments on inlined file names
static bool GenerateInferredTypes; // comments on constant/variable tables
static bool ConvertSuperGlobals; // $GLOBALS['var'] => global $var
static bool ConvertQOpExpressions; // $var = $exp ? $yes : $no => if-else
@@ -207,83 +174,13 @@ public:
/**
* Name resolution helpers.
*/
static const char *FunctionPrefix;
static const char *TypedFunctionPrefix;
static const char *BuiltinFunctionPrefix;
static const char *InvokePrefix;
static const char *InvokeFewArgsPrefix;
static const char *InvokeWrapperPrefix;
static const char *InvokeWrapperFewArgsPrefix;
static const char *InvokeSinglePrefix;
static const char *CreateObjectOnlyPrefix;
static const char *PseudoMainPrefix;
static const char *VariablePrefix;
static const char *LabelPrefix;
static const char *HiddenVariablePrefix;
static const char *GlobalVariablePrefix;
static const char *StaticVariablePrefix;
static const char *ScalarArrayName;
static const char *SystemScalarArrayName;
static const char *ClassPrefix;
static const char *ClassStaticsCallbackPrefix;
static const char *ClassStaticsCallbackNullPrefix;
static const char *ClassStaticInitializerFlagPrefix;
static const char *ObjectPrefix;
static const char *ObjectStaticPrefix;
static const char *SmartPtrPrefix;
static const char *MethodPrefix;
static const char *TypedMethodPrefix;
static const char *MethodWrapperPrefix;
static const char *MethodImplPrefix;
static const char *TypedMethodImplPrefix;
static const char *PropertyPrefix;
static const char *StaticPropertyPrefix;
static const char *ConstantPrefix;
static const char *ClassConstantPrefix;
static const char *ExceptionPrefix;
static const char *TempVariablePrefix;
static const char *CseTempVariablePrefix;
static const char *CseTempStoragePrefix;
static const char *EvalOrderTempPrefix;
static const char *SilencerPrefix;
static const char *CallInfoPrefix;
static const char *CallInfoWrapperPrefix;
static const char *SysPrefix;
static const char *ScalarPrefix;
static const char *StaticStringPrefix;
static const char *StaticStringProxyPrefix;
static const char *StaticArrayPrefix;
static const char *StaticVarIntPrefix;
static const char *StaticVarDblPrefix;
static const char *StaticVarStrPrefix;
static const char *StaticVarStrProxyPrefix;
static const char *StaticVarArrPrefix;
static const char *ClassPropTablePrefix;
static const char *TempPrefix;
static const char *MapPrefix;
static const char *IterPrefix;
static const char *InitPrefix;
static const char *SwitchPrefix;
static const char *FFIFnPrefix;
static const char *SystemFilePrefix;
static const char *UserFilePrefix;
static const char *ClassHeaderPrefix;
static const char *ClusterPrefix;
static const char *FFIFilePrefix;
/**
* Turn it off for cleaner unit tests.
*/
static bool GenerateCPPMacros; // all macros
static bool GenerateCPPMain; // include and main()
static bool GenerateCPPComments; // section comments
static bool GenerateCPPMetaInfo; // class map
static bool GenerateCPPNameSpace; // namespace HPHP
static bool KeepStatementsWithNoEffect;
static bool GenerateDummyPseudoMain;
/**
* When we have an include inside a function or a method, how many levels
@@ -318,13 +215,6 @@ public:
*/
static std::string MangleFilename(const std::string &name, bool id);
/**
* Returns a name for a clustered .cpp file.
*/
static std::string FormatClusterFile(int index);
static bool GenerateFFI;
enum EvalLevel {
NoEval = 0, // calling eval is a fatal
LimitedEval = 1, // eval is supported in a limited way with no perf hit
@@ -333,11 +223,6 @@ public:
static EvalLevel EnableEval;
/**
* The root package for Java FFI stubs (dot-separated). The default is php.
*/
static std::string JavaFFIRootPackage;
static std::string ProgramName;
static std::string PreprocessedPartitionConfig; // generated by ppp.php
@@ -350,7 +235,6 @@ public:
static bool EnableAspTags;
static bool EnableXHP;
static bool EnableFinallyStatement;
static bool NativeXHP;
static int ScannerType;
static int ParserThreadCount;
@@ -390,11 +274,6 @@ public:
static bool WholeProgram;
static bool RecordErrors;
static std::string DocJson; // filename to dump doc JSON to
static bool PregenerateCPP;
static bool GenerateFFIStaticBinding;
static int GCCOptimization[3];
static int GetOptimizationLevel(int length);
static void setHookHandler(void (*hookHandler)(Hdf &config)) {
m_hookHandler = hookHandler;
+1 -2
Ver Arquivo
@@ -31,7 +31,6 @@
#include <util/db_conn.h>
#include <util/db_query.h>
#include <util/exception.h>
#include <util/preprocess.h>
#include <util/job_queue.h>
#include <runtime/base/execution_context.h>
@@ -298,7 +297,7 @@ bool Package::parseImpl(const char *fileName) {
int lines = 0;
try {
Logger::Verbose("parsing %s ...", fullPath.c_str());
Scanner scanner(fullPath.c_str(), Option::ScannerType, hhvm);
Scanner scanner(fullPath.c_str(), Option::ScannerType, true);
Compiler::Parser parser(scanner, fileName, m_ar, sb.st_size);
parser.parse();
lines = parser.line1();
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+12 -13
Ver Arquivo
@@ -83,7 +83,6 @@
#include <compiler/analysis/code_error.h>
#include <compiler/analysis/analysis_result.h>
#include <util/preprocess.h>
#include <util/lock.h>
#include <util/logger.h>
@@ -146,7 +145,7 @@ StatementListPtr Parser::ParseString(CStrRef input, AnalysisResultPtr ar,
if (!fileName || !*fileName) fileName = "string";
int len = input.size();
Scanner scanner(input.data(), len, Option::ScannerType, fileName, hhvm);
Scanner scanner(input.data(), len, Option::ScannerType, fileName, true);
Parser parser(scanner, fileName, ar, len);
parser.m_lambdaMode = lambdaMode;
if (parser.parse()) {
@@ -163,11 +162,8 @@ Parser::Parser(Scanner &scanner, const char *fileName,
AnalysisResultPtr ar, int fileSize /* = 0 */)
: ParserBase(scanner, fileName), m_ar(ar), m_lambdaMode(false),
m_closureGenerator(false) {
MD5 md5;
if (hhvm) {
string md5str = Eval::FileRepository::unitMd5(scanner.getMd5());
md5 = MD5(md5str.c_str());
}
string md5str = Eval::FileRepository::unitMd5(scanner.getMd5());
MD5 md5 = MD5(md5str.c_str());
m_file = FileScopePtr(new FileScope(m_fileName, fileSize, md5));
@@ -858,7 +854,7 @@ void Parser::onFunction(Token &out, Token &ret, Token &ref, Token &name,
Token origGenFunc;
create_generator(this, out, params, name, closureName, nullptr, nullptr,
hasCallToGetArgs, origGenFunc,
hhvm && Option::OutputHHBC &&
Option::OutputHHBC &&
(!Option::WholeProgram || !Option::ParseTimeOpts),
attr);
m_closureGenerator = false;
@@ -1154,7 +1150,7 @@ void Parser::onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
Token origGenFunc;
create_generator(this, out, params, name, closureName, m_clsName.c_str(),
&modifiers, hasCallToGetArgs, origGenFunc,
hhvm && Option::OutputHHBC &&
Option::OutputHHBC &&
(!Option::WholeProgram || !Option::ParseTimeOpts),
attr);
MethodStatementPtr origStmt =
@@ -1571,12 +1567,15 @@ void Parser::onClosureStart(Token &name) {
void Parser::onClosure(Token &out, Token &ret, Token &ref, Token &params,
Token &cparams, Token &stmts) {
Token func, name;
onFunction(func, ret, ret, name, params, stmts, 0);
onFunction(func, ret, ref, name, params, stmts, 0);
ClosureExpressionPtr closure = NEW_EXP(
ClosureExpression,
dynamic_pointer_cast<FunctionStatement>(func->stmt),
dynamic_pointer_cast<ExpressionList>(cparams->exp));
closure->getClosureFunction()->setContainingClosure(closure);
out.reset();
out->exp = NEW_EXP(ClosureExpression,
dynamic_pointer_cast<FunctionStatement>(func->stmt),
dynamic_pointer_cast<ExpressionList>(cparams->exp));
out->exp = closure;
}
void Parser::onClosureParam(Token &out, Token *params, Token &param,
+2 -1
Ver Arquivo
@@ -20,6 +20,7 @@
#include <runtime/base/util/exceptions.h>
#include <util/parser/parser.h>
#include <compiler/construct.h>
#include <compiler/option.h>
#ifdef HPHP_PARSER_NS
#undef HPHP_PARSER_NS
@@ -31,7 +32,7 @@
#endif
#define HPHP_PARSER_ERROR(fmt, p, args...) \
do { \
if (!HPHP::hhvm) { \
if (HPHP::Option::WholeProgram) { \
HPHP::Logger::Error(fmt " %s", ##args, (p)->getMessage(true).c_str()); \
} \
throw HPHP::ParseTimeFatalException((p)->file(), (p)->line1(), \
@@ -101,11 +101,3 @@ void BlockStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_stmts) m_stmts->outputPHP(cg, ar);
cg_indentEnd("}\n");
}
void BlockStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_stmts) {
cg_indentBegin("{\n");
m_stmts->outputCPP(cg, ar);
cg_indentEnd("}\n");
}
}
+2 -75
Ver Arquivo
@@ -109,86 +109,13 @@ void BreakStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
}
int64 BreakStatement::getDepth() {
int64_t BreakStatement::getDepth() {
if (!m_exp) return 1;
Variant v;
if (m_exp->getScalarValue(v) &&
v.isInteger()) {
int64 depth = v.toInt64();
int64_t depth = v.toInt64();
return depth >= 1 ? depth : 1;
}
return 0;
}
void BreakStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
const std::vector<int> &labelIds = cg.getBreakScopes();
if (labelIds.empty()) {
cg_printf("throw_fatal(\"bad %s\");\n", m_name);
return;
}
int64 depth = getDepth();
if (!depth) {
unsigned size = labelIds.size();
int labelId = 0;
int varId = cg.createNewLocalId(shared_from_this());
cg_printf("int64 %s%d;\n", Option::TempPrefix, varId);
m_exp->outputCPPBegin(cg, ar);
cg_printf("%s%d = (", Option::TempPrefix, varId);
m_exp->outputCPP(cg, ar);
cg_printf(");\n");
m_exp->outputCPPEnd(cg, ar);
if (size > 1) {
cg_printf("switch (");
cg_printf("%s%d", Option::TempPrefix, varId);
cg_printf(") {\n");
for (unsigned int i = 0; i < size; i++) {
labelId = labelIds[i];
labelId &= ~CodeGenerator::BreakScopeBitMask;
cg_printf("case %d: goto %s%d;\n",
int(labelIds.size() - i), m_name, labelId);
cg.addLabelId(m_name, labelId);
}
cg_printf("default:\n");
} else {
labelId = labelIds.back();
labelId &= ~CodeGenerator::BreakScopeBitMask;
cg.addLabelId(m_name, labelId);
}
cg_printf("if (");
cg_printf("%s%d", Option::TempPrefix, varId);
cg_printf("<2) {\n");
cg_printf("goto %s%d;\n", m_name, labelId);
cg_printf("} else {\n");
cg_printf("throw_fatal(\"bad %s\");\n", m_name);
cg_printf("}\n");
if (size > 1) {
cg_printf("}\n");
}
return;
}
assert(depth >= 1);
if (depth > (int64)labelIds.size()) {
cg_printf("throw_fatal(\"bad %s\");\n", m_name);
return;
}
int labelId = labelIds[labelIds.size() - depth];
if (depth > 1 || labelId & CodeGenerator::InsideSwitch) {
if (depth == 1 && labelId & CodeGenerator::StaticCases) {
cg_printf("break;\n"); // continue will turn into break as well
} else {
labelId &= ~CodeGenerator::BreakScopeBitMask;
cg_printf("goto %s%d;\n", m_name, labelId);
cg.addLabelId(m_name, labelId);
}
} else {
cg_printf("%s;\n", m_name);
}
}
+1 -1
Ver Arquivo
@@ -32,7 +32,7 @@ public:
DECLARE_STATEMENT_VIRTUAL_FUNCTIONS;
StatementPtr preOptimize(AnalysisResultConstPtr ar);
int64 getDepth();
int64_t getDepth();
ExpressionPtr getExp();
protected:
const char *m_name;
+1 -45
Ver Arquivo
@@ -58,7 +58,7 @@ bool CaseStatement::isLiteralString() const {
return exp->isLiteralString();
}
int64 CaseStatement::getLiteralInteger() const {
int64_t CaseStatement::getLiteralInteger() const {
assert(m_condition->is(Expression::KindOfScalarExpression));
ScalarExpressionPtr exp =
dynamic_pointer_cast<ScalarExpression>(m_condition);
@@ -134,47 +134,3 @@ void CaseStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
}
cg_indentEnd();
}
void CaseStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_condition) {
cg_printf("case ");
m_condition->outputCPPImpl(cg, ar);
cg_indentBegin(":\n");
} else {
cg_indentBegin("default:\n");
}
cg_indentBegin("{\n");
if (m_stmt) {
m_stmt->outputCPP(cg, ar);
}
cg_indentEnd("}\n");
cg_indentEnd();
}
void CaseStatement::outputCPPByNumber(CodeGenerator &cg, AnalysisResultPtr ar,
int varId, int caseNum) {
if (caseNum >= 0) {
cg_indentBegin("case_%d_%d:\n", varId, caseNum);
}
cg_indentBegin("{\n");
if (m_stmt) {
m_stmt->outputCPP(cg, ar);
}
cg_indentEnd("}\n");
if (caseNum >= 0) {
cg_indentEnd();
}
}
void CaseStatement::outputCPPAsIf(CodeGenerator &cg, AnalysisResultPtr ar,
int varId, const char *var, int caseNum) {
if (m_condition) {
m_condition->outputCPPBegin(cg, ar);
cg_printf("if (equal(%s, (", var);
m_condition->outputCPP(cg, ar);
cg_printf("))) goto case_%d_%d;\n", varId, caseNum);
m_condition->outputCPPEnd(cg, ar);
} else {
cg_printf("goto case_%d_%d;\n", varId, caseNum);
}
}
+1 -14
Ver Arquivo
@@ -42,7 +42,7 @@ public:
*/
bool isLiteralInteger() const;
bool isLiteralString() const;
int64 getLiteralInteger() const;
int64_t getLiteralInteger() const;
std::string getLiteralString() const;
bool getScalarConditionValue(Variant &v) const {
@@ -55,19 +55,6 @@ public:
*/
ExpressionPtr getCondition() { return m_condition;}
StatementPtr getStatement() { return m_stmt; }
/**
* Generate an "if" statement that sets caseVar to caseNum if m_condition
* evaluates true.
*/
void outputCPPAsIf(CodeGenerator &cg, AnalysisResultPtr ar,
int varId, const char *var, int caseNum);
/**
* Generate a case statement that cases by caseNum.
*/
void outputCPPByNumber(CodeGenerator &cg, AnalysisResultPtr ar,
int varId, int caseNum);
private:
ExpressionPtr m_condition;
StatementPtr m_stmt;
-17
Ver Arquivo
@@ -144,20 +144,3 @@ void CatchStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_stmt) m_stmt->outputPHP(cg, ar);
cg_indentEnd("}");
}
void CatchStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_valid) {
cg_printf("if (e.instanceof(");
cg_printString(m_className, ar, shared_from_this());
cg_indentBegin(")) {\n");
VariableTablePtr variables = getScope()->getVariables();
assert(m_variable->hasAssignableCPPVariable());
const string &cppName =
m_variable->getAssignableCPPVariable(ar);
cg_printf("%s = e;\n", cppName.c_str());
} else {
cg_indentBegin("if (false) {\n");
}
if (m_stmt) m_stmt->outputCPP(cg, ar);
cg_indentEnd("}");
}
-76
Ver Arquivo
@@ -138,79 +138,3 @@ void ClassConstant::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
cg_printf(";\n");
}
void ClassConstant::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
if (cg.getContext() != CodeGenerator::CppClassConstantsDecl &&
cg.getContext() != CodeGenerator::CppClassConstantsImpl) {
return;
}
ClassScopePtr scope = getClassScope();
for (int i = 0; i < m_exp->getCount(); i++) {
AssignmentExpressionPtr exp =
dynamic_pointer_cast<AssignmentExpression>((*m_exp)[i]);
ConstantExpressionPtr var =
dynamic_pointer_cast<ConstantExpression>(exp->getVariable());
TypePtr type = scope->getConstants()->getFinalType(var->getName());
ExpressionPtr value = exp->getValue();
if (scope->getConstants()->isDynamic(var->getName())) {
continue;
}
switch (cg.getContext()) {
case CodeGenerator::CppClassConstantsDecl:
cg_printf("extern const ");
if (type->is(Type::KindOfString)) {
cg_printf("StaticString");
} else {
type->outputCPPDecl(cg, ar, getScope());
}
cg_printf(" %s%s%s%s;\n",
Option::ClassConstantPrefix, scope->getId().c_str(),
Option::IdPrefix.c_str(), var->getName().c_str());
break;
case CodeGenerator::CppClassConstantsImpl: {
bool isString = type->is(Type::KindOfString);
bool isVariant = Type::IsMappedToVariant(type);
ScalarExpressionPtr scalarExp =
dynamic_pointer_cast<ScalarExpression>(value);
bool stringForVariant = false;
if (isVariant && scalarExp &&
scalarExp->getActualType() &&
scalarExp->getActualType()->is(Type::KindOfString)) {
cg_printf("static const StaticString %s%s%s%s%sv(LITSTR_INIT(%s));\n",
Option::ClassConstantPrefix, scope->getId().c_str(),
Option::IdPrefix.c_str(), var->getName().c_str(),
Option::IdPrefix.c_str(),
scalarExp->getCPPLiteralString().c_str());
stringForVariant = true;
}
cg_printf("const ");
if (isString) {
cg_printf("StaticString");
} else {
type->outputCPPDecl(cg, ar, getScope());
}
value->outputCPPBegin(cg, ar);
cg_printf(" %s%s%s%s",
Option::ClassConstantPrefix, scope->getId().c_str(),
Option::IdPrefix.c_str(), var->getName().c_str());
cg_printf(isString ? "(" : " = ");
if (stringForVariant) {
cg_printf("%s%s%s%s%sv",
Option::ClassConstantPrefix, scope->getId().c_str(),
Option::IdPrefix.c_str(), var->getName().c_str(),
Option::IdPrefix.c_str());
} else if (isString && scalarExp) {
cg_printf("LITSTR_INIT(%s)",
scalarExp->getCPPLiteralString().c_str());
} else {
value->outputCPP(cg, ar);
}
cg_printf(isString ? ");\n" : ";\n");
value->outputCPPEnd(cg, ar);
break;
}
default:
assert(false);
}
}
}
+1 -591
Ver Arquivo
@@ -189,7 +189,6 @@ void ClassStatement::analyzeProgram(AnalysisResultPtr ar) {
if (ar->getPhase() != AnalysisResult::AnalyzeAll) return;
ar->recordClassSource(m_name, m_loc, getFileScope()->getName());
for (unsigned int i = 0; i < bases.size(); i++) {
ClassScopePtr cls = ar->findClass(bases[i]);
if (cls) {
@@ -275,594 +274,5 @@ bool ClassStatement::hasImpl() const {
ClassScopeRawPtr cls = getClassScope();
return cls->isVolatile() ||
cls->getVariables()->getAttribute(VariableTable::ContainsDynamicStatic) ||
(hhvm && Option::OutputHHBC);
}
void ClassStatement::outputCPPClassDecl(CodeGenerator &cg,
AnalysisResultPtr ar,
const char *clsName,
const char *originalName,
const char *parent) {
ClassScopeRawPtr classScope = getClassScope();
VariableTablePtr variables = classScope->getVariables();
ConstantTablePtr constants = classScope->getConstants();
const char *sweep =
classScope->isUserClass() && !classScope->isSepExtension() ?
"_NO_SWEEP" : "";
if (variables->hasAllJumpTables() &&
classScope->hasAllJumpTables()) {
cg_printf("DECLARE_CLASS%s(%s, %s, %s)\n",
sweep, clsName,
CodeGenerator::EscapeLabel(originalName).c_str(), parent);
return;
}
// Now we start to break down DECLARE_CLASS into lines of code that could
// be generated differently...
cg_printf("DECLARE_CLASS_COMMON%s(%s, %s)\n", sweep,
clsName, CodeGenerator::EscapeLabel(originalName).c_str());
}
void ClassStatement::GetCtorAndInitInfo(
StatementPtr s, bool &needsCppCtor, bool &needsInit) {
if (!s) return;
switch (s->getKindOf()) {
case Statement::KindOfStatementList:
{
StatementListPtr stmts = static_pointer_cast<StatementList>(s);
for (int i = 0; i < stmts->getCount(); i++) {
GetCtorAndInitInfo((*stmts)[i], needsCppCtor, needsInit);
}
}
break;
case Statement::KindOfClassVariable:
{
ClassVariablePtr cv = static_pointer_cast<ClassVariable>(s);
cv->getCtorAndInitInfo(needsCppCtor, needsInit);
}
break;
default: break;
}
}
void ClassStatement::getCtorAndInitInfo(bool &needsCppCtor, bool &needsInit) {
needsCppCtor = needsInit = false;
ClassScopeRawPtr classScope = getClassScope();
if (!m_parent.empty()) {
if (classScope->derivesFromRedeclaring() ==
ClassScope::DirectFromRedeclared) {
needsInit = true;
}
}
GetCtorAndInitInfo(m_stmt, needsCppCtor, needsInit);
// exception is special
if (!needsInit && m_name == "exception") needsInit = true;
}
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
if (cg.getContext() == CodeGenerator::NoContext) {
InterfaceStatement::outputCPPImpl(cg, ar);
return;
}
ClassScopeRawPtr classScope = getClassScope();
if (cg.getContext() != CodeGenerator::CppForwardDeclaration) {
printSource(cg);
}
string clsNameStr = classScope->getId();
const char *clsName = clsNameStr.c_str();
switch (cg.getContext()) {
case CodeGenerator::CppDeclaration:
{
if (Option::GenerateCPPMacros) {
classScope->outputForwardDeclaration(cg);
}
classScope->outputCPPGlobalTableWrappersDecl(cg, ar);
bool system = cg.getOutput() == CodeGenerator::SystemCPP;
ClassScopePtr parCls;
if (!m_parent.empty()) {
parCls = ar->findClass(m_parent);
if (parCls && parCls->isRedeclaring()) parCls.reset();
}
if (Option::GenerateCppLibCode) {
cg.printDocComment(classScope->getDocComment());
}
cg_printf("class %s%s", Option::ClassPrefix, clsName);
if (!m_parent.empty() && classScope->derivesDirectlyFrom(m_parent)) {
if (!parCls) {
cg_printf(" : public DynamicObjectData");
} else {
cg_printf(" : public %s%s", Option::ClassPrefix,
parCls->getId().c_str());
}
} else {
if (classScope->derivesFromRedeclaring()) {
cg_printf(" : public DynamicObjectData");
} else if (system) {
cg_printf(" : public ExtObjectData");
} else {
cg_printf(" : public ObjectData");
}
}
if (m_base && Option::UseVirtualDispatch) {
for (int i = 0; i < m_base->getCount(); i++) {
ScalarExpressionPtr exp =
dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
const char *intf = exp->getString().c_str();
ClassScopePtr intfClassScope = ar->findClass(intf);
if (intfClassScope && !intfClassScope->isRedeclaring() &&
classScope->derivesDirectlyFrom(intf) &&
(!parCls || !parCls->derivesFrom(ar, intf, true, false))) {
string id = intfClassScope->getId();
cg_printf(", public %s%s", Option::ClassPrefix, id.c_str());
}
}
}
cg_indentBegin(" {\n");
cg_printf("public:\n");
cg.printSection("Properties");
if (classScope->getVariables()->outputCPPPropertyDecl(
cg, ar, classScope->derivesFromRedeclaring())) {
cg.printSection("Destructor");
cg_printf("~%s%s() NEVER_INLINE {}", Option::ClassPrefix, clsName);
}
if (Option::GenerateCppLibCode) {
cg.printSection("Methods");
classScope->outputMethodWrappers(cg, ar);
cg.printSection(">>>>>>>>>> Internal Implementation <<<<<<<<<<");
cg_printf("// NOTE: Anything below is subject to change. "
"Use everything above instead.\n");
}
cg.printSection("Class Map");
bool hasEmitCppCtor = false;
bool needsCppCtor = classScope->needsCppCtor();
bool needsInit = classScope->needsInitMethod();
bool disableDestructor =
!classScope->canSkipCreateMethod(ar) ||
(!classScope->derivesFromRedeclaring() &&
!classScope->hasAttribute(ClassScope::HasDestructor, ar));
if (Option::GenerateCPPMacros) {
bool dyn = classScope->derivesFromRedeclaring() ==
ClassScope::DirectFromRedeclared;
bool idyn = parCls && classScope->derivesFromRedeclaring() ==
ClassScope::IndirectFromRedeclared;
bool redec = classScope->isRedeclaring();
if (!parCls && !m_parent.empty()) {
always_assert(dyn);
}
if (!classScope->derivesFromRedeclaring()) {
outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(),
parCls ? parCls->getId().c_str()
: "ObjectData");
} else {
cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName,
m_originalName.c_str(),
dyn || !parCls ? "DynamicObjectData" :
parCls->getId().c_str());
}
if (classScope->checkHasPropTable(ar)) {
cg_printf("static const ClassPropTable %sprop_table;\n",
Option::ObjectStaticPrefix);
}
bool hasGet = classScope->getAttribute(
ClassScope::HasUnknownPropGetter);
bool hasSet = classScope->getAttribute(
ClassScope::HasUnknownPropSetter);
bool hasIsset = classScope->getAttribute(
ClassScope::HasUnknownPropTester);
bool hasUnset = classScope->getAttribute(
ClassScope::HasPropUnsetter);
bool hasCall = classScope->getAttribute(
ClassScope::HasUnknownMethodHandler);
bool hasCallStatic = classScope->getAttribute(
ClassScope::HasUnknownStaticMethodHandler);
bool hasRootParam =
classScope->derivedByDynamic() && (redec || dyn || idyn);
string lateInit = "";
if (redec && classScope->derivedByDynamic()) {
if (!dyn && !idyn && (!parCls || parCls->isUserClass())) {
cg_printf("private: ObjectData* root;\n");
cg_printf("public:\n");
cg_printf("virtual ObjectData *getRoot() { return root; }\n");
lateInit = "root(r ? r : this)";
}
}
string callbacks = Option::ClassStaticsCallbackPrefix + clsNameStr;
string conInit = "";
if (dyn) {
conInit = "DynamicObjectData(cb, \"" +
CodeGenerator::EscapeLabel(m_parent) + "\", ";
if (hasRootParam) {
conInit += "r)";
} else {
conInit += "this)";
}
} else if (parCls) {
conInit = string(Option::ClassPrefix) + parCls->getId() + "(";
if (parCls->derivedByDynamic() &&
(parCls->isRedeclaring() ||
parCls->derivesFromRedeclaring() != ClassScope::FromNormal)) {
if (hasRootParam) {
conInit += "r ? r : ";
}
conInit += "this, ";
}
conInit += "cb)";
} else {
if (system) {
conInit = "ExtObjectData(cb)";
} else {
if (hasRootParam) {
conInit = "ObjectData(cb, r)";
} else {
conInit = "ObjectData(cb, false)";
}
}
}
cg_printf("%s%s(%sconst ObjectStaticCallbacks *cb = &%s%s) : %s",
Option::ClassPrefix,
clsName,
hasRootParam ? "ObjectData* r = NULL," : "",
callbacks.c_str(),
redec ? ".oscb" : "",
conInit.c_str());
if (needsCppCtor) {
cg_printf(", ");
cg.setContext(CodeGenerator::CppConstructor);
assert(!cg.hasInitListFirstElem());
m_stmt->outputCPP(cg, ar);
cg.clearInitListFirstElem();
cg.setContext(CodeGenerator::CppDeclaration);
}
if (!lateInit.empty()) {
cg_printf(", %s", lateInit.c_str());
}
cg_indentBegin(" {%s",
hasGet || hasSet || hasIsset || hasUnset ||
hasCall || hasCallStatic || disableDestructor ||
hasRootParam ? "\n" : "");
if (hasRootParam) {
cg_printf("setId(r);\n");
}
if (hasGet) cg_printf("setAttribute(UseGet);\n");
if (hasSet) cg_printf("setAttribute(UseSet);\n");
if (hasIsset) cg_printf("setAttribute(UseIsset);\n");
if (hasUnset) cg_printf("setAttribute(UseUnset);\n");
if (hasCall) cg_printf("setAttribute(HasCall);\n");
if (hasCallStatic) cg_printf("setAttribute(HasCallStatic);\n");
if (disableDestructor) {
cg_printf("if (!hhvm) setAttribute(NoDestructor);\n");
}
cg_indentEnd("}\n");
hasEmitCppCtor = true;
}
if (needsCppCtor && !hasEmitCppCtor) {
cg_printf("%s%s() : ", Option::ClassPrefix, clsName);
cg.setContext(CodeGenerator::CppConstructor);
assert(!cg.hasInitListFirstElem());
m_stmt->outputCPP(cg, ar);
cg.clearInitListFirstElem();
cg.setContext(CodeGenerator::CppDeclaration);
cg_printf(" {%s}\n",
disableDestructor ?
" if (!hhvm) setAttribute(NoDestructor); " : "");
}
if (needsInit) {
cg_printf("void init();\n");
}
// doCall
if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) {
cg_printf("Variant doCall(Variant v_name, Variant v_arguments, "
"bool fatal);\n");
}
if (classScope->getAttribute(ClassScope::HasInvokeMethod)) {
FunctionScopePtr func =
classScope->findFunction(ar, "__invoke", false);
assert(func);
if (!func->isAbstract()) {
cg_printf("const CallInfo *"
"t___invokeCallInfoHelper(void *&extra);\n");
}
}
if (classScope->isRedeclaring() &&
!classScope->derivesFromRedeclaring() &&
classScope->derivedByDynamic()) {
cg_printf("Variant doRootCall(Variant v_name, Variant v_arguments, "
"bool fatal);\n");
}
if (m_stmt) m_stmt->outputCPP(cg, ar);
{
std::set<string> done;
classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName);
}
if (Option::GenerateCPPMacros) {
classScope->outputCPPJumpTableDecl(cg, ar);
}
cg_indentEnd("};\n");
classScope->outputCPPDynamicClassDecl(cg);
if (m_stmt) {
cg.setContext(CodeGenerator::CppClassConstantsDecl);
m_stmt->outputCPP(cg, ar);
cg.setContext(CodeGenerator::CppDeclaration);
}
}
break;
case CodeGenerator::CppImplementation:
{
if (m_stmt) {
cg.setContext(CodeGenerator::CppClassConstantsImpl);
m_stmt->outputCPP(cg, ar);
cg.setContext(CodeGenerator::CppImplementation);
}
classScope->outputCPPSupportMethodsImpl(cg, ar);
bool needsInit = classScope->needsInitMethod();
if (needsInit) {
cg_indentBegin("void %s%s::init() {\n",
Option::ClassPrefix, clsName);
if (!m_parent.empty()) {
if (classScope->derivesFromRedeclaring() ==
ClassScope::DirectFromRedeclared) {
cg_printf("parent->init();\n");
} else {
ClassScopePtr parCls = ar->findClass(m_parent);
cg_printf("%s%s::init();\n", Option::ClassPrefix,
parCls->getId().c_str());
}
}
if (classScope->getVariables()->
getAttribute(VariableTable::NeedGlobalPointer)) {
cg.printDeclareGlobals();
}
cg.setContext(CodeGenerator::CppInitializer);
if (m_stmt) m_stmt->outputCPP(cg, ar);
// This is lame. Exception base class needs to prepare stacktrace
// outside of its PHP constructor. Every subclass of exception also
// needs this stacktrace, so we're adding an artificial __init__ in
// exception.php and calling it here.
if (m_name == "exception") {
cg_printf("{CountableHelper h(this); t___init__();}\n");
}
cg_indentEnd("}\n");
}
cg.setContext(CodeGenerator::CppImplementation);
if (m_stmt) m_stmt->outputCPP(cg, ar);
}
break;
case CodeGenerator::CppFFIDecl:
case CodeGenerator::CppFFIImpl:
if (m_stmt) m_stmt->outputCPP(cg, ar);
break;
case CodeGenerator::JavaFFI:
{
if (classScope->isRedeclaring()) break;
// TODO support PHP namespaces, once HPHP supports it
string packageName = Option::JavaFFIRootPackage;
string packageDir = packageName;
Util::replaceAll(packageDir, ".", "/");
string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix +
packageDir + "/";
Util::mkdir(outputDir);
// uses a different cg to generate a separate file for each PHP class
// also, uses the original capitalized class name
string clsFile = outputDir + getOriginalName() + ".java";
std::ofstream fcls(clsFile.c_str());
CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP);
cgCls.setContext(CodeGenerator::JavaFFI);
cgCls.printf("package %s;\n\n", packageName.c_str());
cgCls.printf("import hphp.*;\n\n");
printSource(cgCls);
string clsModifier;
switch (m_type) {
case T_CLASS:
break;
case T_ABSTRACT:
clsModifier = "abstract ";
break;
case T_FINAL:
clsModifier = "final ";
break;
}
cgCls.printf("public %sclass %s ", clsModifier.c_str(),
getOriginalName().c_str());
ClassScopePtr parCls;
if (!m_parent.empty()) parCls = ar->findClass(m_parent);
if (!m_parent.empty() && classScope->derivesDirectlyFrom(m_parent)
&& parCls && parCls->isUserClass() && !parCls->isRedeclaring()) {
// system classes are not supported in static FFI translation
// they shouldn't appear as superclasses as well
cgCls.printf("extends %s", parCls->getOriginalName().c_str());
}
else {
cgCls.printf("extends HphpObject");
}
if (m_base) {
bool first = true;
for (int i = 0; i < m_base->getCount(); i++) {
ScalarExpressionPtr exp =
dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
const char *intf = exp->getString().c_str();
ClassScopePtr intfClassScope = ar->findClass(intf);
if (intfClassScope && classScope->derivesFrom(ar, intf, false, false)
&& intfClassScope->isUserClass()) {
if (first) {
cgCls.printf(" implements ");
first = false;
}
else {
cgCls.printf(", ");
}
cgCls.print(intfClassScope->getOriginalName().c_str());
}
}
}
cgCls.indentBegin(" {\n");
// constructor for initializing the variant pointer
cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n",
getOriginalName().c_str());
FunctionScopePtr cons = classScope->findConstructor(ar, true);
if ((cons && !cons->isAbstract()) || m_type != T_ABSTRACT) {
// if not an abstract class and not having an explicit constructor,
// adds a default constructor
outputJavaFFIConstructor(cgCls, ar, cons);
}
if (m_stmt) m_stmt->outputCPP(cgCls, ar);
cgCls.indentEnd("}\n");
fcls.close();
}
break;
case CodeGenerator::JavaFFICppDecl:
case CodeGenerator::JavaFFICppImpl:
{
if (classScope->isRedeclaring()) break;
if (m_stmt) m_stmt->outputCPP(cg, ar);
FunctionScopePtr cons = classScope->findConstructor(ar, true);
if ((cons && !cons->isAbstract()) || m_type != T_ABSTRACT) {
outputJavaFFICPPCreator(cg, ar, cons);
}
}
break;
default:
assert(false);
break;
}
}
void ClassStatement::outputJavaFFIConstructor(CodeGenerator &cg,
AnalysisResultPtr ar,
FunctionScopePtr cons) {
int ac = cons ? cons->getMaxParamCount() : 0;
bool varArgs = cons && cons->isVariableArgument();
// generates the constructor
cg_printf("public %s(", getOriginalName().c_str());
std::ostringstream args;
std::ostringstream params;
bool first = true;
for (int i = 0; i < ac; i++) {
if (first) {
first = false;
}
else {
cg_printf(", ");
args << ", ";
params << ", ";
}
cg_printf("HphpVariant a%d", i);
args << "a" << i << ".getVariantPtr()";
params << "long a" << i;
}
if (varArgs) {
if (!first) {
cg_printf(", ");
args << ", ";
params << ", ";
}
cg_printf("HphpVariant va");
args << "va.getVariantPtr()";
params << "long va";
}
cg_indentBegin(") {\n");
cg_printf("this(create(%s));\n", args.str().c_str());
cg_indentEnd("}\n\n");
// generates the native method stub for creating the object
cg_printf("private static native long create(%s);\n\n",
params.str().c_str());
}
void ClassStatement::outputJavaFFICPPCreator(CodeGenerator &cg,
AnalysisResultPtr ar,
FunctionScopePtr cons) {
ClassScopeRawPtr cls = getClassScope();
string packageName = Option::JavaFFIRootPackage;
int ac = cons ? cons->getMaxParamCount() : 0;
bool varArgs = cons && cons->isVariableArgument();
const char *clsName = getOriginalName().c_str();
string mangledName = "Java_" + packageName + "_" + clsName + "_create";
Util::replaceAll(mangledName, ".", "_");
cg_printf("JNIEXPORT jlong JNICALL\n");
cg_printf("%s(JNIEnv *env, jclass cls", mangledName.c_str());
std::ostringstream args;
bool first = true;
if (varArgs) {
args << ac << " + (((Variant *)va)->isNull() ? 0"
<< " : ((Variant *)va)->getArrayData()->size())";
first = false;
}
for (int i = 0; i < ac; i++) {
if (first) first = false;
else {
args << ", ";
}
cg_printf(", jlong a%d", i);
args << "*(Variant *)a" << i;
}
if (varArgs) {
if (!first) {
args << ", ";
}
cg_printf(", jlong va");
args << "((Variant *)va)->toArray()";
}
if (cg.getContext() == CodeGenerator::JavaFFICppDecl) {
// java_stubs.h
cg_printf(");\n\n");
return;
}
cg_indentBegin(") {\n");
cg_printf("ObjectData *obj = (NEWOBJ(%s%s)())->create(%s);\n",
Option::ClassPrefix, cls->getId().c_str(), args.str().c_str());
cg_printf("return (jlong)(NEW(Variant)(obj));\n");
cg_indentEnd("}\n\n");
Option::OutputHHBC;
}

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