diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/Error.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/Error.cpp | 275 |
1 files changed, 223 insertions, 52 deletions
diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp index a87be188a..677dc9b1c 100644 --- a/Source/JavaScriptCore/runtime/Error.cpp +++ b/Source/JavaScriptCore/runtime/Error.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003-2006, 2008, 2016 Apple Inc. All rights reserved. * Copyright (C) 2007 Eric Seidel (eric@webkit.org) * * This library is free software; you can redistribute it and/or @@ -28,139 +28,277 @@ #include "ErrorConstructor.h" #include "ExceptionHelpers.h" #include "FunctionPrototype.h" +#include "Interpreter.h" #include "JSArray.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSObject.h" #include "JSString.h" +#include "JSCInlines.h" #include "NativeErrorConstructor.h" -#include "Operations.h" #include "SourceCode.h" - -#include <wtf/text/StringBuilder.h> +#include "StackFrame.h" namespace JSC { static const char* linePropertyName = "line"; static const char* sourceURLPropertyName = "sourceURL"; -JSObject* createError(JSGlobalObject* globalObject, const String& message) +JSObject* createError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->vm(), globalObject->errorStructure(), message); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(), message, appender, TypeNothing, true); } -JSObject* createEvalError(JSGlobalObject* globalObject, const String& message) +JSObject* createEvalError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->vm(), globalObject->evalErrorConstructor()->errorStructure(), message); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->evalErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); } -JSObject* createRangeError(JSGlobalObject* globalObject, const String& message) +JSObject* createRangeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); } -JSObject* createReferenceError(JSGlobalObject* globalObject, const String& message) +JSObject* createReferenceError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->vm(), globalObject->referenceErrorConstructor()->errorStructure(), message); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->referenceErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); } -JSObject* createSyntaxError(JSGlobalObject* globalObject, const String& message) +JSObject* createSyntaxError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->vm(), globalObject->syntaxErrorConstructor()->errorStructure(), message); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->syntaxErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); } -JSObject* createTypeError(JSGlobalObject* globalObject, const String& message) +JSObject* createTypeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender, RuntimeType type) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message, appender, type, true); } -JSObject* createNotEnoughArgumentsError(JSGlobalObject* globalObject) +JSObject* createNotEnoughArgumentsError(ExecState* exec, ErrorInstance::SourceAppender appender) { - return createTypeError(globalObject, ASCIILiteral("Not enough arguments")); + return createTypeError(exec, ASCIILiteral("Not enough arguments"), appender, TypeNothing); } -JSObject* createURIError(JSGlobalObject* globalObject, const String& message) +JSObject* createURIError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); } -JSObject* createError(ExecState* exec, const String& message) +JSObject* createError(ExecState* exec, ErrorType errorType, const String& message) { - return createError(exec->lexicalGlobalObject(), message); + switch (errorType) { + case ErrorType::Error: + return createError(exec, message); + case ErrorType::EvalError: + return createEvalError(exec, message); + case ErrorType::RangeError: + return createRangeError(exec, message); + case ErrorType::ReferenceError: + return createReferenceError(exec, message); + case ErrorType::SyntaxError: + return createSyntaxError(exec, message); + case ErrorType::TypeError: + return createTypeError(exec, message); + case ErrorType::URIError: + return createURIError(exec, message); + } + ASSERT_NOT_REACHED(); + return nullptr; } -JSObject* createEvalError(ExecState* exec, const String& message) +class FindFirstCallerFrameWithCodeblockFunctor { +public: + FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame) + : m_startCallFrame(startCallFrame) + , m_foundCallFrame(nullptr) + , m_foundStartCallFrame(false) + , m_index(0) + { } + + StackVisitor::Status operator()(StackVisitor& visitor) const + { + if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame)) + m_foundStartCallFrame = true; + + if (m_foundStartCallFrame) { + if (visitor->callFrame()->codeBlock()) { + m_foundCallFrame = visitor->callFrame(); + return StackVisitor::Done; + } + m_index++; + } + + return StackVisitor::Continue; + } + + CallFrame* foundCallFrame() const { return m_foundCallFrame; } + unsigned index() const { return m_index; } + +private: + CallFrame* m_startCallFrame; + mutable CallFrame* m_foundCallFrame; + mutable bool m_foundStartCallFrame; + mutable unsigned m_index; +}; + +bool addErrorInfoAndGetBytecodeOffset(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame, CallFrame*& callFrame, unsigned* bytecodeOffset) { - return createEvalError(exec->lexicalGlobalObject(), message); + Vector<StackFrame> stackTrace = Vector<StackFrame>(); + + size_t framesToSkip = useCurrentFrame ? 0 : 1; + vm.interpreter->getStackTrace(stackTrace, framesToSkip); + if (!stackTrace.isEmpty()) { + + ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); + + StackFrame* firstFrameWithLineAndColumnInfo = nullptr; + for (unsigned i = 0 ; i < stackTrace.size(); ++i) { + firstFrameWithLineAndColumnInfo = &stackTrace.at(i); + if (firstFrameWithLineAndColumnInfo->hasLineAndColumnInfo()) + break; + } + + if (bytecodeOffset) { + FindFirstCallerFrameWithCodeblockFunctor functor(exec); + vm.topCallFrame->iterate(functor); + callFrame = functor.foundCallFrame(); + unsigned stackIndex = functor.index(); + *bytecodeOffset = 0; + if (stackTrace.at(stackIndex).hasBytecodeOffset()) + *bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset(); + } + + unsigned line; + unsigned column; + firstFrameWithLineAndColumnInfo->computeLineAndColumn(line, column); + obj->putDirect(vm, vm.propertyNames->line, jsNumber(line)); + obj->putDirect(vm, vm.propertyNames->column, jsNumber(column)); + + String frameSourceURL = firstFrameWithLineAndColumnInfo->sourceURL(); + if (!frameSourceURL.isEmpty()) + obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, frameSourceURL)); + + obj->putDirect(vm, vm.propertyNames->stack, Interpreter::stackTraceAsString(vm, stackTrace), DontEnum); + + return true; + } + return false; } -JSObject* createRangeError(ExecState* exec, const String& message) +void addErrorInfo(ExecState* exec, JSObject* obj, bool useCurrentFrame) { - return createRangeError(exec->lexicalGlobalObject(), message); + CallFrame* callFrame = nullptr; + addErrorInfoAndGetBytecodeOffset(exec, exec->vm(), obj, useCurrentFrame, callFrame); } -JSObject* createReferenceError(ExecState* exec, const String& message) +JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source) { - return createReferenceError(exec->lexicalGlobalObject(), message); + VM* vm = &callFrame->vm(); + const String& sourceURL = source.provider()->url(); + + if (line != -1) + error->putDirect(*vm, Identifier::fromString(vm, linePropertyName), jsNumber(line)); + if (!sourceURL.isNull()) + error->putDirect(*vm, Identifier::fromString(vm, sourceURLPropertyName), jsString(vm, sourceURL)); + return error; } -JSObject* createSyntaxError(ExecState* exec, const String& message) +JSObject* throwConstructorCannotBeCalledAsFunctionTypeError(ExecState* exec, ThrowScope& scope, const char* constructorName) { - return createSyntaxError(exec->lexicalGlobalObject(), message); + return throwTypeError(exec, scope, makeString("calling ", constructorName, " constructor without new is invalid")); } -JSObject* createTypeError(ExecState* exec, const String& message) +JSObject* throwTypeError(ExecState* exec, ThrowScope& scope) { - return createTypeError(exec->lexicalGlobalObject(), message); + return throwException(exec, scope, createTypeError(exec)); } -JSObject* createNotEnoughArgumentsError(ExecState* exec) +JSObject* throwTypeError(ExecState* exec, ThrowScope& scope, ASCIILiteral errorMessage) { - return createNotEnoughArgumentsError(exec->lexicalGlobalObject()); + return throwTypeError(exec, scope, String(errorMessage)); } -JSObject* createURIError(ExecState* exec, const String& message) +JSObject* throwTypeError(ExecState* exec, ThrowScope& scope, const String& message) { - return createURIError(exec->lexicalGlobalObject(), message); + return throwException(exec, scope, createTypeError(exec, message)); } -JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source) +JSObject* throwSyntaxError(ExecState* exec, ThrowScope& scope) { - VM* vm = &callFrame->vm(); - const String& sourceURL = source.provider()->url(); + return throwException(exec, scope, createSyntaxError(exec, ASCIILiteral("Syntax error"))); +} - if (line != -1) - error->putDirect(*vm, Identifier(vm, linePropertyName), jsNumber(line), ReadOnly | DontDelete); - if (!sourceURL.isNull()) - error->putDirect(*vm, Identifier(vm, sourceURLPropertyName), jsString(vm, sourceURL), ReadOnly | DontDelete); - return error; +JSObject* throwSyntaxError(ExecState* exec, ThrowScope& scope, const String& message) +{ + return throwException(exec, scope, createSyntaxError(exec, message)); +} + +JSObject* createError(ExecState* exec, const String& message) +{ + return createError(exec, message, nullptr); +} + +JSObject* createEvalError(ExecState* exec, const String& message) +{ + return createEvalError(exec, message, nullptr); +} + +JSObject* createRangeError(ExecState* exec, const String& message) +{ + return createRangeError(exec, message, nullptr); +} + +JSObject* createReferenceError(ExecState* exec, const String& message) +{ + return createReferenceError(exec, message, nullptr); +} + +JSObject* createSyntaxError(ExecState* exec, const String& message) +{ + return createSyntaxError(exec, message, nullptr); } +JSObject* createTypeError(ExecState* exec) +{ + return createTypeError(exec, ASCIILiteral("Type error")); +} + +JSObject* createTypeError(ExecState* exec, const String& message) +{ + return createTypeError(exec, message, nullptr, TypeNothing); +} -bool hasErrorInfo(ExecState* exec, JSObject* error) +JSObject* createNotEnoughArgumentsError(ExecState* exec) { - return error->hasProperty(exec, Identifier(exec, linePropertyName)) - || error->hasProperty(exec, Identifier(exec, sourceURLPropertyName)); + return createNotEnoughArgumentsError(exec, nullptr); } -JSObject* throwTypeError(ExecState* exec) +JSObject* createURIError(ExecState* exec, const String& message) { - return exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Type error"))); + return createURIError(exec, message, nullptr); } -JSObject* throwSyntaxError(ExecState* exec) +JSObject* createOutOfMemoryError(ExecState* exec) { - return exec->vm().throwException(exec, createSyntaxError(exec, ASCIILiteral("Syntax error"))); + return createError(exec, ASCIILiteral("Out of memory"), nullptr); } -const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) }; + +const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) }; void StrictModeTypeErrorFunction::destroy(JSCell* cell) { @@ -168,3 +306,36 @@ void StrictModeTypeErrorFunction::destroy(JSCell* cell) } } // namespace JSC + +namespace WTF { + +using namespace JSC; + +void printInternal(PrintStream& out, JSC::ErrorType errorType) +{ + switch (errorType) { + case JSC::ErrorType::Error: + out.print("Error"); + break; + case JSC::ErrorType::EvalError: + out.print("EvalError"); + break; + case JSC::ErrorType::RangeError: + out.print("RangeError"); + break; + case JSC::ErrorType::ReferenceError: + out.print("ReferenceError"); + break; + case JSC::ErrorType::SyntaxError: + out.print("SyntaxError"); + break; + case JSC::ErrorType::TypeError: + out.print("TypeError"); + break; + case JSC::ErrorType::URIError: + out.print("URIError"); + break; + } +} + +} // namespace WTF |