mirror of
https://github.com/openharmony/ark_js_runtime.git
synced 2026-07-20 23:00:29 -04:00
0b4981525d
1. using runtime container instead of stl container 2. change debugger line amd column type to int32_t issue: https://gitee.com/openharmony/ark_js_runtime/issues/I50NHW Signed-off-by: wengchangcheng <wengchangcheng@huawei.com> Change-Id: I0eb4651f17c6f6894f11de1ba904bcbe83a57db7
241 lines
10 KiB
C++
241 lines
10 KiB
C++
/*
|
|
* Copyright (c) 2021 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "ecmascript/base/error_helper.h"
|
|
#include "ecmascript/base/builtins_base.h"
|
|
#include "ecmascript/base/error_type.h"
|
|
#include "ecmascript/base/number_helper.h"
|
|
#include "ecmascript/ecma_macros.h"
|
|
#include "ecmascript/ecma_vm.h"
|
|
#include "ecmascript/global_env.h"
|
|
#include "ecmascript/interpreter/frame_handler.h"
|
|
#include "ecmascript/interpreter/interpreter.h"
|
|
#include "ecmascript/js_object-inl.h"
|
|
#include "ecmascript/js_tagged_value-inl.h"
|
|
#include "ecmascript/jspandafile/js_pandafile_manager.h"
|
|
#include "ecmascript/object_factory.h"
|
|
#include "ecmascript/tooling/js_pt_extractor.h"
|
|
|
|
namespace panda::ecmascript::base {
|
|
using panda::tooling::ecmascript::JSPtExtractor;
|
|
|
|
JSTaggedValue ErrorHelper::ErrorCommonToString(EcmaRuntimeCallInfo *argv, const ErrorType &errorType)
|
|
{
|
|
ASSERT(argv);
|
|
JSThread *thread = argv->GetThread();
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
// 1. Let O be the this value.
|
|
// 2. If Type(O) is not Object, throw a TypeError exception
|
|
JSHandle<JSTaggedValue> thisValue = BuiltinsBase::GetThis(argv);
|
|
if (!thisValue->IsECMAObject()) {
|
|
THROW_TYPE_ERROR_AND_RETURN(thread, "ErrorToString:not an object", JSTaggedValue::Exception());
|
|
}
|
|
// 3. Let name be Get(O, "name").
|
|
// 4. ReturnIfAbrupt(name).
|
|
auto globalConst = thread->GlobalConstants();
|
|
JSHandle<JSTaggedValue> handleName = globalConst->GetHandledNameString();
|
|
JSHandle<JSTaggedValue> name = JSObject::GetProperty(thread, thisValue, handleName).GetValue();
|
|
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
|
|
|
// 5. If name is undefined, let name be "Error"; otherwise let name be ToString(name).
|
|
// 6. ReturnIfAbrupt(name).
|
|
name = ErrorHelper::GetErrorName(thread, name, errorType);
|
|
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
|
|
|
// 7. Let msg be Get(O, "message").
|
|
// 8. ReturnIfAbrupt(msg).
|
|
JSHandle<JSTaggedValue> handleMsg = globalConst->GetHandledMessageString();
|
|
JSHandle<JSTaggedValue> msg = JSObject::GetProperty(thread, thisValue, handleMsg).GetValue();
|
|
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
|
|
|
// 9. If msg is undefined, let msg be the empty String; otherwise let msg be ToString(msg).
|
|
// 10. ReturnIfAbrupt(msg).
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
if (msg->IsUndefined()) {
|
|
msg = JSHandle<JSTaggedValue>::Cast(factory->GetEmptyString());
|
|
} else {
|
|
msg = JSHandle<JSTaggedValue>::Cast(JSTaggedValue::ToString(thread, msg));
|
|
}
|
|
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
|
|
|
// 11. If name is the empty String, return msg.
|
|
// 12. If msg is the empty String, return name.
|
|
if (JSHandle<EcmaString>::Cast(name)->GetLength() == 0) {
|
|
return msg.GetTaggedValue();
|
|
}
|
|
|
|
if (JSHandle<EcmaString>::Cast(msg)->GetLength() == 0) {
|
|
return name.GetTaggedValue();
|
|
}
|
|
|
|
// 13. Return the result of concatenating name, the code unit 0x003A (COLON), the code unit 0x0020 (SPACE), and msg.
|
|
JSHandle<EcmaString> space = factory->NewFromCanBeCompressString(": ");
|
|
JSHandle<EcmaString> jsHandleName = JSHandle<EcmaString>::Cast(name);
|
|
JSHandle<EcmaString> jsHandleMsg = JSHandle<EcmaString>::Cast(msg);
|
|
JSHandle<EcmaString> handleNameSpace = factory->ConcatFromString(jsHandleName, space);
|
|
JSHandle<EcmaString> result = factory->ConcatFromString(handleNameSpace, jsHandleMsg);
|
|
return result.GetTaggedValue();
|
|
}
|
|
|
|
JSHandle<JSTaggedValue> ErrorHelper::GetErrorName(JSThread *thread, const JSHandle<JSTaggedValue> &name,
|
|
const ErrorType &errorType)
|
|
{
|
|
auto globalConst = thread->GlobalConstants();
|
|
if (name->IsUndefined()) {
|
|
TaggedObject *errorKey = nullptr;
|
|
switch (errorType) {
|
|
case ErrorType::RANGE_ERROR:
|
|
errorKey = reinterpret_cast<TaggedObject *>(*globalConst->GetHandledRangeErrorString());
|
|
break;
|
|
case ErrorType::EVAL_ERROR:
|
|
errorKey = reinterpret_cast<TaggedObject *>(*globalConst->GetHandledEvalErrorString());
|
|
break;
|
|
case ErrorType::REFERENCE_ERROR:
|
|
errorKey = reinterpret_cast<TaggedObject *>(*globalConst->GetHandledReferenceErrorString());
|
|
break;
|
|
case ErrorType::TYPE_ERROR:
|
|
errorKey = reinterpret_cast<TaggedObject *>(*globalConst->GetHandledTypeErrorString());
|
|
break;
|
|
case ErrorType::URI_ERROR:
|
|
errorKey = reinterpret_cast<TaggedObject *>(*globalConst->GetHandledURIErrorString());
|
|
break;
|
|
case ErrorType::SYNTAX_ERROR:
|
|
errorKey = reinterpret_cast<TaggedObject *>(*globalConst->GetHandledSyntaxErrorString());
|
|
break;
|
|
default:
|
|
errorKey = reinterpret_cast<TaggedObject *>(*globalConst->GetHandledErrorString());
|
|
break;
|
|
}
|
|
return JSHandle<JSTaggedValue>(thread, JSTaggedValue(errorKey));
|
|
}
|
|
return JSHandle<JSTaggedValue>::Cast(JSTaggedValue::ToString(thread, name));
|
|
}
|
|
|
|
JSTaggedValue ErrorHelper::ErrorCommonConstructor(EcmaRuntimeCallInfo *argv,
|
|
[[maybe_unused]] const ErrorType &errorType)
|
|
{
|
|
JSThread *thread = argv->GetThread();
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
// 1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
|
|
auto ecmaVm = thread->GetEcmaVM();
|
|
ObjectFactory *factory = ecmaVm->GetFactory();
|
|
JSHandle<JSTaggedValue> ctor = BuiltinsBase::GetConstructor(argv);
|
|
JSMutableHandle<JSTaggedValue> newTarget(BuiltinsBase::GetNewTarget(argv));
|
|
if (newTarget->IsUndefined()) {
|
|
newTarget.Update(ctor.GetTaggedValue());
|
|
}
|
|
JSHandle<JSTaggedValue> message = BuiltinsBase::GetCallArg(argv, 0);
|
|
|
|
// 2. Let O be OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%", «[[ErrorData]]»).
|
|
JSHandle<JSObject> nativeInstanceObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), newTarget);
|
|
|
|
// 3. ReturnIfAbrupt(O).
|
|
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
|
|
|
// 4. If message is not undefined, then
|
|
// a. Let msg be ToString(message).
|
|
// b. ReturnIfAbrupt(msg).
|
|
// c. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]: true, [[Enumerable]]: false,
|
|
// [[Configurable]]: true}.
|
|
// d. Let status be DefinePropertyOrThrow(O, "message", msgDesc).
|
|
// e. Assert: status is not an abrupt completion
|
|
auto globalConst = thread->GlobalConstants();
|
|
if (!message->IsUndefined()) {
|
|
JSHandle<EcmaString> handleStr = JSTaggedValue::ToString(thread, message);
|
|
LOG(DEBUG, ECMASCRIPT) << "Ark throw error: " << utf::Mutf8AsCString(handleStr->GetDataUtf8());
|
|
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
|
JSHandle<JSTaggedValue> msgKey = globalConst->GetHandledMessageString();
|
|
PropertyDescriptor msgDesc(thread, JSHandle<JSTaggedValue>::Cast(handleStr), true, false, true);
|
|
[[maybe_unused]] bool status = JSObject::DefineOwnProperty(thread, nativeInstanceObj, msgKey, msgDesc);
|
|
ASSERT_PRINT(status == true, "return result exception!");
|
|
}
|
|
|
|
JSHandle<EcmaString> handleStack = BuildEcmaStackTrace(thread);
|
|
JSHandle<JSTaggedValue> stackkey = globalConst->GetHandledStackString();
|
|
PropertyDescriptor stackDesc(thread, JSHandle<JSTaggedValue>::Cast(handleStack), true, false, true);
|
|
[[maybe_unused]] bool status = JSObject::DefineOwnProperty(thread, nativeInstanceObj, stackkey, stackDesc);
|
|
ASSERT_PRINT(status == true, "return result exception!");
|
|
|
|
// 5. Return O.
|
|
return nativeInstanceObj.GetTaggedValue();
|
|
}
|
|
|
|
CString ErrorHelper::DecodeFunctionName(const CString &name)
|
|
{
|
|
if (name.empty()) {
|
|
return "anonymous";
|
|
}
|
|
return name;
|
|
}
|
|
|
|
JSHandle<EcmaString> ErrorHelper::BuildEcmaStackTrace(JSThread *thread)
|
|
{
|
|
CString data = BuildNativeAndJsStackTrace(thread);
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
LOG(DEBUG, ECMASCRIPT) << data;
|
|
return factory->NewFromString(data);
|
|
}
|
|
|
|
CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread)
|
|
{
|
|
CString data;
|
|
auto sp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
|
|
InterpretedFrameHandler frameHandler(sp);
|
|
for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) {
|
|
if (frameHandler.IsBreakFrame()) {
|
|
continue;
|
|
}
|
|
auto method = frameHandler.GetMethod();
|
|
if (!method->IsNative()) {
|
|
data.append(" at ");
|
|
data += DecodeFunctionName(method->ParseFunctionName());
|
|
data.append(" (");
|
|
// source file
|
|
JSPtExtractor *debugExtractor =
|
|
JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile());
|
|
const CString &sourceFile = debugExtractor->GetSourceFile(method->GetFileId());
|
|
if (sourceFile.empty()) {
|
|
data.push_back('?');
|
|
} else {
|
|
data += sourceFile;
|
|
}
|
|
data.push_back(':');
|
|
// line number and column number
|
|
auto callbackFunc = [&data](int32_t line, int32_t column) -> bool {
|
|
data += ToCString(line + 1);
|
|
data.push_back(':');
|
|
data += ToCString(column + 1);
|
|
return true;
|
|
};
|
|
if (!debugExtractor->MatchWithOffset(callbackFunc, method->GetFileId(), frameHandler.GetBytecodeOffset())) {
|
|
data.push_back('?');
|
|
}
|
|
data.push_back(')');
|
|
}
|
|
data.push_back('\n');
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
CString ErrorHelper::BuildNativeAndJsStackTrace(JSThread *thread)
|
|
{
|
|
CString data = BuildNativeEcmaStackTrace(thread);
|
|
return data;
|
|
}
|
|
} // namespace panda::ecmascript::base
|