A MessageObject is a purely internal object to hold information about
authorager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 2 Feb 2011 13:31:52 +0000 (13:31 +0000)
committerager@chromium.org <ager@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 2 Feb 2011 13:31:52 +0000 (13:31 +0000)
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

19 files changed:
include/v8.h
src/api.cc
src/bootstrapper.cc
src/factory.cc
src/factory.h
src/heap.cc
src/heap.h
src/messages.cc
src/messages.h
src/messages.js
src/objects-debug.cc
src/objects-inl.h
src/objects-printer.cc
src/objects-visiting.cc
src/objects.cc
src/objects.h
src/runtime.cc
src/runtime.h
test/cctest/test-api.cc

index 44a7dcc..44ff2c0 100644 (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;
 
index 9303782..c162440 100644 (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);
 }
 
index 16a186f..6db9a48 100644 (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);
 }
index 2bc878c..a3d5592 100644 (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);
index a5e1591..ba2b181 100644 (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,
index 7c7f3d2..0093829 100644 (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.
index 1c86817..e051b50 100644 (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.
index 42fc3c9..4323649 100644 (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<JSFunction> fun(Top::global_context()->make_message_fun());
-  int start, end;
-  Handle<Object> script;
+  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]);
+  }
+
+  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);
-
-  // 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);
+
+  Handle<Object> stack_trace_handle = stack_trace.is_null()
+      ? Factory::undefined_value()
+      : Handle<Object>::cast(stack_trace);
+
+  Handle<Object> stack_frames_handle =  stack_frames.is_null()
+      ? Factory::undefined_value()
+      : Handle<Object>::cast(stack_frames);
+
+  Handle<JSMessageObject> message =
+      Factory::NewJSMessageObject(type_handle,
+                                  arguments_handle,
+                                  start,
+                                  end,
+                                  script_handle,
+                                  stack_trace_handle,
+                                  stack_frames_handle);
+
+  return message;
 }
 
 
index 440bde8..48f3244 100644 (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);
index e9a88ec..4c3d1e7 100644 (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)
index f9c57e6..c8246c8 100644 (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);
index db9e2ef..50f4031 100644 (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)
index 9f05b0f..237358d 100644 (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, "#");
index c35e02c..5f054bd 100644 (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);
index 36a8e5c..8bced58 100644 (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:
index 8c63022..c9b3757 100644 (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.
index 96d07a8..d55a201 100644 (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.
index d8b3457..b201eb8 100644 (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)
 
index 5667e99..ee62067 100644 (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'; }");