X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/f9bf01c6616d5ddcf65b13b33cedf9e387ff7a63..4be4e30906bcb8ee30b4d189205cb70bad6707ce:/runtime/ExceptionHelpers.cpp?ds=inline diff --git a/runtime/ExceptionHelpers.cpp b/runtime/ExceptionHelpers.cpp index 9bb740e..816e8e3 100644 --- a/runtime/ExceptionHelpers.cpp +++ b/runtime/ExceptionHelpers.cpp @@ -31,161 +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 createTypeError(ExecState* exec, const char* message) + +JSObject* createStackOverflowError(ExecState* exec) { - return createError(exec, TypeError, message); + return createRangeError(exec, ASCIILiteral("Maximum call stack size exceeded.")); } -JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, unsigned bytecodeOffset, CodeBlock* codeBlock) +JSObject* createStackOverflowError(JSGlobalObject* globalObject) { - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - JSObject* exception = Error::create(exec, ReferenceError, makeString("Can't find variable: ", ident.ustring()), line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->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(globalObject, ASCIILiteral("Maximum call stack size exceeded.")); +} + +JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident) +{ + String message(makeString("Can't find variable: ", ident.string())); + return createReferenceError(exec, message); } -static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue value, UString error) -{ - if (!expressionStop || expressionStart > codeBlock->source()->length()) - return makeString(value.toString(exec), " is ", error); - if (expressionStart < expressionStop) - return makeString("Result of expression '", codeBlock->source()->getRange(expressionStart, expressionStop), "' [", value.toString(exec), "] is ", error, "."); - - // 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--; - return makeString("Result of expression near '...", codeBlock->source()->getRange(start, stop), "...' [", value.toString(exec), "] is ", error, "."); -} - -JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock) -{ - 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, makeString("not a valid argument for '", op, "'")); - JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->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->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->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->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->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->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->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