X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/ba379fdc102753d6be2c4d937058fe40257329fe..4be4e30906bcb8ee30b4d189205cb70bad6707ce:/runtime/ExceptionHelpers.cpp?ds=inline diff --git a/runtime/ExceptionHelpers.cpp b/runtime/ExceptionHelpers.cpp index e63594c..816e8e3 100644 --- a/runtime/ExceptionHelpers.cpp +++ b/runtime/ExceptionHelpers.cpp @@ -31,181 +31,120 @@ #include "CodeBlock.h" #include "CallFrame.h" +#include "ErrorInstance.h" #include "JSGlobalObjectFunctions.h" #include "JSObject.h" #include "JSNotAnObject.h" #include "Interpreter.h" #include "Nodes.h" +#include "Operations.h" namespace JSC { -class InterruptedExecutionError : public JSObject { -public: - InterruptedExecutionError(JSGlobalData* globalData) - : JSObject(globalData->interruptedExecutionErrorStructure) - { - } +ASSERT_HAS_TRIVIAL_DESTRUCTOR(TerminatedExecutionError); - virtual bool isWatchdogException() const { return true; } +const ClassInfo TerminatedExecutionError::s_info = { "TerminatedExecutionError", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(TerminatedExecutionError) }; - virtual UString toString(ExecState*) const { return "JavaScript execution exceeded timeout."; } -}; +JSValue TerminatedExecutionError::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType hint) +{ + if (hint == PreferString) + return jsNontrivialString(exec, String(ASCIILiteral("JavaScript execution terminated."))); + return JSValue(QNaN); +} -JSValue createInterruptedExecutionException(JSGlobalData* globalData) +JSObject* createTerminatedExecutionException(VM* vm) { - return new (globalData) InterruptedExecutionError(globalData); + return TerminatedExecutionError::create(*vm); } -static JSValue createError(ExecState* exec, ErrorType e, const char* msg) +bool isTerminatedExecutionException(JSObject* object) { - return Error::create(exec, e, msg, -1, -1, 0); + return object->inherits(&TerminatedExecutionError::s_info); } -JSValue createStackOverflowError(ExecState* exec) +bool isTerminatedExecutionException(JSValue value) { - return createError(exec, RangeError, "Maximum call stack size exceeded."); + return value.inherits(&TerminatedExecutionError::s_info); } -JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, unsigned bytecodeOffset, CodeBlock* codeBlock) + +JSObject* createStackOverflowError(ExecState* exec) { - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - UString message = "Can't find variable: "; - message.append(ident.ustring()); - JSObject* exception = Error::create(exec, ReferenceError, message, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); - exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); - return exception; + return createRangeError(exec, ASCIILiteral("Maximum call stack size exceeded.")); } - -static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue value, UString error) + +JSObject* createStackOverflowError(JSGlobalObject* globalObject) { - if (!expressionStop || expressionStart > codeBlock->source()->length()) { - UString errorText = value.toString(exec); - errorText.append(" is "); - errorText.append(error); - return errorText; - } + return createRangeError(globalObject, ASCIILiteral("Maximum call stack size exceeded.")); +} - UString errorText = "Result of expression "; - - if (expressionStart < expressionStop) { - errorText.append('\''); - errorText.append(codeBlock->source()->getRange(expressionStart, expressionStop)); - errorText.append("' ["); - errorText.append(value.toString(exec)); - errorText.append("] is "); - } else { - // No range information, so give a few characters of context - const UChar* data = codeBlock->source()->data(); - int dataLength = codeBlock->source()->length(); - int start = expressionStart; - int stop = expressionStart; - // Get up to 20 characters of context to the left and right of the divot, clamping to the line. - // then strip whitespace. - while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n') - start--; - while (start < (expressionStart - 1) && isStrWhiteSpace(data[start])) - start++; - while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n') - stop++; - while (stop > expressionStart && isStrWhiteSpace(data[stop])) - stop--; - errorText.append("near '..."); - errorText.append(codeBlock->source()->getRange(start, stop)); - errorText.append("...' ["); - errorText.append(value.toString(exec)); - errorText.append("] is "); - } - errorText.append(error); - errorText.append("."); - return errorText; -} - -JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) -{ - UString message = "not a valid argument for '"; - message.append(op); - message.append("'"); +JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident) +{ + String message(makeString("Can't find variable: ", ident.string())); + return createReferenceError(exec, message); +} - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, message); - JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); - exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); +JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value) +{ + String errorMessage = makeString("'", value.toString(exec)->value(exec), "' is not a valid argument for '", op, "'"); + JSObject* exception = createTypeError(exec, errorMessage); + ASSERT(exception->isErrorInstance()); + static_cast(exception)->setAppendSourceToMessage(); return exception; } -JSObject* createNotAConstructorError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) +JSObject* createNotAConstructorError(ExecState* exec, JSValue value) { - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); + String errorMessage = makeString("'", value.toString(exec)->value(exec), "' is not a constructor"); + JSObject* exception = createTypeError(exec, errorMessage); + ASSERT(exception->isErrorInstance()); + static_cast(exception)->setAppendSourceToMessage(); + return exception; +} - // We're in a "new" expression, so we need to skip over the "new.." part - int startPoint = divotPoint - (startOffset ? startOffset - 4 : 0); // -4 for "new " - const UChar* data = codeBlock->source()->data(); - while (startPoint < divotPoint && isStrWhiteSpace(data[startPoint])) - startPoint++; - - UString errorMessage = createErrorMessage(exec, codeBlock, line, startPoint, divotPoint, value, "not a constructor"); - JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); - exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); +JSObject* createNotAFunctionError(ExecState* exec, JSValue value) +{ + String errorMessage = makeString("'", value.toString(exec)->value(exec), "' is not a function"); + JSObject* exception = createTypeError(exec, errorMessage); + ASSERT(exception->isErrorInstance()); + static_cast(exception)->setAppendSourceToMessage(); return exception; } -JSValue createNotAFunctionError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) +JSObject* createNotAnObjectError(ExecState* exec, JSValue value) { - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, value, "not a function"); - JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); - exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); + String errorMessage = makeString("'", value.toString(exec)->value(exec), "' is not an object"); + JSObject* exception = createTypeError(exec, errorMessage); + ASSERT(exception->isErrorInstance()); + static_cast(exception)->setAppendSourceToMessage(); return exception; } -JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState* exec, bool isNull) +JSObject* createErrorForInvalidGlobalAssignment(ExecState* exec, const String& propertyName) { - return new (exec) JSNotAnObjectErrorStub(exec, isNull); + return createReferenceError(exec, makeString("Strict mode forbids implicit creation of global property '", propertyName, "'")); } -JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, unsigned bytecodeOffset, CodeBlock* codeBlock) +JSObject* createOutOfMemoryError(JSGlobalObject* globalObject) { - // Both op_construct and op_instanceof require a use of op_get_by_id to get - // the prototype property from an object. The exception messages for exceptions - // thrown by these instances op_get_by_id need to reflect this. - OpcodeID followingOpcodeID; - if (codeBlock->getByIdExceptionInfoForBytecodeOffset(exec, bytecodeOffset, followingOpcodeID)) { - ASSERT(followingOpcodeID == op_construct || followingOpcodeID == op_instanceof); - if (followingOpcodeID == op_construct) - return createNotAConstructorError(exec, error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock); - return createInvalidParamError(exec, "instanceof", error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock); - } + return createError(globalObject, ASCIILiteral("Out of memory")); +} - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, error->isNull() ? jsNull() : jsUndefined(), "not an object"); - JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); - exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); - exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); - return exception; +JSObject* throwOutOfMemoryError(ExecState* exec) +{ + return throwError(exec, createOutOfMemoryError(exec->lexicalGlobalObject())); +} + +JSObject* throwStackOverflowError(ExecState* exec) +{ + Interpreter::ErrorHandlingMode mode(exec); + return throwError(exec, createStackOverflowError(exec)); +} + +JSObject* throwTerminatedExecutionException(ExecState* exec) +{ + Interpreter::ErrorHandlingMode mode(exec); + return throwError(exec, createTerminatedExecutionException(&exec->vm())); } } // namespace JSC