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
This commit is contained in:
ager@chromium.org 2011-02-02 13:31:52 +00:00
parent a5f94a4862
commit 73a4ecfae1
19 changed files with 351 additions and 119 deletions

View File

@ -3448,7 +3448,7 @@ class Internals {
static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02;
static const int kJSObjectType = 0x9f;
static const int kJSObjectType = 0xa0;
static const int kFirstNonstringType = 0x80;
static const int kProxyType = 0x85;

View File

@ -1478,11 +1478,11 @@ v8::Handle<Value> Message::GetScriptResourceName() const {
}
ENTER_V8;
HandleScope scope;
i::Handle<i::JSObject> obj =
i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
// Return this.script.name.
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());
return scope.Close(Utils::ToLocal(resource_name));
}
@ -1494,11 +1494,11 @@ v8::Handle<Value> Message::GetScriptData() const {
}
ENTER_V8;
HandleScope scope;
i::Handle<i::JSObject> obj =
i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
// Return this.script.data.
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());
return scope.Close(Utils::ToLocal(data));
}
@ -1510,9 +1510,9 @@ v8::Handle<v8::StackTrace> Message::GetStackTrace() const {
}
ENTER_V8;
HandleScope scope;
i::Handle<i::JSObject> obj =
i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
i::Handle<i::Object> stackFramesObj = GetProperty(obj, "stackFrames");
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
i::Handle<i::Object> stackFramesObj(message->stack_frames());
if (!stackFramesObj->IsJSArray()) return v8::Handle<v8::StackTrace>();
i::Handle<i::JSArray> stackTrace =
i::Handle<i::JSArray>::cast(stackFramesObj);
@ -1552,6 +1552,7 @@ int Message::GetLineNumber() const {
ON_BAILOUT("v8::Message::GetLineNumber()", return kNoLineNumberInfo);
ENTER_V8;
HandleScope scope;
EXCEPTION_PREAMBLE();
i::Handle<i::Object> result = CallV8HeapFunction("GetLineNumber",
Utils::OpenHandle(this),
@ -1565,9 +1566,9 @@ int Message::GetStartPosition() const {
if (IsDeadCheck("v8::Message::GetStartPosition()")) return 0;
ENTER_V8;
HandleScope scope;
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
return static_cast<int>(GetProperty(data_obj, "startPos")->Number());
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
return message->start_position();
}
@ -1575,8 +1576,9 @@ int Message::GetEndPosition() const {
if (IsDeadCheck("v8::Message::GetEndPosition()")) return 0;
ENTER_V8;
HandleScope scope;
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
return static_cast<int>(GetProperty(data_obj, "endPos")->Number());
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
return message->end_position();
}
@ -1606,8 +1608,10 @@ int Message::GetEndColumn() const {
data_obj,
&has_pending_exception);
EXCEPTION_BAILOUT_CHECK(0);
int start = static_cast<int>(GetProperty(data_obj, "startPos")->Number());
int end = static_cast<int>(GetProperty(data_obj, "endPos")->Number());
i::Handle<i::JSMessageObject> message =
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);
}

View File

@ -1050,7 +1050,6 @@ void Genesis::InstallNativeFunctions() {
INSTALL_NATIVE(JSFunction, "Instantiate", instantiate_fun);
INSTALL_NATIVE(JSFunction, "ConfigureTemplateInstance",
configure_instance_fun);
INSTALL_NATIVE(JSFunction, "MakeMessage", make_message_fun);
INSTALL_NATIVE(JSFunction, "GetStackTraceLine", get_stack_trace_line_fun);
INSTALL_NATIVE(JSObject, "functionCache", function_cache);
}

View File

@ -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) {
CALL_HEAP_FUNCTION(Heap::AllocateSharedFunctionInfo(*name),
SharedFunctionInfo);

View File

@ -365,6 +365,15 @@ class Factory : public AllStatic {
Handle<SerializedScopeInfo> scope_info);
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(
Handle<NumberDictionary>,
uint32_t key,

View File

@ -1826,6 +1826,12 @@ bool Heap::CreateInitialMaps() {
}
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()));
return true;
}
@ -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.
static inline bool Between(uint32_t character, uint32_t from, uint32_t to) {
// This makes uses of the the unsigned wraparound.

View File

@ -94,6 +94,7 @@ namespace internal {
V(Map, oddball_map, OddballMap) \
V(Map, global_property_cell_map, GlobalPropertyCellMap) \
V(Map, shared_function_info_map, SharedFunctionInfoMap) \
V(Map, message_object_map, JSMessageObjectMap) \
V(Map, proxy_map, ProxyMap) \
V(Object, nan_value, NanValue) \
V(Object, minus_zero_value, MinusZeroValue) \
@ -628,6 +629,19 @@ class Heap : public AllStatic {
// Please note this does not perform a garbage collection.
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.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.

View File

@ -62,67 +62,45 @@ void MessageHandler::ReportMessage(const char* msg) {
}
Handle<Object> MessageHandler::MakeMessageObject(
Handle<JSMessageObject> MessageHandler::MakeMessageObject(
const char* type,
MessageLocation* loc,
Vector< Handle<Object> > args,
Handle<String> stack_trace,
Handle<JSArray> stack_frames) {
// Build error message object
v8::HandleScope scope; // Instantiate a closeable HandleScope for EscapeFrom.
Handle<Object> type_str = Factory::LookupAsciiSymbol(type);
Handle<Object> array = Factory::NewJSArray(args.length());
for (int i = 0; i < args.length(); i++)
SetElement(Handle<JSArray>::cast(array), i, args[i]);
Handle<String> type_handle = Factory::LookupAsciiSymbol(type);
Handle<JSArray> arguments_handle = Factory::NewJSArray(args.length());
for (int i = 0; i < args.length(); i++) {
SetElement(arguments_handle, i, args[i]);
}
Handle<JSFunction> fun(Top::global_context()->make_message_fun());
int start, end;
Handle<Object> script;
int start = 0;
int end = 0;
Handle<Object> script_handle = Factory::undefined_value();
if (loc) {
start = loc->start_pos();
end = loc->end_pos();
script = GetScriptWrapper(loc->script());
} else {
start = end = 0;
script = Factory::undefined_value();
script_handle = GetScriptWrapper(loc->script());
}
Handle<Object> start_handle(Smi::FromInt(start));
Handle<Object> end_handle(Smi::FromInt(end));
Handle<Object> stack_trace_val = stack_trace.is_null()
? Factory::undefined_value()
: Handle<Object>::cast(stack_trace);
Handle<Object> stack_frames_val = stack_frames.is_null()
? Factory::undefined_value()
: Handle<Object>::cast(stack_frames);
const int argc = 7;
Object** argv[argc] = { type_str.location(),
array.location(),
start_handle.location(),
end_handle.location(),
script.location(),
stack_trace_val.location(),
stack_frames_val.location() };
// Setup a catch handler to catch exceptions in creating the message. This
// handler is non-verbose to avoid calling MakeMessage recursively in case of
// an exception.
v8::TryCatch catcher;
catcher.SetVerbose(false);
catcher.SetCaptureMessage(false);
Handle<Object> stack_trace_handle = stack_trace.is_null()
? Factory::undefined_value()
: Handle<Object>::cast(stack_trace);
// Format the message.
bool caught_exception = false;
Handle<Object> message =
Execution::Call(fun, Factory::undefined_value(), argc, argv,
&caught_exception);
Handle<Object> stack_frames_handle = stack_frames.is_null()
? Factory::undefined_value()
: Handle<Object>::cast(stack_frames);
// 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>();
Handle<JSMessageObject> message =
Factory::NewJSMessageObject(type_handle,
arguments_handle,
start,
end,
script_handle,
stack_trace_handle,
stack_frames_handle);
return message.EscapeFrom(&scope);
return message;
}

View File

@ -93,11 +93,12 @@ class MessageHandler {
static void ReportMessage(const char* msg);
// Returns a message object for the API to use.
static Handle<Object> MakeMessageObject(const char* type,
MessageLocation* loc,
Vector< Handle<Object> > args,
Handle<String> stack_trace,
Handle<JSArray> stack_frames);
static Handle<JSMessageObject> MakeMessageObject(
const char* type,
MessageLocation* loc,
Vector< Handle<Object> > args,
Handle<String> stack_trace,
Handle<JSArray> stack_frames);
// Report a formatted message (needs JS allocation).
static void ReportMessage(MessageLocation* loc, Handle<Object> message);

View File

@ -55,7 +55,8 @@ var kMessages = 0;
var kReplacementMarkers =
[ "%0", "%1", "%2", "%3" ]
function FormatString(format, args) {
function FormatString(format, message) {
var args = %MessageGetArguments(message);
var result = "";
var arg_num = 0;
for (var i = 0; i < format.length; i++) {
@ -227,15 +228,18 @@ function FormatMessage(message) {
strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
};
}
var format = kMessages[message.type];
if (!format) return "<unknown message " + message.type + ">";
return FormatString(format, message.args);
var message_type = %MessageGetType(message);
var format = kMessages[message_type];
if (!format) return "<unknown message " + message_type + ">";
return FormatString(format, message);
}
function GetLineNumber(message) {
if (message.startPos == -1) return kNoLineNumberInfo;
var location = message.script.locationFromPosition(message.startPos, true);
var start_position = %MessageGetStartPosition(message);
if (start_position == -1) return kNoLineNumberInfo;
var script = %MessageGetScript(message);
var location = script.locationFromPosition(start_position, true);
if (location == null) return kNoLineNumberInfo;
return location.line + 1;
}
@ -244,7 +248,9 @@ function GetLineNumber(message) {
// Returns the source code line containing the given source
// position, or the empty string if the position is invalid.
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 "";
location.restrict();
return location.sourceText();
@ -623,29 +629,12 @@ SourceSlice.prototype.sourceText = function () {
// Returns the offset of the given position within the containing
// line.
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;
location.restrict();
return message.startPos - 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);
return start_position - location.start;
}
@ -992,7 +981,7 @@ function DefineError(f) {
// DefineOneShotAccessor always inserts a message property and
// ignores setters.
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)) {
%IgnoreAttributesAndSetProperty(this, 'message', ToString(m));
@ -1006,11 +995,12 @@ function DefineError(f) {
function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit;
if (!stackTraceLimit) return;
if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
if (stackTraceLimit < 0 || stackTraceLimit > 10000)
stackTraceLimit = 10000;
var raw_stack = %CollectStackTrace(cons_opt ? cons_opt : captureStackTrace,
stackTraceLimit);
var raw_stack = %CollectStackTrace(cons_opt
? cons_opt
: captureStackTrace, stackTraceLimit);
DefineOneShotAccessor(obj, 'stack', function (obj) {
return FormatRawStackTrace(obj, raw_stack);
});
@ -1041,7 +1031,7 @@ function errorToStringDetectCycle() {
try {
var type = this.type;
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;
}
var message = %_CallFunction(this, "message", ObjectHasOwnProperty)

View File

@ -158,6 +158,9 @@ void HeapObject::HeapObjectVerify() {
case SHARED_FUNCTION_INFO_TYPE:
SharedFunctionInfo::cast(this)->SharedFunctionInfoVerify();
break;
case JS_MESSAGE_OBJECT_TYPE:
JSMessageObject::cast(this)->JSMessageObjectVerify();
break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
@ -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() {
CHECK(IsString());
CHECK(length() >= 0 && length() <= Smi::kMaxValue);

View File

@ -408,7 +408,7 @@ bool MaybeObject::IsRetryAfterGC() {
bool MaybeObject::IsOutOfMemory() {
return HAS_FAILURE_TAG(this)
&& Failure::cast(this)->IsOutOfMemoryException();
&& Failure::cast(this)->IsOutOfMemoryException();
}
@ -430,26 +430,26 @@ Failure* Failure::cast(MaybeObject* obj) {
bool Object::IsJSObject() {
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() {
return IsHeapObject()
&& (HeapObject::cast(this)->map()->instance_type() ==
JS_CONTEXT_EXTENSION_OBJECT_TYPE);
&& (HeapObject::cast(this)->map()->instance_type() ==
JS_CONTEXT_EXTENSION_OBJECT_TYPE);
}
bool Object::IsMap() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == MAP_TYPE;
&& HeapObject::cast(this)->map()->instance_type() == MAP_TYPE;
}
bool Object::IsFixedArray() {
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() {
bool Object::IsCatchContext() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map() == Heap::catch_context_map();
&& HeapObject::cast(this)->map() == Heap::catch_context_map();
}
bool Object::IsGlobalContext() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map() == Heap::global_context_map();
&& HeapObject::cast(this)->map() == Heap::global_context_map();
}
bool Object::IsJSFunction() {
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) {
bool Object::IsCode() {
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() {
bool Object::IsJSValue() {
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() {
bool Object::IsProxy() {
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() {
bool Object::IsJSArray() {
return Object::IsHeapObject()
&& HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE;
&& HeapObject::cast(this)->map()->instance_type() == JS_ARRAY_TYPE;
}
bool Object::IsJSRegExp() {
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) {
bool Object::IsHashTable() {
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() {
return JSValue::kSize;
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
return JSObject::kHeaderSize;
case JS_MESSAGE_OBJECT_TYPE:
return JSMessageObject::kSize;
default:
UNREACHABLE();
return 0;
@ -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)
ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset)
ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset)

View File

@ -151,6 +151,9 @@ void HeapObject::HeapObjectPrint(FILE* out) {
case SHARED_FUNCTION_INFO_TYPE:
SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out);
break;
case JS_MESSAGE_OBJECT_TYPE:
JSMessageObject::cast(this)->JSMessageObjectPrint(out);
break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out);
break;
@ -396,6 +399,7 @@ static const char* TypeToString(InstanceType type) {
case JS_GLOBAL_PROXY_TYPE: return "JS_GLOBAL_PROXY";
case PROXY_TYPE: return "PROXY";
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;
STRUCT_LIST(MAKE_STRUCT_CASE)
#undef MAKE_STRUCT_CASE
@ -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) {
if (StringShape(this).IsSymbol()) {
PrintF(out, "#");

View File

@ -104,6 +104,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
case JS_BUILTINS_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
return GetVisitorIdForSize(kVisitJSObject,
kVisitJSObjectGeneric,
instance_size);

View File

@ -979,6 +979,9 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
case SHARED_FUNCTION_INFO_TYPE:
accumulator->Add("<SharedFunctionInfo>");
break;
case JS_MESSAGE_OBJECT_TYPE:
accumulator->Add("<JSMessageObject>");
break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
accumulator->Put('<'); \
@ -1069,6 +1072,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case JS_GLOBAL_PROXY_TYPE:
case JS_GLOBAL_OBJECT_TYPE:
case JS_BUILTINS_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
JSObject::BodyDescriptor::IterateBody(this, object_size, v);
break;
case JS_FUNCTION_TYPE:

View File

@ -54,7 +54,8 @@
// - JSGlobalObject
// - JSBuiltinsObject
// - JSGlobalProxy
// - JSValue
// - JSValue
// - JSMessageObject
// - ByteArray
// - PixelArray
// - ExternalArray
@ -288,6 +289,8 @@ static const int kVariableSizeSentinel = 0;
V(FIXED_ARRAY_TYPE) \
V(SHARED_FUNCTION_INFO_TYPE) \
\
V(JS_MESSAGE_OBJECT_TYPE) \
\
V(JS_VALUE_TYPE) \
V(JS_OBJECT_TYPE) \
V(JS_CONTEXT_EXTENSION_OBJECT_TYPE) \
@ -518,6 +521,8 @@ enum InstanceType {
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
JS_MESSAGE_OBJECT_TYPE,
JS_VALUE_TYPE, // FIRST_JS_OBJECT_TYPE
JS_OBJECT_TYPE,
JS_CONTEXT_EXTENSION_OBJECT_TYPE,
@ -675,6 +680,7 @@ class MaybeObject BASE_EMBEDDED {
V(Oddball) \
V(SharedFunctionInfo) \
V(JSValue) \
V(JSMessageObject) \
V(StringWrapper) \
V(Proxy) \
V(Boolean) \
@ -4696,6 +4702,68 @@ class JSValue: public JSObject {
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
// The regular expression holds a single reference to a FixedArray in
// the kDataOffset field.

View File

@ -10748,6 +10748,45 @@ static MaybeObject* Runtime_GetFromCache(Arguments args) {
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
// ListNatives is ONLY used by the fuzz-natives.js in debug mode
// Exclude the code in release mode.

View File

@ -310,6 +310,13 @@ namespace internal {
/* Cache suport */ \
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 */ \
F(IS_VAR, 1, 1)

View File

@ -2385,6 +2385,11 @@ TEST(APIThrowMessageOverwrittenToString) {
Local<ObjectTemplate> templ = ObjectTemplate::New();
templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
LocalContext context(NULL, templ);
CompileRun("asdf;");
CompileRun("var limit = {};"
"limit.valueOf = fail;"
"Error.stackTraceLimit = limit;");
CompileRun("asdf");
CompileRun("Array.prototype.pop = fail;");
CompileRun("Object.prototype.hasOwnProperty = fail;");
CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");