2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/php7/compiler.h"
19 #include <folly/Format.h>
23 namespace HPHP
{ namespace php7
{
26 // helpers to cope with these functions taking non-const pointers
29 inline const zval
* zend_ast_get_zval(const zend_ast
* ast
) {
30 return &reinterpret_cast<const zend_ast_zval
*>(ast
)->val
;
33 inline const zend_ast_list
* zend_ast_get_list(const zend_ast
* ast
) {
34 return reinterpret_cast<const zend_ast_list
*>(ast
);
37 inline std::string
zval_to_string(const zval
* zv
) {
39 switch (Z_TYPE_P(zv
)) {
41 folly::format(&out
, "{}", Z_LVAL_P(zv
));
50 folly::format(&out
, "{}", Z_DVAL_P(zv
));
53 folly::format(&out
, "{}", Z_STRVAL_P(zv
));
64 Compiler::Compiler() {
65 unit
= std::make_unique
<Unit
>();
66 unit
->name
= "unit.hhas";
69 void Compiler::compileProgram(const zend_ast
* ast
) {
70 assert(ast
->kind
== ZEND_AST_STMT_LIST
);
72 auto pseudomain
= unit
->getPseudomain();
73 activeFunction
= pseudomain
;
74 activeBlock
= pseudomain
->entry
;
76 compileStatement(ast
);
79 activeBlock
->emit(Int
{-1});
80 activeBlock
->exit(RetC
{});
84 void Compiler::panic(const std::string
& msg
) {
85 throw CompilerException(folly::sformat("panic: {}", msg
));
88 void Compiler::compileZvalLiteral(const zval
* zv
) {
89 switch (Z_TYPE_P(zv
)) {
91 activeBlock
->emit(Int
{Z_LVAL_P(zv
)});
94 activeBlock
->emit(Null
{});
97 activeBlock
->emit(False
{});
100 activeBlock
->emit(True
{});
103 activeBlock
->emit(Double
{Z_DVAL_P(zv
)});
106 activeBlock
->emit(String
{Z_STRVAL_P(zv
)});
109 panic("unsupported literal");
113 void Compiler::compileConstant(const zend_ast
* ast
) {
114 auto name
= ast
->child
[0];
115 const char* str
= Z_STRVAL_P(zend_ast_get_zval(name
));
116 if (name
->attr
& ZEND_NAME_NOT_FQ
) {
117 if (strcasecmp(str
, "true") == 0) {
118 activeBlock
->emit(True
{});
119 } else if (strcasecmp(str
, "false") == 0) {
120 activeBlock
->emit(False
{});
121 } else if (strcasecmp(str
, "null") == 0) {
122 activeBlock
->emit(Null
{});
124 panic("unknown unqualified constant");
127 panic("unknown constant");
131 void Compiler::compileVar(const zend_ast
* ast
) {
132 getLvalue(ast
)->getC();
135 Bytecode
Compiler::opForBinaryOp(const zend_ast
* ast
) {
136 // NB: bizarrely, greater-than (>,>=) have their own AST type
137 // and there is no ZEND_IS_GREATER since it doesn't correspond to a VM
139 if (ast
->kind
== ZEND_AST_GREATER
) {
141 } else if (ast
->kind
== ZEND_AST_GREATER_EQUAL
) {
146 case ZEND_ADD
: return Add
{};
147 case ZEND_SUB
: return Sub
{};
148 case ZEND_MUL
: return Mul
{};
149 case ZEND_DIV
: return Div
{};
150 case ZEND_POW
: return Pow
{};
151 case ZEND_MOD
: return Mod
{};
152 case ZEND_SL
: return Shl
{};
153 case ZEND_SR
: return Shr
{};
154 case ZEND_BW_OR
: return BitOr
{};
155 case ZEND_BW_AND
: return BitAnd
{};
156 case ZEND_BW_XOR
: return BitXor
{};
157 case ZEND_CONCAT
: return Concat
{};
159 case ZEND_IS_IDENTICAL
: return Same
{};
160 case ZEND_IS_NOT_IDENTICAL
: return NSame
{};
161 case ZEND_IS_EQUAL
: return Eq
{};
162 case ZEND_IS_NOT_EQUAL
: return Neq
{};
163 case ZEND_IS_SMALLER
: return Lt
{};
164 case ZEND_IS_SMALLER_OR_EQUAL
: return Lte
{};
165 case ZEND_SPACESHIP
: return Cmp
{};
167 panic("unknown binop");
171 void Compiler::compileUnaryOp(const zend_ast
* ast
) {
173 case ZEND_AST_UNARY_MINUS
:
174 activeBlock
->emit(Int
{0});
175 compileExpression(ast
->child
[0]);
176 activeBlock
->emit(Sub
{});
178 case ZEND_AST_UNARY_PLUS
:
179 activeBlock
->emit(Int
{0});
180 compileExpression(ast
->child
[0]);
181 activeBlock
->emit(Add
{});
183 case ZEND_AST_UNARY_OP
:
184 compileExpression(ast
->child
[0]);
187 activeBlock
->emit(Not
{});
190 activeBlock
->emit(BitNot
{});
194 panic("unknown unop");
197 IncDecOp
Compiler::getIncDecOpForNode(zend_ast_kind kind
) {
199 case ZEND_AST_PRE_INC
:
200 return IncDecOp::PreInc
;
201 case ZEND_AST_PRE_DEC
:
202 return IncDecOp::PreDec
;
203 case ZEND_AST_POST_INC
:
204 return IncDecOp::PostInc
;
205 case ZEND_AST_POST_DEC
:
206 return IncDecOp::PostDec
;
208 panic("not a inc/dec node");
212 SetOpOp
Compiler::getSetOpOp(zend_ast_attr attr
) {
214 case ZEND_ASSIGN_ADD
:
215 return SetOpOp::PlusEqual
;
216 case ZEND_ASSIGN_SUB
:
217 return SetOpOp::MinusEqual
;
218 case ZEND_ASSIGN_MUL
:
219 return SetOpOp::MulEqual
;
220 case ZEND_ASSIGN_POW
:
221 return SetOpOp::PowEqual
;
222 case ZEND_ASSIGN_DIV
:
223 return SetOpOp::DivEqual
;
224 case ZEND_ASSIGN_CONCAT
:
225 return SetOpOp::ConcatEqual
;
226 case ZEND_ASSIGN_MOD
:
227 return SetOpOp::ModEqual
;
228 case ZEND_ASSIGN_BW_AND
:
229 return SetOpOp::AndEqual
;
230 case ZEND_ASSIGN_BW_OR
:
231 return SetOpOp::OrEqual
;
232 case ZEND_ASSIGN_BW_XOR
:
233 return SetOpOp::XorEqual
;
235 return SetOpOp::SlEqual
;
237 return SetOpOp::SrEqual
;
239 panic("unsupported set-op");
243 void Compiler::compileIncDec(const zend_ast
* ast
) {
244 auto op
= getIncDecOpForNode(ast
->kind
);
245 auto var
= ast
->child
[0];
247 getLvalue(var
)->incDec(op
);
250 void Compiler::compileAssignment(const zend_ast
* ast
) {
251 auto rhs
= ast
->child
[1];
252 auto lhs
= ast
->child
[0];
254 getLvalue(lhs
)->assign(rhs
);
257 void Compiler::compileAssignOp(const zend_ast
* ast
) {
258 auto rhs
= ast
->child
[1];
259 auto op
= getSetOpOp(ast
->attr
);
260 auto lhs
= ast
->child
[0];
262 getLvalue(lhs
)->assignOp(op
, rhs
);
266 void Compiler::compileExpression(const zend_ast
* ast
) {
269 compileZvalLiteral(zend_ast_get_zval(ast
));
272 compileConstant(ast
);
274 case ZEND_AST_UNARY_MINUS
:
275 case ZEND_AST_UNARY_PLUS
:
276 case ZEND_AST_UNARY_OP
:
279 case ZEND_AST_BINARY_OP
:
280 case ZEND_AST_GREATER
:
281 case ZEND_AST_GREATER_EQUAL
:
282 compileExpression(ast
->child
[0]);
283 compileExpression(ast
->child
[1]);
284 activeBlock
->emit(opForBinaryOp(ast
));
286 case ZEND_AST_POST_INC
:
287 case ZEND_AST_POST_DEC
:
288 case ZEND_AST_PRE_INC
:
289 case ZEND_AST_PRE_DEC
:
295 case ZEND_AST_ASSIGN
:
296 compileAssignment(ast
);
298 case ZEND_AST_ASSIGN_OP
:
299 compileAssignOp(ast
);
302 panic("unsupported expression");
306 void Compiler::compileStatement(const zend_ast
* ast
) {
308 case ZEND_AST_STMT_LIST
: {
309 // just a block, so recur please :)
310 auto list
= zend_ast_get_list(ast
);
311 for (uint32_t i
= 0; i
< list
->children
; i
++) {
312 if (!list
->child
[i
]) {
315 compileStatement(list
->child
[i
]);
320 compileExpression(ast
->child
[0]);
321 activeBlock
->emit(Print
{});
322 activeBlock
->emit(PopC
{});
328 compileWhile(ast
->child
[0], ast
->child
[1], false);
330 case ZEND_AST_DO_WHILE
:
331 compileWhile(ast
->child
[1], ast
->child
[0], true);
334 compileExpression(ast
);
335 activeBlock
->emit(PopC
{});
339 void Compiler::compileIf(const zend_ast
* ast
) {
340 auto list
= zend_ast_get_list(ast
);
342 // where control will return after we're finished
343 auto end
= activeFunction
->allocateBlock();
345 for (uint32_t i
= 0; i
<list
->children
; i
++) {
346 auto elem
= list
->child
[i
];
347 auto condition
= elem
->child
[0];
348 auto contents
= elem
->child
[1];
350 // if no condition is provided, this is the 'else' branch
351 compileStatement(contents
);
354 // otherwise, we have a conditional
355 auto branch
= activeFunction
->allocateBlock();
357 withBlock(branch
, [&]() {
358 compileStatement(contents
);
359 activeBlock
->exit(Jmp
{end
});
362 compileExpression(condition
);
363 branchTo
<JmpNZ
>(branch
);
367 activeBlock
->exit(Jmp
{end
});
371 void Compiler::compileWhile(const zend_ast
* condition
, const zend_ast
* body
,
374 auto continuation
= activeFunction
->allocateBlock();
375 auto bodyBlock
= activeFunction
->allocateBlock();
376 auto testBlock
= activeFunction
->allocateBlock();
378 withBlock(bodyBlock
, [&]() {
379 activeLoops
.push({continuation
, testBlock
});
380 compileStatement(body
);
381 activeBlock
->exit(Jmp
{testBlock
});
385 withBlock(testBlock
, [&]() {
386 compileExpression(condition
);
387 activeBlock
->exit(JmpNZ
{bodyBlock
});
388 activeBlock
->exit(Jmp
{continuation
});
392 activeBlock
->exit(Jmp
{bodyBlock
});
394 activeBlock
->exit(Jmp
{testBlock
});
397 activeBlock
= continuation
;
400 struct Compiler::LocalLvalue
: Compiler::Lvalue
{
401 LocalLvalue(Compiler
& c
, std::string name
)
403 , name(std::move(name
)) {}
405 void getC() override
{
406 c
.activeFunction
->locals
.insert(name
);
407 c
.activeBlock
->emit(CGetL
{name
});
410 void assign(const zend_ast
* rhs
) override
{
411 c
.activeFunction
->locals
.insert(name
);
412 c
.compileExpression(rhs
);
413 c
.activeBlock
->emit(SetL
{name
});
416 void assignOp(SetOpOp op
, const zend_ast
* rhs
) override
{
417 c
.activeFunction
->locals
.insert(name
);
418 c
.compileExpression(rhs
);
419 c
.activeBlock
->emit(SetOpL
{name
, op
});
422 void incDec(IncDecOp op
) override
{
423 c
.activeFunction
->locals
.insert(name
);
424 c
.activeBlock
->emit(IncDecL
{name
, op
});
431 struct Compiler::DynamicLocalLvalue
: Compiler::Lvalue
{
432 DynamicLocalLvalue(Compiler
& c
, const zend_ast
* nameExpr
)
434 , nameExpr(nameExpr
) {}
436 void getC() override
{
437 c
.compileExpression(nameExpr
);
438 c
.activeBlock
->emit(CGetN
{});
441 void assign(const zend_ast
* rhs
) override
{
442 c
.compileExpression(nameExpr
);
443 c
.compileExpression(rhs
);
444 c
.activeBlock
->emit(SetN
{});
447 void assignOp(SetOpOp op
, const zend_ast
* rhs
) override
{
448 c
.compileExpression(nameExpr
);
449 c
.compileExpression(rhs
);
450 c
.activeBlock
->emit(SetOpN
{op
});
453 void incDec(IncDecOp op
) override
{
454 c
.compileExpression(nameExpr
);
455 c
.activeBlock
->emit(IncDecN
{op
});
459 const zend_ast
* nameExpr
;
462 std::unique_ptr
<Compiler::Lvalue
> Compiler::getLvalue(const zend_ast
* ast
) {
463 if (ast
->kind
== ZEND_AST_VAR
) {
464 auto name
= ast
->child
[0];
465 switch (name
->kind
) {
467 return std::make_unique
<Compiler::LocalLvalue
>(
469 zval_to_string(zend_ast_get_zval(name
)));
471 return std::make_unique
<Compiler::DynamicLocalLvalue
>(
477 panic("unsupported lvalue");