Arquivos
hhvm/hphp/runtime/ext/ext_error.cpp
T
Drew Paroski d3c421cb79 Separate resources from objects, part 2
In HHVM we've been piggybacking resources on the KindOfObject machinery.
At the language level, resource is considered to be a different type than
object, and there are a number of differences in behavior between objects
and resources (ex. resources don't allow for dynamic properties, resources
don't work with the clone operator, the "(object)" cast behaves differently
for resources vs. objects, etc).

Piggybacking resources on the KindOfObject machinery has some downsides.
Code that deals with KindOfObject values often needs to check if the value
is a resource and go down a different code path. This makes things harder
to maintain and harder to keep parity with Zend. Also, these extra branches
hurt performance a little, and they make it harder for the JIT to do a good
job in some cases when its generating machine code that operates on objects.

This diff introduces a new DataType called "KindOfResource", it separates
ResourceData from ObjectData's inheritance hierarchy, introduces a new
smart pointer types called "Resource" and "SmartResource", updates the
runtime as appropriate, and kills some more dead code in ObjectData and
ResourceData. I've tried to keep behavior the same for the most part and
resisted the urge to fix existing bugs with resources.
2013-07-29 11:25:56 -07:00

245 linhas
7.9 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
| Copyright (c) 1997-2010 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include "hphp/runtime/ext/ext_error.h"
#include "hphp/runtime/base/exceptions.h"
#include "hphp/runtime/base/string_buffer.h"
#include "hphp/runtime/ext/ext_file.h"
#include "hphp/util/logger.h"
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
const int DEBUG_BACKTRACE_PROVIDE_OBJECT = 1;
const int DEBUG_BACKTRACE_IGNORE_ARGS = 2;
Array f_debug_backtrace(int64_t options /* = 1 */, int64_t limit /* = 0 */) {
bool provide_object = options & DEBUG_BACKTRACE_PROVIDE_OBJECT;
bool ignore_args = options & DEBUG_BACKTRACE_IGNORE_ARGS;
return g_vmContext->debugBacktrace(
true, false, provide_object, nullptr, ignore_args, limit
);
}
/**
* hphp_debug_caller_info - returns an array of info about the "caller"
*
* For clarity, we refer to the function that called hphp_debug_caller_info()
* as the "callee", and we refer to the function that called the callee as
* the "caller".
*
* This function returns an array containing two keys "file" and "line" which
* indicate the the filename and line number where the "caller" called the
* "callee".
*/
Array f_hphp_debug_caller_info() {
if (RuntimeOption::InjectedStackTrace) {
return g_vmContext->getCallerInfo();
}
return Array::Create();
}
void f_debug_print_backtrace(int64_t options /* = 0 */,
int64_t limit /* = 0 */) {
bool ignore_args = options & DEBUG_BACKTRACE_IGNORE_ARGS;
echo(debug_string_backtrace(true, ignore_args, limit));
}
const StaticString
s_class("class"),
s_type("type"),
s_function("function"),
s_file("file"),
s_line("line"),
s_message("message"),
s_args("args");
String debug_string_backtrace(bool skip, bool ignore_args /* = false */,
int limit /* = 0 */) {
if (RuntimeOption::InjectedStackTrace) {
Array bt;
StringBuffer buf;
bt = g_vmContext->debugBacktrace(skip, false, false, nullptr,
ignore_args, limit);
int i = 0;
for (ArrayIter it = bt.begin(); !it.end(); it.next(), i++) {
Array frame = it.second().toArray();
buf.append('#');
buf.append(i);
if (i < 10) buf.append(' ');
buf.append(' ');
if (frame.exists(s_class)) {
buf.append(frame->get(s_class).toString());
buf.append(frame->get(s_type).toString());
}
buf.append(frame->get(s_function).toString());
buf.append("(");
if (!ignore_args) {
bool first = true;
for (ArrayIter it = frame->get(s_args).begin(); !it.end(); it.next()) {
if (!first) {
buf.append(", ");
} else {
first = false;
}
buf.append(it.second().toString());
}
}
buf.append(")");
if (frame.exists(s_file)) {
buf.append(" called at [");
buf.append(frame->get(s_file).toString());
buf.append(':');
buf.append(frame->get(s_line).toString());
buf.append(']');
}
buf.append('\n');
}
return buf.detach();
} else {
StackTrace st;
return String(st.toString());
}
}
Array f_error_get_last() {
String lastError = g_context->getLastError();
if (lastError.isNull()) {
return (ArrayData *)NULL;
}
return CREATE_MAP2(s_message, g_context->getLastError(),
s_type, g_context->getLastErrorNumber());
}
bool f_error_log(CStrRef message, int message_type /* = 0 */,
CStrRef destination /* = null_string */,
CStrRef extra_headers /* = null_string */) {
// error_log() should not invoke the user error handler,
// so we use Logger::Error() instead of raise_warning() or raise_error()
switch (message_type) {
case 0:
{
std::string line(message.data(),
// Truncate to 512k
message.size() > (1<<19) ? (1<<19) : message.size());
Logger::Error(line);
if (!RuntimeOption::ServerExecutionMode() &&
Logger::UseLogFile && Logger::Output) {
// otherwise errors will go to error log without displaying on screen
std::cerr << line;
}
return true;
}
case 3:
{
Variant outfile = f_fopen(destination, "a"); // open for append only
if (outfile.isNull()) {
Logger::Error("can't open error_log file!\n");
return false;
}
f_fwrite(outfile.toResource(), message);
f_fclose(outfile.toResource());
return true;
}
case 2: // not used per PHP
default:
Logger::Error("error_log does not support message_type %d!", message_type);
break;
}
return false;
}
int64_t f_error_reporting(CVarRef level /* = null */) {
int oldErrorReportingLevel = g_context->getErrorReportingLevel();
if (!level.isNull()) {
g_context->setErrorReportingLevel(level.toInt32());
}
return oldErrorReportingLevel;
}
bool f_restore_error_handler() {
g_context->popUserErrorHandler();
return true;
}
bool f_restore_exception_handler() {
g_context->popUserExceptionHandler();
return false;
}
Variant f_set_error_handler(CVarRef error_handler,
int error_types /* = k_E_ALL */) {
return g_context->pushUserErrorHandler(error_handler, error_types);
}
Variant f_set_exception_handler(CVarRef exception_handler) {
return g_context->pushUserExceptionHandler(exception_handler);
}
void f_hphp_set_error_page(CStrRef page) {
g_context->setErrorPage(page);
}
void f_hphp_throw_fatal_error(CStrRef error_msg) {
std::string msg = error_msg.data();
raise_error(msg);
}
void f_hphp_clear_unflushed() {
g_context->obEndAll();
g_context->obStart();
g_context->obProtect(true);
}
bool f_trigger_error(CStrRef error_msg,
int error_type /* = k_E_USER_NOTICE */) {
std::string msg = error_msg.data();
if (g_context->getThrowAllErrors()) throw error_type;
if (error_type == k_E_USER_ERROR) {
g_context->handleError(msg, error_type, true,
ExecutionContext::ErrorThrowMode::IfUnhandled,
"HipHop Recoverable error: ");
} else if (error_type == k_E_USER_WARNING) {
g_context->handleError(msg, error_type, true,
ExecutionContext::ErrorThrowMode::Never,
"HipHop Warning: ");
} else if (error_type == k_E_USER_NOTICE) {
g_context->handleError(msg, error_type, true,
ExecutionContext::ErrorThrowMode::Never,
"HipHop Notice: ");
} else if (error_type == k_E_USER_DEPRECATED) {
g_context->handleError(msg, error_type, true,
ExecutionContext::ErrorThrowMode::Never,
"HipHop Deprecated: ");
} else {
return false;
}
return true;
}
bool f_user_error(CStrRef error_msg, int error_type /* = k_E_USER_NOTICE */) {
return f_trigger_error(error_msg, error_type);
}
const int64_t k_DEBUG_BACKTRACE_PROVIDE_OBJECT = 1;
const int64_t k_DEBUG_BACKTRACE_IGNORE_ARGS = 2;
///////////////////////////////////////////////////////////////////////////////
}