X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/14957cd040308e3eeec43d26bae5d76da13fcd85..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/runtime/Error.cpp?ds=inline diff --git a/runtime/Error.cpp b/runtime/Error.cpp index 7eda19f..00285a6 100644 --- a/runtime/Error.cpp +++ b/runtime/Error.cpp @@ -26,186 +26,256 @@ #include "ConstructData.h" #include "ErrorConstructor.h" +#include "ExceptionHelpers.h" +#include "FunctionPrototype.h" +#include "JSArray.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSObject.h" #include "JSString.h" #include "NativeErrorConstructor.h" +#include "JSCInlines.h" #include "SourceCode.h" +#include + namespace JSC { static const char* linePropertyName = "line"; -static const char* sourceIdPropertyName = "sourceId"; static const char* sourceURLPropertyName = "sourceURL"; -JSObject* createError(JSGlobalObject* globalObject, const UString& message) +JSObject* createError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(&globalObject->globalData(), globalObject->errorStructure(), message); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(), message, appender, TypeNothing, true); } -JSObject* createEvalError(JSGlobalObject* globalObject, const UString& message) +JSObject* createEvalError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(&globalObject->globalData(), 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 UString& message) +JSObject* createRangeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(&globalObject->globalData(), 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 UString& message) +JSObject* createReferenceError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(&globalObject->globalData(), 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 UString& message) +JSObject* createSyntaxError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(&globalObject->globalData(), 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 UString& message) +JSObject* createTypeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender, RuntimeType type) { ASSERT(!message.isEmpty()); - return ErrorInstance::create(&globalObject->globalData(), globalObject->typeErrorConstructor()->errorStructure(), message); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message, appender, type, true); } -JSObject* createURIError(JSGlobalObject* globalObject, const UString& message) +JSObject* createNotEnoughArgumentsError(ExecState* exec, ErrorInstance::SourceAppender appender) { - ASSERT(!message.isEmpty()); - return ErrorInstance::create(&globalObject->globalData(), globalObject->URIErrorConstructor()->errorStructure(), message); + return createTypeError(exec, ASCIILiteral("Not enough arguments"), appender, TypeNothing); } -JSObject* createError(ExecState* exec, const UString& message) +JSObject* createURIError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender) { - return createError(exec->lexicalGlobalObject(), message); + ASSERT(!message.isEmpty()); + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + return ErrorInstance::create(exec, globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message, appender, TypeNothing, true); } -JSObject* createEvalError(ExecState* exec, const UString& message) +JSObject* createOutOfMemoryError(ExecState* exec, ErrorInstance::SourceAppender appender) { - return createEvalError(exec->lexicalGlobalObject(), message); + return createError(exec, ASCIILiteral("Out of memory"), appender); } -JSObject* createRangeError(ExecState* exec, const UString& message) + +class FindFirstCallerFrameWithCodeblockFunctor { +public: + FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame) + : m_startCallFrame(startCallFrame) + , m_foundCallFrame(nullptr) + , m_foundStartCallFrame(false) + , m_index(0) + { } + + StackVisitor::Status operator()(StackVisitor& visitor) + { + 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; + CallFrame* m_foundCallFrame; + bool m_foundStartCallFrame; + unsigned m_index; +}; + +bool addErrorInfoAndGetBytecodeOffset(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame, CallFrame*& callFrame, unsigned &bytecodeOffset) { - return createRangeError(exec->lexicalGlobalObject(), message); + Vector stackTrace = Vector(); + + if (exec && stackTrace.isEmpty()) + vm.interpreter->getStackTrace(stackTrace); + + if (!stackTrace.isEmpty()) { + + ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec()); + + StackFrame* stackFrame; + for (unsigned i = 0 ; i < stackTrace.size(); ++i) { + stackFrame = &stackTrace.at(i); + if (stackFrame->bytecodeOffset) + break; + } + + if (bytecodeOffset) { + FindFirstCallerFrameWithCodeblockFunctor functor(exec); + vm.topCallFrame->iterate(functor); + callFrame = functor.foundCallFrame(); + unsigned stackIndex = functor.index(); + bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset; + } + + unsigned line; + unsigned column; + stackFrame->computeLineAndColumn(line, column); + obj->putDirect(vm, vm.propertyNames->line, jsNumber(line), ReadOnly | DontDelete); + obj->putDirect(vm, vm.propertyNames->column, jsNumber(column), ReadOnly | DontDelete); + + if (!stackFrame->sourceURL.isEmpty()) + obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, stackFrame->sourceURL), ReadOnly | DontDelete); + + if (!useCurrentFrame) + stackTrace.remove(0); + obj->putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum); + + return true; + } + return false; } -JSObject* createReferenceError(ExecState* exec, const UString& message) +void addErrorInfo(ExecState* exec, JSObject* obj, bool useCurrentFrame) { - return createReferenceError(exec->lexicalGlobalObject(), message); + CallFrame* callFrame = nullptr; + unsigned bytecodeOffset = 0; + addErrorInfoAndGetBytecodeOffset(exec, exec->vm(), obj, useCurrentFrame, callFrame, bytecodeOffset); } -JSObject* createSyntaxError(ExecState* exec, const UString& message) +JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source) { - return createSyntaxError(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), ReadOnly | DontDelete); + if (!sourceURL.isNull()) + error->putDirect(*vm, Identifier::fromString(vm, sourceURLPropertyName), jsString(vm, sourceURL), ReadOnly | DontDelete); + return error; } -JSObject* createTypeError(ExecState* exec, const UString& message) + +bool hasErrorInfo(ExecState* exec, JSObject* error) { - return createTypeError(exec->lexicalGlobalObject(), message); + return error->hasProperty(exec, Identifier::fromString(exec, linePropertyName)) + || error->hasProperty(exec, Identifier::fromString(exec, sourceURLPropertyName)); } -JSObject* createURIError(ExecState* exec, const UString& message) +JSObject* throwTypeError(ExecState* exec) { - return createURIError(exec->lexicalGlobalObject(), message); + return exec->vm().throwException(exec, createTypeError(exec)); } -JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source) +JSObject* throwSyntaxError(ExecState* exec) { - intptr_t sourceID = source.provider()->asID(); - const UString& sourceURL = source.provider()->url(); + return exec->vm().throwException(exec, createSyntaxError(exec, ASCIILiteral("Syntax error"))); +} - if (line != -1) - error->putWithAttributes(globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete); - if (sourceID != -1) - error->putWithAttributes(globalData, Identifier(globalData, sourceIdPropertyName), jsNumber((double)sourceID), ReadOnly | DontDelete); - if (!sourceURL.isNull()) - error->putWithAttributes(globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete); - return error; +JSObject* createError(ExecState* exec, const String& message) +{ + return createError(exec, message, nullptr); } -JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source) +JSObject* createEvalError(ExecState* exec, const String& message) { - return addErrorInfo(&exec->globalData(), error, line, source); + return createEvalError(exec, message, nullptr); } -bool hasErrorInfo(ExecState* exec, JSObject* error) +JSObject* createRangeError(ExecState* exec, const String& message) { - return error->hasProperty(exec, Identifier(exec, linePropertyName)) - || error->hasProperty(exec, Identifier(exec, sourceIdPropertyName)) - || error->hasProperty(exec, Identifier(exec, sourceURLPropertyName)); + return createRangeError(exec, message, nullptr); } -JSValue throwError(ExecState* exec, JSValue error) +JSObject* createReferenceError(ExecState* exec, const String& message) { - exec->globalData().exception = error; - return error; + return createReferenceError(exec, message, nullptr); } -JSObject* throwError(ExecState* exec, JSObject* error) +JSObject* createSyntaxError(ExecState* exec, const String& message) { - exec->globalData().exception = error; - return error; + return createSyntaxError(exec, message, nullptr); } -JSObject* throwTypeError(ExecState* exec) +JSObject* createTypeError(ExecState* exec) { - return throwError(exec, createTypeError(exec, "Type error")); + return createTypeError(exec, ASCIILiteral("Type error")); } -JSObject* throwSyntaxError(ExecState* exec) +JSObject* createTypeError(ExecState* exec, const String& message) { - return throwError(exec, createSyntaxError(exec, "Syntax error")); + return createTypeError(exec, message, nullptr, TypeNothing); } -class StrictModeTypeErrorFunction : public InternalFunction { -public: - StrictModeTypeErrorFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, const UString& message) - : InternalFunction(&exec->globalData(), globalObject, structure, exec->globalData().propertyNames->emptyIdentifier) - , m_message(message) - { - } - - static EncodedJSValue JSC_HOST_CALL constructThrowTypeError(ExecState* exec) - { - throwTypeError(exec, static_cast(exec->callee())->m_message); - return JSValue::encode(jsNull()); - } - - ConstructType getConstructData(ConstructData& constructData) - { - constructData.native.function = constructThrowTypeError; - return ConstructTypeHost; - } - - static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec) - { - throwTypeError(exec, static_cast(exec->callee())->m_message); - return JSValue::encode(jsNull()); - } +JSObject* createNotEnoughArgumentsError(ExecState* exec) +{ + return createNotEnoughArgumentsError(exec, nullptr); +} - CallType getCallData(CallData& callData) - { - callData.native.function = callThrowTypeError; - return CallTypeHost; - } +JSObject* createURIError(ExecState* exec, const String& message) +{ + return createURIError(exec, message, nullptr); +} + +JSObject* createOutOfMemoryError(ExecState* exec) +{ + return createOutOfMemoryError(exec, nullptr); +} -private: - UString m_message; -}; -ASSERT_CLASS_FITS_IN_CELL(StrictModeTypeErrorFunction); +const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) }; -JSValue createTypeErrorFunction(ExecState* exec, const UString& message) +void StrictModeTypeErrorFunction::destroy(JSCell* cell) { - return new (exec) StrictModeTypeErrorFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->internalFunctionStructure(), message); + static_cast(cell)->StrictModeTypeErrorFunction::~StrictModeTypeErrorFunction(); } } // namespace JSC