f8f9284238
Finally logic is handled by a new component: FinallyRouter. The approach taken essentially constructs a simple finite state automaton that decides which action to take next, once the control reaches the end of a finally block. The automaton uses an unnamed local variable "state". It also uses an additional unnamed local to stash result between the point of actually returning from a function and invoking return. In order to minimize perf impact, two copies of finally blocka are in fact emitted. The first copy ends with a switch statement and is part of the automaton. The second copy handles exceptional situations exclusively and ends with Unwind. When multiple nested finallies exist, multiple copies of a fault funclet corresponding to the inner finally will be emitted in order to correctly handle chaining. Exception chaining is handled using an extended set of members in Fault (m_raiseLevel, m_raiseFrame, m_raiseNesting). These values are used to decide whether two exceptions stored on the top of the m_faults stack should be chained already, or not yet. Additionally, changes have been made to grammar files and AST in order to give the emitter more information about the scope of goto labels. This is used in order to handle goto from try finally block correctly. No jumps into try finally are allowed, since reference implementation (Zend) fatals in this case. Reviewed By: @paroski Differential Revision: D1058497
71 linhas
2.4 KiB
C++
71 linhas
2.4 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "hphp/compiler/statement/statement.h"
|
|
#include "hphp/compiler/analysis/ast_walker.h"
|
|
#include "hphp/compiler/analysis/function_scope.h"
|
|
|
|
using namespace HPHP;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define DEC_STMT_NAMES(x) #x
|
|
const char *Statement::Names[] = {
|
|
DECLARE_STATEMENT_TYPES(DEC_STMT_NAMES)
|
|
};
|
|
|
|
Statement::Statement(STATEMENT_CONSTRUCTOR_BASE_PARAMETERS)
|
|
: Construct(scope, loc),
|
|
m_kindOf(kindOf),
|
|
m_labelScope(labelScope) {
|
|
DCHECK(m_labelScope != nullptr);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// parser functions
|
|
|
|
void Statement::addElement(StatementPtr stmt) {
|
|
assert(false);
|
|
}
|
|
|
|
void Statement::insertElement(StatementPtr stmt, int index /* = 0 */) {
|
|
assert(false);
|
|
}
|
|
|
|
bool Statement::hasReachableLabel() const {
|
|
if (FunctionWalker::SkipRecurse(this)) return false;
|
|
switch (getKindOf()) {
|
|
case KindOfForStatement:
|
|
case KindOfForEachStatement:
|
|
case KindOfWhileStatement:
|
|
case KindOfDoStatement: {
|
|
// a label inside a loop cant be reached from outside the loop
|
|
FunctionScopeRawPtr f = getFunctionScope();
|
|
if (f && f->isGenerator()) break;
|
|
return false;
|
|
}
|
|
case KindOfLabelStatement:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
for (int i = getKidCount(); i--; ) {
|
|
StatementPtr child(getNthStmt(i));
|
|
if (child && child->hasReachableLabel()) return true;
|
|
}
|
|
return false;
|
|
}
|