Commit 73a4ecfa authored by ager@chromium.org's avatar ager@chromium.org

A MessageObject is a purely internal object to hold information about

an error message that needs to be generated and reported. This change
hides all of the error information from JavaScript code so user
callbacks cannot get hold of it.

Review URL: http://codereview.chromium.org/6368051

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6574 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent a5f94a48
...@@ -3448,7 +3448,7 @@ class Internals { ...@@ -3448,7 +3448,7 @@ class Internals {
static const int kFullStringRepresentationMask = 0x07; static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02; static const int kExternalTwoByteRepresentationTag = 0x02;
static const int kJSObjectType = 0x9f; static const int kJSObjectType = 0xa0;
static const int kFirstNonstringType = 0x80; static const int kFirstNonstringType = 0x80;
static const int kProxyType = 0x85; static const int kProxyType = 0x85;
......
...@@ -1478,11 +1478,11 @@ v8::Handle<Value> Message::GetScriptResourceName() const { ...@@ -1478,11 +1478,11 @@ v8::Handle<Value> Message::GetScriptResourceName() const {
} }
ENTER_V8; ENTER_V8;
HandleScope scope; HandleScope scope;
i::Handle<i::JSObject> obj = i::Handle<i::JSMessageObject> message =
i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
// Return this.script.name. // Return this.script.name.
i::Handle<i::JSValue> script = i::Handle<i::JSValue> script =
i::Handle<i::JSValue>::cast(GetProperty(obj, "script")); i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script()));
i::Handle<i::Object> resource_name(i::Script::cast(script->value())->name()); i::Handle<i::Object> resource_name(i::Script::cast(script->value())->name());
return scope.Close(Utils::ToLocal(resource_name)); return scope.Close(Utils::ToLocal(resource_name));
} }
...@@ -1494,11 +1494,11 @@ v8::Handle<Value> Message::GetScriptData() const { ...@@ -1494,11 +1494,11 @@ v8::Handle<Value> Message::GetScriptData() const {
} }
ENTER_V8; ENTER_V8;
HandleScope scope; HandleScope scope;
i::Handle<i::JSObject> obj = i::Handle<i::JSMessageObject> message =
i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
// Return this.script.data. // Return this.script.data.
i::Handle<i::JSValue> script = i::Handle<i::JSValue> script =
i::Handle<i::JSValue>::cast(GetProperty(obj, "script")); i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script()));
i::Handle<i::Object> data(i::Script::cast(script->value())->data()); i::Handle<i::Object> data(i::Script::cast(script->value())->data());
return scope.Close(Utils::ToLocal(data)); return scope.Close(Utils::ToLocal(data));
} }
...@@ -1510,9 +1510,9 @@ v8::Handle<v8::StackTrace> Message::GetStackTrace() const { ...@@ -1510,9 +1510,9 @@ v8::Handle<v8::StackTrace> Message::GetStackTrace() const {
} }
ENTER_V8; ENTER_V8;
HandleScope scope; HandleScope scope;
i::Handle<i::JSObject> obj = i::Handle<i::JSMessageObject> message =
i::Handle<i::JSObject>::cast(Utils::OpenHandle(this)); i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
i::Handle<i::Object> stackFramesObj = GetProperty(obj, "stackFrames"); i::Handle<i::Object> stackFramesObj(message->stack_frames());
if (!stackFramesObj->IsJSArray()) return v8::Handle<v8::StackTrace>(); if (!stackFramesObj->IsJSArray()) return v8::Handle<v8::StackTrace>();
i::Handle<i::JSArray> stackTrace = i::Handle<i::JSArray> stackTrace =
i::Handle<i::JSArray>::cast(stackFramesObj); i::Handle<i::JSArray>::cast(stackFramesObj);
...@@ -1552,6 +1552,7 @@ int Message::GetLineNumber() const { ...@@ -1552,6 +1552,7 @@ int Message::GetLineNumber() const {
ON_BAILOUT("v8::Message::GetLineNumber()", return kNoLineNumberInfo); ON_BAILOUT("v8::Message::GetLineNumber()", return kNoLineNumberInfo);
ENTER_V8; ENTER_V8;
HandleScope scope; HandleScope scope;
EXCEPTION_PREAMBLE(); EXCEPTION_PREAMBLE();
i::Handle<i::Object> result = CallV8HeapFunction("GetLineNumber", i::Handle<i::Object> result = CallV8HeapFunction("GetLineNumber",
Utils::OpenHandle(this), Utils::OpenHandle(this),
...@@ -1565,9 +1566,9 @@ int Message::GetStartPosition() const { ...@@ -1565,9 +1566,9 @@ int Message::GetStartPosition() const {
if (IsDeadCheck("v8::Message::GetStartPosition()")) return 0; if (IsDeadCheck("v8::Message::GetStartPosition()")) return 0;
ENTER_V8; ENTER_V8;
HandleScope scope; HandleScope scope;
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this); i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
return static_cast<int>(GetProperty(data_obj, "startPos")->Number()); return message->start_position();
} }
...@@ -1575,8 +1576,9 @@ int Message::GetEndPosition() const { ...@@ -1575,8 +1576,9 @@ int Message::GetEndPosition() const {
if (IsDeadCheck("v8::Message::GetEndPosition()")) return 0; if (IsDeadCheck("v8::Message::GetEndPosition()")) return 0;
ENTER_V8; ENTER_V8;
HandleScope scope; HandleScope scope;
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this); i::Handle<i::JSMessageObject> message =
return static_cast<int>(GetProperty(data_obj, "endPos")->Number()); i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
return message->end_position();
} }
...@@ -1606,8 +1608,10 @@ int Message::GetEndColumn() const { ...@@ -1606,8 +1608,10 @@ int Message::GetEndColumn() const {
data_obj, data_obj,
&has_pending_exception); &has_pending_exception);
EXCEPTION_BAILOUT_CHECK(0); EXCEPTION_BAILOUT_CHECK(0);
int start = static_cast<int>(GetProperty(data_obj, "startPos")->Number()); i::Handle<i::JSMessageObject> message =
int end = static_cast<int>(GetProperty(data_obj, "endPos")->Number()); i::Handle<i::JSMessageObject>::cast(data_obj);
int start = message->start_position();
int end = message->end_position();
return static_cast<int>(start_col_obj->Number()) + (end - start); return static_cast<int>(start_col_obj->Number()) + (end - start);
} }
......
...@@ -1050,7 +1050,6 @@ void Genesis::InstallNativeFunctions() { ...@@ -1050,7 +1050,6 @@ void Genesis::InstallNativeFunctions() {
INSTALL_NATIVE(JSFunction, "Instantiate", instantiate_fun); INSTALL_NATIVE(JSFunction, "Instantiate", instantiate_fun);
INSTALL_NATIVE(JSFunction, "ConfigureTemplateInstance", INSTALL_NATIVE(JSFunction, "ConfigureTemplateInstance",
configure_instance_fun); configure_instance_fun);
INSTALL_NATIVE(JSFunction, "MakeMessage", make_message_fun);
INSTALL_NATIVE(JSFunction, "GetStackTraceLine", get_stack_trace_line_fun); INSTALL_NATIVE(JSFunction, "GetStackTraceLine", get_stack_trace_line_fun);
INSTALL_NATIVE(JSObject, "functionCache", function_cache); INSTALL_NATIVE(JSObject, "functionCache", function_cache);
} }
......
...@@ -755,6 +755,24 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo( ...@@ -755,6 +755,24 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
} }
Handle<JSMessageObject> Factory::NewJSMessageObject(
Handle<String> type,
Handle<JSArray> arguments,
int start_position,
int end_position,
Handle<Object> script,
Handle<Object> stack_trace,
Handle<Object> stack_frames) {
CALL_HEAP_FUNCTION(Heap::AllocateJSMessageObject(*type,
*arguments,
start_position,
end_position,
*script,
*stack_trace,
*stack_frames),
JSMessageObject);
}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) { Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) {
CALL_HEAP_FUNCTION(Heap::AllocateSharedFunctionInfo(*name), CALL_HEAP_FUNCTION(Heap::AllocateSharedFunctionInfo(*name),
SharedFunctionInfo); SharedFunctionInfo);
......
...@@ -365,6 +365,15 @@ class Factory : public AllStatic { ...@@ -365,6 +365,15 @@ class Factory : public AllStatic {
Handle<SerializedScopeInfo> scope_info); Handle<SerializedScopeInfo> scope_info);
static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name); static Handle<SharedFunctionInfo> NewSharedFunctionInfo(Handle<String> name);
static Handle<JSMessageObject> NewJSMessageObject(
Handle<String> type,
Handle<JSArray> arguments,
int start_position,
int end_position,
Handle<Object> script,
Handle<Object> stack_trace,
Handle<Object> stack_frames);
static Handle<NumberDictionary> DictionaryAtNumberPut( static Handle<NumberDictionary> DictionaryAtNumberPut(
Handle<NumberDictionary>, Handle<NumberDictionary>,
uint32_t key, uint32_t key,
......
...@@ -1826,6 +1826,12 @@ bool Heap::CreateInitialMaps() { ...@@ -1826,6 +1826,12 @@ bool Heap::CreateInitialMaps() {
} }
set_shared_function_info_map(Map::cast(obj)); set_shared_function_info_map(Map::cast(obj));
{ MaybeObject* maybe_obj = AllocateMap(JS_MESSAGE_OBJECT_TYPE,
JSMessageObject::kSize);
if (!maybe_obj->ToObject(&obj)) return false;
}
set_message_object_map(Map::cast(obj));
ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array())); ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));
return true; return true;
} }
...@@ -2329,6 +2335,32 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) { ...@@ -2329,6 +2335,32 @@ MaybeObject* Heap::AllocateSharedFunctionInfo(Object* name) {
} }
MaybeObject* Heap::AllocateJSMessageObject(String* type,
JSArray* arguments,
int start_position,
int end_position,
Object* script,
Object* stack_trace,
Object* stack_frames) {
Object* result;
{ MaybeObject* maybe_result = Allocate(message_object_map(), NEW_SPACE);
if (!maybe_result->ToObject(&result)) return maybe_result;
}
JSMessageObject* message = JSMessageObject::cast(result);
message->set_properties(Heap::empty_fixed_array());
message->set_elements(Heap::empty_fixed_array());
message->set_type(type);
message->set_arguments(arguments);
message->set_start_position(start_position);
message->set_end_position(end_position);
message->set_script(script);
message->set_stack_trace(stack_trace);
message->set_stack_frames(stack_frames);
return result;
}
// Returns true for a character in a range. Both limits are inclusive. // Returns true for a character in a range. Both limits are inclusive.
static inline bool Between(uint32_t character, uint32_t from, uint32_t to) { static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
// This makes uses of the the unsigned wraparound. // This makes uses of the the unsigned wraparound.
......
...@@ -94,6 +94,7 @@ namespace internal { ...@@ -94,6 +94,7 @@ namespace internal {
V(Map, oddball_map, OddballMap) \ V(Map, oddball_map, OddballMap) \
V(Map, global_property_cell_map, GlobalPropertyCellMap) \ V(Map, global_property_cell_map, GlobalPropertyCellMap) \
V(Map, shared_function_info_map, SharedFunctionInfoMap) \ V(Map, shared_function_info_map, SharedFunctionInfoMap) \
V(Map, message_object_map, JSMessageObjectMap) \
V(Map, proxy_map, ProxyMap) \ V(Map, proxy_map, ProxyMap) \
V(Object, nan_value, NanValue) \ V(Object, nan_value, NanValue) \
V(Object, minus_zero_value, MinusZeroValue) \ V(Object, minus_zero_value, MinusZeroValue) \
...@@ -628,6 +629,19 @@ class Heap : public AllStatic { ...@@ -628,6 +629,19 @@ class Heap : public AllStatic {
// Please note this does not perform a garbage collection. // Please note this does not perform a garbage collection.
MUST_USE_RESULT static MaybeObject* AllocateSharedFunctionInfo(Object* name); MUST_USE_RESULT static MaybeObject* AllocateSharedFunctionInfo(Object* name);
// Allocates a new JSMessageObject object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note that this does not perform a garbage collection.
MUST_USE_RESULT static MaybeObject* AllocateJSMessageObject(
String* type,
JSArray* arguments,
int start_position,
int end_position,
Object* script,
Object* stack_trace,
Object* stack_frames);
// Allocates a new cons string object. // Allocates a new cons string object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed. // failed.
......
...@@ -62,67 +62,45 @@ void MessageHandler::ReportMessage(const char* msg) { ...@@ -62,67 +62,45 @@ void MessageHandler::ReportMessage(const char* msg) {
} }
Handle<Object> MessageHandler::MakeMessageObject( Handle<JSMessageObject> MessageHandler::MakeMessageObject(
const char* type, const char* type,
MessageLocation* loc, MessageLocation* loc,
Vector< Handle<Object> > args, Vector< Handle<Object> > args,
Handle<String> stack_trace, Handle<String> stack_trace,
Handle<JSArray> stack_frames) { Handle<JSArray> stack_frames) {
// Build error message object Handle<String> type_handle = Factory::LookupAsciiSymbol(type);
v8::HandleScope scope; // Instantiate a closeable HandleScope for EscapeFrom. Handle<JSArray> arguments_handle = Factory::NewJSArray(args.length());
Handle<Object> type_str = Factory::LookupAsciiSymbol(type); for (int i = 0; i < args.length(); i++) {
Handle<Object> array = Factory::NewJSArray(args.length()); SetElement(arguments_handle, i, args[i]);
for (int i = 0; i < args.length(); i++) }
SetElement(Handle<JSArray>::cast(array), i, args[i]);
int start = 0;
Handle<JSFunction> fun(Top::global_context()->make_message_fun()); int end = 0;
int start, end; Handle<Object> script_handle = Factory::undefined_value();
Handle<Object> script;
if (loc) { if (loc) {
start = loc->start_pos(); start = loc->start_pos();
end = loc->end_pos(); end = loc->end_pos();
script = GetScriptWrapper(loc->script()); script_handle = GetScriptWrapper(loc->script());
} else {
start = end = 0;
script = Factory::undefined_value();
} }
Handle<Object> start_handle(Smi::FromInt(start));
Handle<Object> end_handle(Smi::FromInt(end)); Handle<Object> stack_trace_handle = stack_trace.is_null()
Handle<Object> stack_trace_val = stack_trace.is_null() ? Factory::undefined_value()
? Factory::undefined_value() : Handle<Object>::cast(stack_trace);
: Handle<Object>::cast(stack_trace);
Handle<Object> stack_frames_val = stack_frames.is_null() Handle<Object> stack_frames_handle = stack_frames.is_null()
? Factory::undefined_value() ? Factory::undefined_value()
: Handle<Object>::cast(stack_frames); : Handle<Object>::cast(stack_frames);
const int argc = 7;
Object** argv[argc] = { type_str.location(), Handle<JSMessageObject> message =
array.location(), Factory::NewJSMessageObject(type_handle,
start_handle.location(), arguments_handle,
end_handle.location(), start,
script.location(), end,
stack_trace_val.location(), script_handle,
stack_frames_val.location() }; stack_trace_handle,
stack_frames_handle);
// Setup a catch handler to catch exceptions in creating the message. This
// handler is non-verbose to avoid calling MakeMessage recursively in case of return message;
// an exception.
v8::TryCatch catcher;
catcher.SetVerbose(false);
catcher.SetCaptureMessage(false);
// Format the message.
bool caught_exception = false;
Handle<Object> message =
Execution::Call(fun, Factory::undefined_value(), argc, argv,
&caught_exception);
// If creating the message (in JS code) resulted in an exception, we
// skip doing the callback. This usually only happens in case of
// stack overflow exceptions being thrown by the parser when the
// stack is almost full.
if (caught_exception) return Handle<Object>();
return message.EscapeFrom(&scope);
} }
......
...@@ -93,11 +93,12 @@ class MessageHandler { ...@@ -93,11 +93,12 @@ class MessageHandler {
static void ReportMessage(const char* msg); static void ReportMessage(const char* msg);
// Returns a message object for the API to use. // Returns a message object for the API to use.
static Handle<Object> MakeMessageObject(const char* type, static Handle<JSMessageObject> MakeMessageObject(
MessageLocation* loc, const char* type,
Vector< Handle<Object> > args, MessageLocation* loc,
Handle<String> stack_trace, Vector< Handle<Object> > args,
Handle<JSArray> stack_frames); Handle<String> stack_trace,
Handle<JSArray> stack_frames);
// Report a formatted message (needs JS allocation). // Report a formatted message (needs JS allocation).
static void ReportMessage(MessageLocation* loc, Handle<Object> message); static void ReportMessage(MessageLocation* loc, Handle<Object> message);
......
...@@ -55,7 +55,8 @@ var kMessages = 0; ...@@ -55,7 +55,8 @@ var kMessages = 0;
var kReplacementMarkers = var kReplacementMarkers =
[ "%0", "%1", "%2", "%3" ] [ "%0", "%1", "%2", "%3" ]
function FormatString(format, args) { function FormatString(format, message) {
var args = %MessageGetArguments(message);
var result = ""; var result = "";
var arg_num = 0; var arg_num = 0;
for (var i = 0; i < format.length; i++) { for (var i = 0; i < format.length; i++) {
...@@ -227,15 +228,18 @@ function FormatMessage(message) { ...@@ -227,15 +228,18 @@ function FormatMessage(message) {
strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"], strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
}; };
} }
var format = kMessages[message.type]; var message_type = %MessageGetType(message);
if (!format) return "<unknown message " + message.type + ">"; var format = kMessages[message_type];
return FormatString(format, message.args); if (!format) return "<unknown message " + message_type + ">";
return FormatString(format, message);
} }
function GetLineNumber(message) { function GetLineNumber(message) {
if (message.startPos == -1) return kNoLineNumberInfo; var start_position = %MessageGetStartPosition(message);
var location = message.script.locationFromPosition(message.startPos, true); if (start_position == -1) return kNoLineNumberInfo;
var script = %MessageGetScript(message);
var location = script.locationFromPosition(start_position, true);
if (location == null) return kNoLineNumberInfo; if (location == null) return kNoLineNumberInfo;
return location.line + 1; return location.line + 1;
} }
...@@ -244,7 +248,9 @@ function GetLineNumber(message) { ...@@ -244,7 +248,9 @@ function GetLineNumber(message) {
// Returns the source code line containing the given source // Returns the source code line containing the given source
// position, or the empty string if the position is invalid. // position, or the empty string if the position is invalid.
function GetSourceLine(message) { function GetSourceLine(message) {
var location = message.script.locationFromPosition(message.startPos, true); var script = %MessageGetScript(message);
var start_position = %MessageGetStartPosition(message);
var location = script.locationFromPosition(start_position, true);
if (location == null) return ""; if (location == null) return "";
location.restrict(); location.restrict();
return location.sourceText(); return location.sourceText();
...@@ -623,29 +629,12 @@ SourceSlice.prototype.sourceText = function () { ...@@ -623,29 +629,12 @@ SourceSlice.prototype.sourceText = function () {
// Returns the offset of the given position within the containing // Returns the offset of the given position within the containing
// line. // line.
function GetPositionInLine(message) { function GetPositionInLine(message) {
var location = message.script.locationFromPosition(message.startPos, false); var script = %MessageGetScript(message);
var start_position = %MessageGetStartPosition(message);
var location = script.locationFromPosition(start_position, false);
if (location == null) return -1; if (location == null) return -1;
location.restrict(); location.restrict();
return message.startPos - location.start; return start_position - location.start;
}
function ErrorMessage(type, args, startPos, endPos, script, stackTrace,
stackFrames) {
this.startPos = startPos;
this.endPos = endPos;
this.type = type;
this.args = args;
this.script = script;
this.stackTrace = stackTrace;
this.stackFrames = stackFrames;
}
function MakeMessage(type, args, startPos, endPos, script, stackTrace,
stackFrames) {
return new ErrorMessage(type, args, startPos, endPos, script, stackTrace,
stackFrames);
} }
...@@ -992,7 +981,7 @@ function DefineError(f) { ...@@ -992,7 +981,7 @@ function DefineError(f) {
// DefineOneShotAccessor always inserts a message property and // DefineOneShotAccessor always inserts a message property and
// ignores setters. // ignores setters.
DefineOneShotAccessor(this, 'message', function (obj) { DefineOneShotAccessor(this, 'message', function (obj) {
return FormatMessage({type: obj.type, args: obj.arguments}); return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
}); });
} else if (!IS_UNDEFINED(m)) { } else if (!IS_UNDEFINED(m)) {
%IgnoreAttributesAndSetProperty(this, 'message', ToString(m)); %IgnoreAttributesAndSetProperty(this, 'message', ToString(m));
...@@ -1006,11 +995,12 @@ function DefineError(f) { ...@@ -1006,11 +995,12 @@ function DefineError(f) {
function captureStackTrace(obj, cons_opt) { function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit; var stackTraceLimit = $Error.stackTraceLimit;
if (!stackTraceLimit) return; if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
if (stackTraceLimit < 0 || stackTraceLimit > 10000) if (stackTraceLimit < 0 || stackTraceLimit > 10000)
stackTraceLimit = 10000; stackTraceLimit = 10000;
var raw_stack = %CollectStackTrace(cons_opt ? cons_opt : captureStackTrace, var raw_stack = %CollectStackTrace(cons_opt
stackTraceLimit); ? cons_opt
: captureStackTrace, stackTraceLimit);
DefineOneShotAccessor(obj, 'stack', function (obj) { DefineOneShotAccessor(obj, 'stack', function (obj) {
return FormatRawStackTrace(obj, raw_stack); return FormatRawStackTrace(obj, raw_stack);
}); });
...@@ -1041,7 +1031,7 @@ function errorToStringDetectCycle() { ...@@ -1041,7 +1031,7 @@ function errorToStringDetectCycle() {
try { try {
var type = this.type; var type = this.type;
if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) { if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) {
var formatted = FormatMessage({ type: type, args: this.arguments }); var formatted = FormatMessage(%NewMessageObject(type, this.arguments));
return this.name + ": " + formatted; return this.name + ": " + formatted;
} }
var message = %_CallFunction(this, "message", ObjectHasOwnProperty) var message = %_CallFunction(this, "message", ObjectHasOwnProperty)
......
...@@ -158,6 +158,9 @@ void HeapObject::HeapObjectVerify() { ...@@ -158,6 +158,9 @@ void HeapObject::HeapObjectVerify() {
case SHARED_FUNCTION_INFO_TYPE: case SHARED_FUNCTION_INFO_TYPE:
SharedFunctionInfo::cast(this)->SharedFunctionInfoVerify(); SharedFunctionInfo::cast(this)->SharedFunctionInfoVerify();
break; break;
case JS_MESSAGE_OBJECT_TYPE:
JSMessageObject::cast(this)->JSMessageObjectVerify();
break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \ #define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \ case NAME##_TYPE: \
...@@ -296,6 +299,19 @@ void JSValue::JSValueVerify() { ...@@ -296,6 +299,19 @@ void JSValue::JSValueVerify() {
} }
void JSMessageObject::JSMessageObjectVerify() {
CHECK(IsJSMessageObject());
CHECK(type()->IsString());
CHECK(arguments()->IsJSArray());
VerifyObjectField(kStartPositionOffset);
VerifyObjectField(kEndPositionOffset);
VerifyObjectField(kArgumentsOffset);
VerifyObjectField(kScriptOffset);
VerifyObjectField(kStackTraceOffset);
VerifyObjectField(kStackFramesOffset);
}
void String::StringVerify() { void String::StringVerify() {
CHECK(IsString()); CHECK(IsString());
CHECK(length() >= 0 && length() <= Smi::kMaxValue); CHECK(length() >= 0 && length() <= Smi::kMaxValue);
......
...@@ -408,7 +408,7 @@ bool MaybeObject::IsRetryAfterGC() { ...@@ -408,7 +408,7 @@ bool MaybeObject::IsRetryAfterGC() {
bool MaybeObject::IsOutOfMemory() { bool MaybeObject::IsOutOfMemory() {
return HAS_FAILURE_TAG(this) return HAS_FAILURE_TAG(this)
&& Failure::cast(this)->IsOutOfMemoryException(); && Failure::cast(this)->IsOutOfMemoryException();
} }
...@@ -430,26 +430,26 @@ Failure* Failure::cast(MaybeObject* obj) { ...@@ -430,26 +430,26 @@ Failure* Failure::cast(MaybeObject* obj) {
bool Object::IsJSObject() { bool Object::IsJSObject() {
return IsHeapObject() return IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() >= FIRST_JS_OBJECT_TYPE; && HeapObject::cast(this)->map()->instance_type() >= FIRST_JS_OBJECT_TYPE;
} }
bool Object::IsJSContextExtensionObject() { bool Object::IsJSContextExtensionObject() {
return IsHeapObject() return IsHeapObject()
&& (HeapObject::cast(this)->map()->instance_type() == && (HeapObject::cast(this)->map()->instance_type() ==
JS_CONTEXT_EXTENSION_OBJECT_TYPE); JS_CONTEXT_EXTENSION_OBJECT_TYPE);
} }
bool Object::IsMap() { bool Object::IsMap() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == MAP_TYPE; && HeapObject::cast(this)->map()->instance_type() == MAP_TYPE;
} }
bool Object::IsFixedArray() { bool Object::IsFixedArray() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == FIXED_ARRAY_TYPE; && HeapObject::cast(this)->map()->instance_type() == FIXED_ARRAY_TYPE;
} }
...@@ -495,19 +495,19 @@ bool Object::IsContext() { ...@@ -495,19 +495,19 @@ bool Object::IsContext() {
bool Object::IsCatchContext() { bool Object::IsCatchContext() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map() == Heap::catch_context_map(); && HeapObject::cast(this)->map() == Heap::catch_context_map();
} }
bool Object::IsGlobalContext() { bool Object::IsGlobalContext() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map() == Heap::global_context_map(); && HeapObject::cast(this)->map() == Heap::global_context_map();
} }
bool Object::IsJSFunction() { bool Object::IsJSFunction() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE; && HeapObject::cast(this)->map()->instance_type() == JS_FUNCTION_TYPE;
} }
...@@ -518,7 +518,7 @@ template <> inline bool Is<JSFunction>(Object* obj) { ...@@ -518,7 +518,7 @@ template <> inline bool Is<JSFunction>(Object* obj) {
bool Object::IsCode() { bool Object::IsCode() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == CODE_TYPE; && HeapObject::cast(this)->map()->instance_type() == CODE_TYPE;
} }
...@@ -544,7 +544,14 @@ bool Object::IsSharedFunctionInfo() { ...@@ -544,7 +544,14 @@ bool Object::IsSharedFunctionInfo() {
bool Object::IsJSValue() { bool Object::IsJSValue() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == JS_VALUE_TYPE; && HeapObject::cast(this)->map()->instance_type() == JS_VALUE_TYPE;
}
bool Object::IsJSMessageObject() {
return Object::IsHeapObject()
&& (HeapObject::cast(this)->map()->instance_type() ==
JS_MESSAGE_OBJECT_TYPE);
} }
...@@ -555,7 +562,7 @@ bool Object::IsStringWrapper() { ...@@ -555,7 +562,7 @@ bool Object::IsStringWrapper() {
bool Object::IsProxy() { bool Object::IsProxy() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE; && HeapObject::cast(this)->map()->instance_type() == PROXY_TYPE;
} }
...@@ -566,13 +573,13 @@ bool Object::IsBoolean() { ...@@ -566,13 +573,13 @@ bool Object::IsBoolean() {
bool Object::IsJSArray() { bool Object::IsJSArray() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE; && HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE;
} }
bool Object::IsJSRegExp() { bool Object::IsJSRegExp() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == JS_REGEXP_TYPE; && HeapObject::cast(this)->map()->instance_type() == JS_REGEXP_TYPE;
} }
...@@ -583,7 +590,7 @@ template <> inline bool Is<JSArray>(Object* obj) { ...@@ -583,7 +590,7 @@ template <> inline bool Is<JSArray>(Object* obj) {
bool Object::IsHashTable() { bool Object::IsHashTable() {
return Object::IsHeapObject() return Object::IsHeapObject()
&& HeapObject::cast(this)->map() == Heap::hash_table_map(); && HeapObject::cast(this)->map() == Heap::hash_table_map();
} }
...@@ -1285,6 +1292,8 @@ int JSObject::GetHeaderSize() { ...@@ -1285,6 +1292,8 @@ int JSObject::GetHeaderSize() {
return JSValue::kSize; return JSValue::kSize;
case JS_CONTEXT_EXTENSION_OBJECT_TYPE: case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
return JSObject::kHeaderSize; return JSObject::kHeaderSize;
case JS_MESSAGE_OBJECT_TYPE:
return JSMessageObject::kSize;
default: default:
UNREACHABLE(); UNREACHABLE();
return 0; return 0;
...@@ -3289,6 +3298,22 @@ JSValue* JSValue::cast(Object* obj) { ...@@ -3289,6 +3298,22 @@ JSValue* JSValue::cast(Object* obj) {
} }
ACCESSORS(JSMessageObject, type, String, kTypeOffset)
ACCESSORS(JSMessageObject, arguments, JSArray, kArgumentsOffset)
ACCESSORS(JSMessageObject, script, Object, kScriptOffset)
ACCESSORS(JSMessageObject, stack_trace, Object, kStackTraceOffset)
ACCESSORS(JSMessageObject, stack_frames, Object, kStackFramesOffset)
SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset)
SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset)
JSMessageObject* JSMessageObject::cast(Object* obj) {
ASSERT(obj->IsJSMessageObject());
ASSERT(HeapObject::cast(obj)->Size() == JSMessageObject::kSize);
return reinterpret_cast<JSMessageObject*>(obj);
}
INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset) INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset)
ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset) ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset)
ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset) ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset)
......
...@@ -151,6 +151,9 @@ void HeapObject::HeapObjectPrint(FILE* out) { ...@@ -151,6 +151,9 @@ void HeapObject::HeapObjectPrint(FILE* out) {
case SHARED_FUNCTION_INFO_TYPE: case SHARED_FUNCTION_INFO_TYPE:
SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out); SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out);
break; break;
case JS_MESSAGE_OBJECT_TYPE:
JSMessageObject::cast(this)->JSMessageObjectPrint(out);
break;
case JS_GLOBAL_PROPERTY_CELL_TYPE: case JS_GLOBAL_PROPERTY_CELL_TYPE:
JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out); JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out);
break; break;
...@@ -396,6 +399,7 @@ static const char* TypeToString(InstanceType type) { ...@@ -396,6 +399,7 @@ static const char* TypeToString(InstanceType type) {
case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY"; case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY";
case PROXY_TYPE: return "PROXY"; case PROXY_TYPE: return "PROXY";
case LAST_STRING_TYPE: return "LAST_STRING_TYPE"; case LAST_STRING_TYPE: return "LAST_STRING_TYPE";
case JS_MESSAGE_OBJECT_TYPE: return "JS_MESSAGE_OBJECT_TYPE";
#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME; #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: return #NAME;
STRUCT_LIST(MAKE_STRUCT_CASE) STRUCT_LIST(MAKE_STRUCT_CASE)
#undef MAKE_STRUCT_CASE #undef MAKE_STRUCT_CASE
...@@ -466,6 +470,24 @@ void JSValue::JSValuePrint(FILE* out) { ...@@ -466,6 +470,24 @@ void JSValue::JSValuePrint(FILE* out) {
} }
void JSMessageObject::JSMessageObjectPrint(FILE* out) {
HeapObject::PrintHeader(out, "JSMessageObject");
PrintF(out, " - type: ");
type()->ShortPrint(out);
PrintF(out, "\n - arguments: ");
arguments()->ShortPrint(out);
PrintF(out, "\n - start_position: %d", start_position());
PrintF(out, "\n - end_position: %d", end_position());
PrintF(out, "\n - script: ");
script()->ShortPrint(out);
PrintF(out, "\n - stack_trace: ");
stack_trace()->ShortPrint(out);
PrintF(out, "\n - stack_frames: ");
stack_frames()->ShortPrint(out);
PrintF(out, "\n");
}
void String::StringPrint(FILE* out) { void String::StringPrint(FILE* out) {
if (StringShape(this).IsSymbol()) { if (StringShape(this).IsSymbol()) {
PrintF(out, "#"); PrintF(out, "#");
......
...@@ -104,6 +104,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( ...@@ -104,6 +104,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case JS_GLOBAL_PROXY_TYPE: case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE: case JS_GLOBAL_OBJECT_TYPE:
case JS_BUILTINS_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
return GetVisitorIdForSize(kVisitJSObject, return GetVisitorIdForSize(kVisitJSObject,
kVisitJSObjectGeneric, kVisitJSObjectGeneric,
instance_size); instance_size);
......
...@@ -979,6 +979,9 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { ...@@ -979,6 +979,9 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
case SHARED_FUNCTION_INFO_TYPE: case SHARED_FUNCTION_INFO_TYPE:
accumulator->Add("<SharedFunctionInfo>"); accumulator->Add("<SharedFunctionInfo>");
break; break;
case JS_MESSAGE_OBJECT_TYPE:
accumulator->Add("<JSMessageObject>");
break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \ #define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \ case NAME##_TYPE: \
accumulator->Put('<'); \ accumulator->Put('<'); \
...@@ -1069,6 +1072,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size, ...@@ -1069,6 +1072,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case JS_GLOBAL_PROXY_TYPE: case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE: case JS_GLOBAL_OBJECT_TYPE:
case JS_BUILTINS_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
JSObject::BodyDescriptor::IterateBody(this, object_size, v); JSObject::BodyDescriptor::IterateBody(this, object_size, v);
break; break;
case JS_FUNCTION_TYPE: case JS_FUNCTION_TYPE:
......
...@@ -54,7 +54,8 @@ ...@@ -54,7 +54,8 @@
// - JSGlobalObject // - JSGlobalObject
// - JSBuiltinsObject // - JSBuiltinsObject
// - JSGlobalProxy // - JSGlobalProxy
// - JSValue // - JSValue
// - JSMessageObject
// - ByteArray // - ByteArray
// - PixelArray // - PixelArray
// - ExternalArray // - ExternalArray
...@@ -288,6 +289,8 @@ static const int kVariableSizeSentinel = 0; ...@@ -288,6 +289,8 @@ static const int kVariableSizeSentinel = 0;
V(FIXED_ARRAY_TYPE) \ V(FIXED_ARRAY_TYPE) \
V(SHARED_FUNCTION_INFO_TYPE) \ V(SHARED_FUNCTION_INFO_TYPE) \
\ \
V(JS_MESSAGE_OBJECT_TYPE) \
\
V(JS_VALUE_TYPE) \ V(JS_VALUE_TYPE) \
V(JS_OBJECT_TYPE) \ V(JS_OBJECT_TYPE) \
V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \ V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
...@@ -518,6 +521,8 @@ enum InstanceType { ...@@ -518,6 +521,8 @@ enum InstanceType {
FIXED_ARRAY_TYPE, FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE, SHARED_FUNCTION_INFO_TYPE,
JS_MESSAGE_OBJECT_TYPE,
JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE
JS_OBJECT_TYPE, JS_OBJECT_TYPE,
JS_CONTEXT_EXTENSION_OBJECT_TYPE, JS_CONTEXT_EXTENSION_OBJECT_TYPE,
...@@ -675,6 +680,7 @@ class MaybeObject BASE_EMBEDDED { ...@@ -675,6 +680,7 @@ class MaybeObject BASE_EMBEDDED {
V(Oddball) \ V(Oddball) \
V(SharedFunctionInfo) \ V(SharedFunctionInfo) \
V(JSValue) \ V(JSValue) \
V(JSMessageObject) \
V(StringWrapper) \ V(StringWrapper) \
V(Proxy) \ V(Proxy) \
V(Boolean) \ V(Boolean) \
...@@ -4696,6 +4702,68 @@ class JSValue: public JSObject { ...@@ -4696,6 +4702,68 @@ class JSValue: public JSObject {
DISALLOW_IMPLICIT_CONSTRUCTORS(JSValue); DISALLOW_IMPLICIT_CONSTRUCTORS(JSValue);
}; };
// Representation of message objects used for error reporting through
// the API. The messages are formatted in JavaScript so this object is
// a real JavaScript object. The information used for formatting the
// error messages are not directly accessible from JavaScript to
// prevent leaking information to user code called during error
// formatting.
class JSMessageObject: public JSObject {
public:
// [type]: the type of error message.
DECL_ACCESSORS(type, String)
// [arguments]: the arguments for formatting the error message.
DECL_ACCESSORS(arguments, JSArray)
// [script]: the script from which the error message originated.
DECL_ACCESSORS(script, Object)
// [stack_trace]: the stack trace for this error message.
DECL_ACCESSORS(stack_trace, Object)
// [stack_frames]: an array of stack frames for this error object.
DECL_ACCESSORS(stack_frames, Object)
// [start_position]: the start position in the script for the error message.
inline int start_position();
inline void set_start_position(int value);
// [end_position]: the end position in the script for the error message.
inline int end_position();
inline void set_end_position(int value);
// Casting.
static inline JSMessageObject* cast(Object* obj);
// Dispatched behavior.
#ifdef OBJECT_PRINT
inline void JSMessageObjectPrint() {
JSMessageObjectPrint(stdout);
}
void JSMessageObjectPrint(FILE* out);
#endif
#ifdef DEBUG
void JSMessageObjectVerify();
#endif
// Layout description.
static const int kTypeOffset = JSObject::kHeaderSize;
static const int kArgumentsOffset = kTypeOffset + kPointerSize;
static const int kScriptOffset = kArgumentsOffset + kPointerSize;
static const int kStackTraceOffset = kScriptOffset + kPointerSize;
static const int kStackFramesOffset = kStackTraceOffset + kPointerSize;
static const int kStartPositionOffset = kStackFramesOffset + kPointerSize;
static const int kEndPositionOffset = kStartPositionOffset + kPointerSize;
static const int kSize = kEndPositionOffset + kPointerSize;
typedef FixedBodyDescriptor<HeapObject::kMapOffset,
kStackFramesOffset + kPointerSize,
kSize> BodyDescriptor;
};
// Regular expressions // Regular expressions
// The regular expression holds a single reference to a FixedArray in // The regular expression holds a single reference to a FixedArray in
// the kDataOffset field. // the kDataOffset field.
......
...@@ -10748,6 +10748,45 @@ static MaybeObject* Runtime_GetFromCache(Arguments args) { ...@@ -10748,6 +10748,45 @@ static MaybeObject* Runtime_GetFromCache(Arguments args) {
return *value; return *value;
} }
static MaybeObject* Runtime_NewMessageObject(Arguments args) {
HandleScope scope;
CONVERT_ARG_CHECKED(String, type, 0);
CONVERT_ARG_CHECKED(JSArray, arguments, 1);
return *Factory::NewJSMessageObject(type,
arguments,
0,
0,
Factory::undefined_value(),
Factory::undefined_value(),
Factory::undefined_value());
}
static MaybeObject* Runtime_MessageGetType(Arguments args) {
CONVERT_CHECKED(JSMessageObject, message, args[0]);
return message->type();
}
static MaybeObject* Runtime_MessageGetArguments(Arguments args) {
CONVERT_CHECKED(JSMessageObject, message, args[0]);
return message->arguments();
}
static MaybeObject* Runtime_MessageGetStartPosition(Arguments args) {
CONVERT_CHECKED(JSMessageObject, message, args[0]);
return Smi::FromInt(message->start_position());
}
static MaybeObject* Runtime_MessageGetScript(Arguments args) {
CONVERT_CHECKED(JSMessageObject, message, args[0]);
return message->script();
}
#ifdef DEBUG #ifdef DEBUG
// ListNatives is ONLY used by the fuzz-natives.js in debug mode // ListNatives is ONLY used by the fuzz-natives.js in debug mode
// Exclude the code in release mode. // Exclude the code in release mode.
......
...@@ -310,6 +310,13 @@ namespace internal { ...@@ -310,6 +310,13 @@ namespace internal {
/* Cache suport */ \ /* Cache suport */ \
F(GetFromCache, 2, 1) \ F(GetFromCache, 2, 1) \
\ \
/* Message objects */ \
F(NewMessageObject, 2, 1) \
F(MessageGetType, 1, 1) \
F(MessageGetArguments, 1, 1) \
F(MessageGetStartPosition, 1, 1) \
F(MessageGetScript, 1, 1) \
\
/* Pseudo functions - handled as macros by parser */ \ /* Pseudo functions - handled as macros by parser */ \
F(IS_VAR, 1, 1) F(IS_VAR, 1, 1)
......
...@@ -2385,6 +2385,11 @@ TEST(APIThrowMessageOverwrittenToString) { ...@@ -2385,6 +2385,11 @@ TEST(APIThrowMessageOverwrittenToString) {
Local<ObjectTemplate> templ = ObjectTemplate::New(); Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail)); templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
LocalContext context(NULL, templ); LocalContext context(NULL, templ);
CompileRun("asdf;");
CompileRun("var limit = {};"
"limit.valueOf = fail;"
"Error.stackTraceLimit = limit;");
CompileRun("asdf");
CompileRun("Array.prototype.pop = fail;"); CompileRun("Array.prototype.pop = fail;");
CompileRun("Object.prototype.hasOwnProperty = fail;"); CompileRun("Object.prototype.hasOwnProperty = fail;");
CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }"); CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment