1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/ErrorObject.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,151 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sw=4 et tw=78: 1.6 + * 1.7 + * This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#include "vm/ErrorObject-inl.h" 1.12 + 1.13 +#include "jsexn.h" 1.14 + 1.15 +#include "vm/GlobalObject.h" 1.16 + 1.17 +#include "jsobjinlines.h" 1.18 + 1.19 +#include "vm/Shape-inl.h" 1.20 + 1.21 +using namespace js; 1.22 +using mozilla::PodZero; 1.23 + 1.24 +/* static */ Shape * 1.25 +js::ErrorObject::assignInitialShape(ExclusiveContext *cx, Handle<ErrorObject*> obj) 1.26 +{ 1.27 + MOZ_ASSERT(obj->nativeEmpty()); 1.28 + 1.29 + if (!obj->addDataProperty(cx, cx->names().fileName, FILENAME_SLOT, 0)) 1.30 + return nullptr; 1.31 + if (!obj->addDataProperty(cx, cx->names().lineNumber, LINENUMBER_SLOT, 0)) 1.32 + return nullptr; 1.33 + if (!obj->addDataProperty(cx, cx->names().columnNumber, COLUMNNUMBER_SLOT, 0)) 1.34 + return nullptr; 1.35 + return obj->addDataProperty(cx, cx->names().stack, STACK_SLOT, 0); 1.36 +} 1.37 + 1.38 +/* static */ bool 1.39 +js::ErrorObject::init(JSContext *cx, Handle<ErrorObject*> obj, JSExnType type, 1.40 + ScopedJSFreePtr<JSErrorReport> *errorReport, HandleString fileName, 1.41 + HandleString stack, uint32_t lineNumber, uint32_t columnNumber, 1.42 + HandleString message) 1.43 +{ 1.44 + // Null out early in case of error, for exn_finalize's sake. 1.45 + obj->initReservedSlot(ERROR_REPORT_SLOT, PrivateValue(nullptr)); 1.46 + 1.47 + if (!EmptyShape::ensureInitialCustomShape<ErrorObject>(cx, obj)) 1.48 + return false; 1.49 + 1.50 + // The .message property isn't part of the initial shape because it's 1.51 + // present in some error objects -- |Error.prototype|, |new Error("f")|, 1.52 + // |new Error("")| -- but not in others -- |new Error(undefined)|, 1.53 + // |new Error()|. 1.54 + RootedShape messageShape(cx); 1.55 + if (message) { 1.56 + messageShape = obj->addDataProperty(cx, cx->names().message, MESSAGE_SLOT, 0); 1.57 + if (!messageShape) 1.58 + return false; 1.59 + MOZ_ASSERT(messageShape->slot() == MESSAGE_SLOT); 1.60 + } 1.61 + 1.62 + MOZ_ASSERT(obj->nativeLookupPure(NameToId(cx->names().fileName))->slot() == FILENAME_SLOT); 1.63 + MOZ_ASSERT(obj->nativeLookupPure(NameToId(cx->names().lineNumber))->slot() == LINENUMBER_SLOT); 1.64 + MOZ_ASSERT(obj->nativeLookupPure(NameToId(cx->names().columnNumber))->slot() == 1.65 + COLUMNNUMBER_SLOT); 1.66 + MOZ_ASSERT(obj->nativeLookupPure(NameToId(cx->names().stack))->slot() == STACK_SLOT); 1.67 + MOZ_ASSERT_IF(message, 1.68 + obj->nativeLookupPure(NameToId(cx->names().message))->slot() == MESSAGE_SLOT); 1.69 + 1.70 + MOZ_ASSERT(JSEXN_ERR <= type && type < JSEXN_LIMIT); 1.71 + 1.72 + JSErrorReport *report = errorReport ? errorReport->forget() : nullptr; 1.73 + obj->initReservedSlot(EXNTYPE_SLOT, Int32Value(type)); 1.74 + obj->setReservedSlot(ERROR_REPORT_SLOT, PrivateValue(report)); 1.75 + obj->initReservedSlot(FILENAME_SLOT, StringValue(fileName)); 1.76 + obj->initReservedSlot(LINENUMBER_SLOT, Int32Value(lineNumber)); 1.77 + obj->initReservedSlot(COLUMNNUMBER_SLOT, Int32Value(columnNumber)); 1.78 + obj->initReservedSlot(STACK_SLOT, StringValue(stack)); 1.79 + if (message) 1.80 + obj->nativeSetSlotWithType(cx, messageShape, StringValue(message)); 1.81 + 1.82 + if (report && report->originPrincipals) 1.83 + JS_HoldPrincipals(report->originPrincipals); 1.84 + 1.85 + return true; 1.86 +} 1.87 + 1.88 +/* static */ ErrorObject * 1.89 +js::ErrorObject::create(JSContext *cx, JSExnType errorType, HandleString stack, 1.90 + HandleString fileName, uint32_t lineNumber, uint32_t columnNumber, 1.91 + ScopedJSFreePtr<JSErrorReport> *report, HandleString message) 1.92 +{ 1.93 + Rooted<JSObject*> proto(cx, GlobalObject::getOrCreateCustomErrorPrototype(cx, cx->global(), errorType)); 1.94 + if (!proto) 1.95 + return nullptr; 1.96 + 1.97 + Rooted<ErrorObject*> errObject(cx); 1.98 + { 1.99 + JSObject* obj = NewObjectWithGivenProto(cx, &ErrorObject::class_, proto, nullptr); 1.100 + if (!obj) 1.101 + return nullptr; 1.102 + errObject = &obj->as<ErrorObject>(); 1.103 + } 1.104 + 1.105 + if (!ErrorObject::init(cx, errObject, errorType, report, fileName, stack, 1.106 + lineNumber, columnNumber, message)) 1.107 + { 1.108 + return nullptr; 1.109 + } 1.110 + 1.111 + return errObject; 1.112 +} 1.113 + 1.114 +JSErrorReport * 1.115 +js::ErrorObject::getOrCreateErrorReport(JSContext *cx) 1.116 +{ 1.117 + if (JSErrorReport *r = getErrorReport()) 1.118 + return r; 1.119 + 1.120 + // We build an error report on the stack and then use CopyErrorReport to do 1.121 + // the nitty-gritty malloc stuff. 1.122 + JSErrorReport report; 1.123 + PodZero(&report); 1.124 + 1.125 + // Type. 1.126 + JSExnType type_ = type(); 1.127 + report.exnType = type_; 1.128 + 1.129 + // Filename. 1.130 + JSAutoByteString filenameStr; 1.131 + if (!filenameStr.encodeLatin1(cx, fileName(cx))) 1.132 + return nullptr; 1.133 + report.filename = filenameStr.ptr(); 1.134 + 1.135 + // Coordinates. 1.136 + report.lineno = lineNumber(); 1.137 + report.column = columnNumber(); 1.138 + 1.139 + // Message. Note that |new Error()| will result in an undefined |message| 1.140 + // slot, so we need to explicitly substitute the empty string in that case. 1.141 + RootedString message(cx, getMessage()); 1.142 + if (!message) 1.143 + message = cx->runtime()->emptyString; 1.144 + if (!message->ensureFlat(cx)) 1.145 + return nullptr; 1.146 + report.ucmessage = message->asFlat().chars(); 1.147 + 1.148 + // Cache and return. 1.149 + JSErrorReport *copy = CopyErrorReport(cx, &report); 1.150 + if (!copy) 1.151 + return nullptr; 1.152 + setReservedSlot(ERROR_REPORT_SLOT, PrivateValue(copy)); 1.153 + return copy; 1.154 +}