X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/b80e619319b1def83d1e8b4f84042b661be1be7f..14957cd040308e3eeec43d26bae5d76da13fcd85:/runtime/ExceptionHelpers.cpp diff --git a/runtime/ExceptionHelpers.cpp b/runtime/ExceptionHelpers.cpp index aee6f31..1d74315 100644 --- a/runtime/ExceptionHelpers.cpp +++ b/runtime/ExceptionHelpers.cpp @@ -31,18 +31,20 @@ #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 "UStringConcatenate.h" namespace JSC { -class InterruptedExecutionError : public JSObject { +class InterruptedExecutionError : public JSNonFinalObject { public: InterruptedExecutionError(JSGlobalData* globalData) - : JSObject(globalData->interruptedExecutionErrorStructure) + : JSNonFinalObject(*globalData, globalData->interruptedExecutionErrorStructure.get()) { } @@ -51,15 +53,15 @@ public: virtual UString toString(ExecState*) const { return "JavaScript execution exceeded timeout."; } }; -JSValue createInterruptedExecutionException(JSGlobalData* globalData) +JSObject* createInterruptedExecutionException(JSGlobalData* globalData) { return new (globalData) InterruptedExecutionError(globalData); } -class TerminatedExecutionError : public JSObject { +class TerminatedExecutionError : public JSNonFinalObject { public: TerminatedExecutionError(JSGlobalData* globalData) - : JSObject(globalData->terminatedExecutionErrorStructure) + : JSNonFinalObject(*globalData, globalData->terminatedExecutionErrorStructure.get()) { } @@ -68,146 +70,81 @@ public: virtual UString toString(ExecState*) const { return "JavaScript execution terminated."; } }; -JSValue createTerminatedExecutionException(JSGlobalData* globalData) +JSObject* createTerminatedExecutionException(JSGlobalData* globalData) { return new (globalData) TerminatedExecutionError(globalData); } -static JSValue createError(ExecState* exec, ErrorType e, const char* msg) +JSObject* createStackOverflowError(ExecState* exec) { - return Error::create(exec, e, msg, -1, -1, UString()); + return createRangeError(exec, "Maximum call stack size exceeded."); } -JSValue createStackOverflowError(ExecState* exec) +JSObject* createStackOverflowError(JSGlobalObject* globalObject) { - return createError(exec, RangeError, "Maximum call stack size exceeded."); + return createRangeError(globalObject, "Maximum call stack size exceeded."); } -JSValue createTypeError(ExecState* exec, const char* message) +JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident) { - return createError(exec, TypeError, message); -} - -JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, unsigned bytecodeOffset, CodeBlock* codeBlock) -{ - 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; + UString message(makeUString("Can't find variable: ", ident.ustring())); + return createReferenceError(exec, message); } -static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue value, UString error) +JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value) { - 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, "."); + UString errorMessage = makeUString("'", value.toString(exec), "' is not a valid argument for '", op, "'"); + JSObject* exception = createTypeError(exec, errorMessage); + ASSERT(exception->isErrorInstance()); + static_cast(exception)->setAppendSourceToMessage(); + return exception; } -JSObject* createInvalidParamError(ExecState* exec, const char* op, 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); - 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); + UString errorMessage = makeUString("'", value.toString(exec), "' is not a constructor"); + 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* createNotAFunctionError(ExecState* exec, JSValue value) { - int startOffset = 0; - int endOffset = 0; - int divotPoint = 0; - int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); - - // 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); + UString errorMessage = makeUString("'", value.toString(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); + UString errorMessage = makeUString("'", value.toString(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 UString& propertyName) { - return new (exec) JSNotAnObjectErrorStub(exec, isNull); + return createReferenceError(exec, makeUString("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, "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())); } -JSValue throwOutOfMemoryError(ExecState* exec) +JSObject* throwStackOverflowError(ExecState* exec) { - return throwError(exec, GeneralError, "Out of memory"); + return throwError(exec, createStackOverflowError(exec)); } } // namespace JSC